first init

This commit is contained in:
ISMAIL MASSERAN
2026-06-08 11:37:14 +08:00
commit df0d0e743b
585 changed files with 55790 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { Box } from "@/components/ui/box";
</script>
<template>
<Box class="w-full xl:w-1/2">
<div class="text-xl font-medium capitalize border-b border-foreground/15 pb-5">{{ $route.name }}</div>
<div class="mt-16 flex flex-col gap-10">
<RouterView />
</div>
</Box>
</template>
+486
View File
@@ -0,0 +1,486 @@
<script lang="ts" setup>
import {
AccordionRoot,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@/components/ui/accordion";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
import { Box } from "@/components/ui/box";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Box raised="single" class="w-full">
<AccordionRoot class="w-full" :default-value="['product-information']">
<AccordionItem value="product-information">
<AccordionTrigger>Product Information</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
Our flagship product combines cutting-edge technology with
sleek design. Built with premium materials, it offers
unparalleled performance and reliability.
</p>
<p>
Key features include advanced processing capabilities, and an
intuitive user interface designed for both beginners and
experts.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="shipping-details">
<AccordionTrigger>Shipping Details</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We offer worldwide shipping through trusted courier partners.
Standard delivery takes 3-5 business days, while express
shipping ensures delivery within 1-2 business days.
</p>
<p>
All orders are carefully packaged and fully insured. Track
your shipment in real-time through our dedicated tracking
portal.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="return-policy">
<AccordionTrigger>Return Policy</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We stand behind our products with a comprehensive 30-day
return policy. If you're not completely satisfied, simply
return the item in its original condition.
</p>
<p>
Our hassle-free return process includes free return shipping
and full refunds processed within 48 hours of receiving the
returned item.
</p>
</AccordionContent>
</AccordionItem>
</AccordionRoot>
</Box>
</template>
<template #code>
<PreviewCode>
{{ `
<Box raised="single" class="w-full">
<AccordionRoot class="w-full" :default-value="['product-information']">
<AccordionItem value="product-information">
<AccordionTrigger>Product Information</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
Our flagship product combines cutting-edge technology with
sleek design. Built with premium materials, it offers
unparalleled performance and reliability.
</p>
<p>
Key features include advanced processing capabilities, and an
intuitive user interface designed for both beginners and
experts.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="shipping-details">
<AccordionTrigger>Shipping Details</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We offer worldwide shipping through trusted courier partners.
Standard delivery takes 3-5 business days, while express
shipping ensures delivery within 1-2 business days.
</p>
<p>
All orders are carefully packaged and fully insured. Track
your shipment in real-time through our dedicated tracking
portal.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="return-policy">
<AccordionTrigger>Return Policy</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We stand behind our products with a comprehensive 30-day
return policy. If you're not completely satisfied, simply
return the item in its original condition.
</p>
<p>
Our hassle-free return process includes free return shipping
and full refunds processed within 48 hours of receiving the
returned item.
</p>
</AccordionContent>
</AccordionItem>
</AccordionRoot>
</Box>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/accordion</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/accordion/AccordionContent.vue">
{{ `
<script lang="ts" setup>
import { accordionContent } from "@mykopkb/core/styles/accordion.styles";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/accordion";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("accordionApi");
const item = inject<ItemProps>("accordionItem");
</script>
<template>
<Slot :class="cn([className, accordionContent])"
v-bind="{ ...props, ...$attrs, ...api?.getItemContentProps(item!) }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/accordion/AccordionItem.vue">
{{ `
<script lang="ts" setup>
import { accordionItemVariants } from "@mykopkb/core/styles/accordion.styles";
import {
boxVariants,
type BoxVariants,
} from "@mykopkb/core/styles/box.styles";
import { cn } from "@mykopkb/core/utils/cn";
import { inject, provide } from "vue";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/accordion";
const {
raised,
class: className,
asChild = false,
...props
} = defineProps<
BoxVariants & ItemProps & { class?: string; asChild?: boolean }
>();
const variant = inject<"default" | "boxed">("accordionVariant", "default");
const api = inject<Api>("accordionApi");
provide("accordionItem", props);
</script>
<template>
<Slot :class="
cn([
className,
variant == 'boxed' ? boxVariants({ raised, className }) : '',
accordionItemVariants({ variant, className }),
])
" v-bind="{ ...props, ...$attrs, ...api?.getItemProps(props) }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/accordion/AccordionRoot.vue">
{{`
<script lang="ts" setup>
import { accordionRootVariants } from "@mykopkb/core/styles/accordion.styles";
import { cn } from "@mykopkb/core/utils/cn";
import { provide, computed } from "vue";
import * as accordion from "@zag-js/accordion";
import type { Props } from "@zag-js/accordion";
import { useMachine, normalizeProps } from "@zag-js/vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
variant = "default",
asChild = false,
collapsible = true,
...props
} = defineProps<
Partial<Props> & {
class?: string;
variant?: "default" | "boxed";
asChild?: boolean;
}
>();
const service = useMachine(accordion.machine, {
collapsible,
...props,
id: crypto.randomUUID(),
});
const api = computed(() => accordion.connect(service, normalizeProps));
provide("accordionVariant", variant);
provide("accordionApi", api);
</script>
<template>
<Slot :class="cn([className, accordionRootVariants({ variant, className })])"
v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/accordion/AccordionTrigger.vue">
{{ `
<script lang="ts" setup>
import { ChevronDownIcon } from "@lucide/vue";
import {
accordionTrigger,
accordionItemIndicator,
} from "@mykopkb/core/styles/accordion.styles";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/accordion";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("accordionApi");
const item = inject<ItemProps>("accordionItem");
</script>
<template>
<Slot :class="cn([className, accordionTrigger])"
v-bind="{ ...props, ...$attrs, ...api?.getItemTriggerProps(item!) }">
<slot v-if="asChild" />
<button v-else>
<slot />
<div v-bind="api?.getItemIndicatorProps(item!)" :class="cn(accordionItemIndicator)">
<ChevronDownIcon />
</div>
</button>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/accordion/index.ts">
{{ `
export { default as AccordionRoot } from "./AccordionRoot.vue";
export { default as AccordionItem } from "./AccordionItem.vue";
export { default as AccordionTrigger } from "./AccordionTrigger.vue";
export { default as AccordionContent } from "./AccordionContent.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
AccordionRoot,
AccordionItem,
AccordionTrigger,
AccordionContent,
} from "@/components/ui/accordion";
import { Box } from "@/components/ui/box";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Box raised="single" class="w-full">
<AccordionRoot class="w-full" :default-value="['product-information']">
<AccordionItem value="product-information">
<AccordionTrigger>Product Information</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
Our flagship product combines cutting-edge technology with
sleek design. Built with premium materials, it offers
unparalleled performance and reliability.
</p>
<p>
Key features include advanced processing capabilities, and an
intuitive user interface designed for both beginners and
experts.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="shipping-details">
<AccordionTrigger>Shipping Details</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We offer worldwide shipping through trusted courier partners.
Standard delivery takes 3-5 business days, while express
shipping ensures delivery within 1-2 business days.
</p>
<p>
All orders are carefully packaged and fully insured. Track
your shipment in real-time through our dedicated tracking
portal.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem value="return-policy">
<AccordionTrigger>Return Policy</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We stand behind our products with a comprehensive 30-day
return policy. If you're not completely satisfied, simply
return the item in its original condition.
</p>
<p>
Our hassle-free return process includes free return shipping
and full refunds processed within 48 hours of receiving the
returned item.
</p>
</AccordionContent>
</AccordionItem>
</AccordionRoot>
</Box>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<AccordionRoot class="w-full" variant="boxed" :default-value="['product-information']">
<AccordionItem raised="single" value="product-information">
<AccordionTrigger>Product Information</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
Our flagship product combines cutting-edge technology with sleek
design. Built with premium materials, it offers unparalleled
performance and reliability.
</p>
<p>
Key features include advanced processing capabilities, and an
intuitive user interface designed for both beginners and
experts.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem raised="single" value="shipping-details">
<AccordionTrigger>Shipping Details</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We offer worldwide shipping through trusted courier partners.
Standard delivery takes 3-5 business days, while express
shipping ensures delivery within 1-2 business days.
</p>
<p>
All orders are carefully packaged and fully insured. Track your
shipment in real-time through our dedicated tracking portal.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem raised="single" value="return-policy">
<AccordionTrigger>Return Policy</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We stand behind our products with a comprehensive 30-day return
policy. If you're not completely satisfied, simply return the
item in its original condition.
</p>
<p>
Our hassle-free return process includes free return shipping and
full refunds processed within 48 hours of receiving the returned
item.
</p>
</AccordionContent>
</AccordionItem>
</AccordionRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AccordionRoot class="w-full" variant="boxed" :default-value="['product-information']">
<AccordionItem raised="single" value="product-information">
<AccordionTrigger>Product Information</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
Our flagship product combines cutting-edge technology with sleek
design. Built with premium materials, it offers unparalleled
performance and reliability.
</p>
<p>
Key features include advanced processing capabilities, and an
intuitive user interface designed for both beginners and
experts.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem raised="single" value="shipping-details">
<AccordionTrigger>Shipping Details</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We offer worldwide shipping through trusted courier partners.
Standard delivery takes 3-5 business days, while express
shipping ensures delivery within 1-2 business days.
</p>
<p>
All orders are carefully packaged and fully insured. Track your
shipment in real-time through our dedicated tracking portal.
</p>
</AccordionContent>
</AccordionItem>
<AccordionItem raised="single" value="return-policy">
<AccordionTrigger>Return Policy</AccordionTrigger>
<AccordionContent>
<p class="mb-2">
We stand behind our products with a comprehensive 30-day return
policy. If you're not completely satisfied, simply return the
item in its original condition.
</p>
<p>
Our hassle-free return process includes free return shipping and
full refunds processed within 48 hours of receiving the returned
item.
</p>
</AccordionContent>
</AccordionItem>
</AccordionRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+639
View File
@@ -0,0 +1,639 @@
<script lang="ts" setup>
import {
AlertRoot,
AlertTitle,
AlertDescription,
AlertCloseTrigger,
} from "@/components/ui/alert";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
import { Compass } from "@lucide/vue";
import { Box } from "@/components/ui/box";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<AlertRoot variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AlertRoot variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/alert</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/alert/AlertCloseTrigger.vue">
{{`
<script lang="ts" setup>
import { X } from "@lucide/vue";
import { cn } from "@mykopkb/core/utils/cn";
import { Slot } from "@/components/ui/slot";
import { alertCloseTrigger } from "@mykopkb/core/styles/alert.styles";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const context = inject<{
present: boolean;
setPresent: (value: boolean) => void;
} | null>("alertPresent", null);
</script>
<template>
<Slot :class="cn([className, alertCloseTrigger])" v-bind="{ ...props, ...$attrs }"
@click="context?.setPresent(false)">
<slot v-if="asChild" />
<div v-else>
<slot v-if="$slots.default" />
<X v-else />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/alert/AlertDescription.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { Slot } from "@/components/ui/slot";
import { alertDescription } from "@mykopkb/core/styles/alert.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
</script>
<template>
<Slot :class="cn([className, alertDescription])" v-bind="{ ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/alert/AlertRoot.vue">
{{`
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import {
alertRootVariants,
type AlertRootVariants,
} from "@mykopkb/core/styles/alert.styles";
import { Presence } from "@/components/ui/presence";
import { ref, provide } from "vue";
const {
class: className,
look,
variant,
...rest
} = defineProps<AlertRootVariants & { class?: string }>();
const present = ref(true);
const setPresent = (value: boolean) => {
present.value = value;
};
provide("alertPresent", { present, setPresent });
</script>
<template>
<Presence :class="
cn(
alertRootVariants({
look,
variant,
}),
className
)
" v-bind="rest" :present="present">
<slot />
</Presence>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/alert/AlertTitle.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { Slot } from "@/components/ui/slot";
import { alertTitle } from "@mykopkb/core/styles/alert.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
</script>
<template>
<Slot :class="cn([className, alertTitle])" v-bind="{ ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/alert/index.ts">
{{ `
export { default as AlertRoot } from "./AlertRoot.vue";
export { default as AlertTitle } from "./AlertTitle.vue";
export { default as AlertDescription } from "./AlertDescription.vue";
export { default as AlertCloseTrigger } from "./AlertCloseTrigger.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
AlertRoot,
AlertTitle,
AlertDescription,
AlertCloseTrigger,
} from "@/components/ui/alert";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<AlertRoot>
<Compass />
<AlertTitle>
Success! Your changes have been saved
</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview class="flex-col!">
<template #preview>
<AlertRoot variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AlertRoot variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview class="flex-col!">
<template #preview>
<AlertRoot look="filled" variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AlertRoot look="filled" variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot look="filled" variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview class="flex-col!">
<template #preview>
<AlertRoot variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AlertRoot variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
<AlertRoot variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertCloseTrigger />
</AlertRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview class="flex-col!">
<template #preview>
<AlertRoot look="filled" variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AlertRoot look="filled" variant="primary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="secondary">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="success">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="danger">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="pending">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
<AlertRoot look="filled" variant="warning">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
</AlertRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview class="flex-col!">
<template #preview>
<Box class="p-0">
<AlertRoot variant="ghost">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</Box>
<Box class="p-0" raised="single">
<AlertRoot variant="ghost">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</Box>
<Box class="p-0" raised="double">
<AlertRoot variant="ghost">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</Box>
</template>
<template #code>
<PreviewCode>
{{ `
<Box class="p-0">
<AlertRoot variant="ghost">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</Box>
<Box class="p-0" raised="single">
<AlertRoot variant="ghost">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</Box>
<Box class="p-0" raised="double">
<AlertRoot variant="ghost">
<Compass />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>
This is an alert with icon, title and description.
</AlertDescription>
<AlertCloseTrigger />
</AlertRoot>
</Box>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+239
View File
@@ -0,0 +1,239 @@
<script lang="ts" setup>
import {
AvatarRoot,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<AvatarRoot>
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AvatarRoot>
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/avatar</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/avatar/AvatarFallback.vue">
{{ `
<script lang="ts" setup>
import type { Api } from "@zag-js/avatar";
import { cn } from "@mykopkb/core/utils/cn";
import { avatarFallback } from "@mykopkb/core/styles/avatar.styles";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
asChild?: boolean;
class?: string;
}>();
const api = inject<Api>("avatarApi");
</script>
<template>
<Slot :class="cn(avatarFallback, className)" v-bind="{ ...props, ...$attrs, ...api?.getFallbackProps() }">
<slot v-if="asChild" />
<span v-else>
<slot />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/avatar/AvatarImage.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { avatarImage } from "@mykopkb/core/styles/avatar.styles";
import { inject } from "vue";
import type { Api } from "@zag-js/avatar";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("avatarApi");
</script>
<template>
<img :class="cn(avatarImage, className)" v-bind="{ ...props, ...$attrs, ...api?.getImageProps() }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/avatar/AvatarRoot.vue">
{{`
<script lang="ts" setup>
import * as avatar from "@zag-js/avatar";
import { provide, computed } from "vue";
import { useMachine, normalizeProps } from "@zag-js/vue";
import type { Props } from "@zag-js/avatar";
import { cn } from "@mykopkb/core/utils/cn";
import {
avatarRootVariants,
type AvatarRootVariants,
} from "@mykopkb/core/styles/avatar.styles";
import { Slot } from "@/components/ui/slot";
const {
class: className,
bordered,
asChild = false,
...props
} = defineProps<
AvatarRootVariants &
Partial<Props> & {
class?: string;
asChild?: boolean;
}
>();
const service = useMachine(avatar.machine, {
...props,
id: crypto.randomUUID(),
});
const api = computed(() => avatar.connect(service, normalizeProps));
provide("avatarApi", api);
</script>
<template>
<Slot :class="
cn(
avatarRootVariants({
bordered,
className,
}),
className
)
" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/avatar/index.ts">
{{ `
export { default as AvatarRoot } from "./AvatarRoot.vue";
export { default as AvatarFallback } from "./AvatarFallback.vue";
export { default as AvatarImage } from "./AvatarImage.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
AvatarRoot,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<AvatarRoot>
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<AvatarRoot :bordered="false">
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AvatarRoot :bordered="false">
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<AvatarRoot class="rounded-full">
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AvatarRoot class="rounded-full">
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<AvatarRoot class="rounded-full" :bordered="false">
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<AvatarRoot class="rounded-full" :bordered="false">
<AvatarFallback>PA</AvatarFallback>
<AvatarImage src="https://i.pravatar.cc/300" alt="avatar" />
</AvatarRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+351
View File
@@ -0,0 +1,351 @@
<script lang="ts" setup>
import { ChevronDown, CheckSquare } from "@lucide/vue";
import { Badge } from "@/components/ui/badge";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Badge variant="primary">12%</Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge variant="primary">12%</Badge>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/badge/Badge.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import {
TooltipRoot,
TooltipTrigger,
TooltipPositioner,
TooltipContent,
} from "@/components/ui/tooltip";
import {
badgeVariants,
type BadgeVariants,
} from "@mykopkb/core/styles/badge.styles";
const {
class: className,
look,
variant,
content,
...props
} = defineProps<
BadgeVariants & {
class?: string;
content?: string;
}
>();
</script>
<template>
<TooltipRoot :disabled="!content">
<TooltipTrigger as-child>
<span :class="cn(badgeVariants({ look, variant, className }))" v-bind="{ ...props, ...$attrs }">
<slot />
</span>
</TooltipTrigger>
<TooltipPositioner>
<TooltipContent>\{\{ content \}\}</TooltipContent>
</TooltipPositioner>
</TooltipRoot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/badge/index.ts">
{{ `
export { default as Badge } from "./Badge.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { Badge } from "@/components/ui/badge";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Badge>12%</Badge>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<Badge variant="primary">12%</Badge>
<Badge variant="secondary">12%</Badge>
<Badge variant="success">12%</Badge>
<Badge variant="danger">12%</Badge>
<Badge variant="pending">12%</Badge>
<Badge variant="warning">12%</Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge variant="primary">12%</Badge>
<Badge variant="secondary">12%</Badge>
<Badge variant="success">12%</Badge>
<Badge variant="danger">12%</Badge>
<Badge variant="pending">12%</Badge>
<Badge variant="warning">12%</Badge>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Badge variant="primary"> 12%
<ChevronDown />
</Badge>
<Badge variant="secondary"> 12%
<ChevronDown />
</Badge>
<Badge variant="success"> 12%
<ChevronDown />
</Badge>
<Badge variant="danger"> 12%
<ChevronDown />
</Badge>
<Badge variant="pending"> 12%
<ChevronDown />
</Badge>
<Badge variant="warning"> 12%
<ChevronDown />
</Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge variant="primary"> 12%
<ChevronDown />
</Badge>
<Badge variant="secondary"> 12%
<ChevronDown />
</Badge>
<Badge variant="success"> 12%
<ChevronDown />
</Badge>
<Badge variant="danger"> 12%
<ChevronDown />
</Badge>
<Badge variant="pending"> 12%
<ChevronDown />
</Badge>
<Badge variant="warning"> 12%
<ChevronDown />
</Badge>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Badge look="outline" variant="primary"> 12% </Badge>
<Badge look="outline" variant="secondary"> 12% </Badge>
<Badge look="outline" variant="success"> 12% </Badge>
<Badge look="outline" variant="danger"> 12% </Badge>
<Badge look="outline" variant="pending"> 12% </Badge>
<Badge look="outline" variant="warning"> 12% </Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge look="outline" variant="primary"> 12% </Badge>
<Badge look="outline" variant="secondary"> 12% </Badge>
<Badge look="outline" variant="success"> 12% </Badge>
<Badge look="outline" variant="danger"> 12% </Badge>
<Badge look="outline" variant="pending"> 12% </Badge>
<Badge look="outline" variant="warning"> 12% </Badge>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Badge look="outline" variant="primary"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="secondary"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="success"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="danger"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="pending"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="warning"> 12%
<ChevronDown />
</Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge look="outline" variant="primary"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="secondary"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="success"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="danger"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="pending"> 12%
<ChevronDown />
</Badge>
<Badge look="outline" variant="warning"> 12%
<ChevronDown />
</Badge>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Badge look="filled" variant="primary"> 12% </Badge>
<Badge look="filled" variant="secondary"> 12% </Badge>
<Badge look="filled" variant="success"> 12% </Badge>
<Badge look="filled" variant="danger"> 12% </Badge>
<Badge look="filled" variant="pending"> 12% </Badge>
<Badge look="filled" variant="warning"> 12% </Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge look="filled" variant="primary"> 12% </Badge>
<Badge look="filled" variant="secondary"> 12% </Badge>
<Badge look="filled" variant="success"> 12% </Badge>
<Badge look="filled" variant="danger"> 12% </Badge>
<Badge look="filled" variant="pending"> 12% </Badge>
<Badge look="filled" variant="warning"> 12% </Badge>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Badge look="filled" variant="primary"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="secondary"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="success"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="danger"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="pending"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="warning"> 12%
<ChevronDown />
</Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge look="filled" variant="primary"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="secondary"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="success"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="danger"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="pending"> 12%
<ChevronDown />
</Badge>
<Badge look="filled" variant="warning"> 12%
<ChevronDown />
</Badge>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Badge look="outline" variant="primary" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="secondary" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="success" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="danger" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="pending" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="warning" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
</template>
<template #code>
<PreviewCode>
{{ `
<Badge look="outline" variant="primary" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="secondary" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="success" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="danger" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="pending" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
<Badge look="outline" variant="warning" content="12% Higher than last month">
<CheckSquare /> 12%
</Badge>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+199
View File
@@ -0,0 +1,199 @@
<script lang="ts" setup>
import { CircleGauge } from "@lucide/vue";
import { Box } from "@/components/ui/box";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Box class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
</template>
<template #code>
<PreviewCode>
{{ `
<Box class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/box/Box.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import {
boxVariants,
type BoxVariants,
} from "@mykopkb/core/styles/box.styles";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
raised,
...props
} = defineProps<
BoxVariants & {
class?: string;
asChild?: boolean;
}
>();
</script>
<template>
<Slot :class="cn(boxVariants({ raised, className }), className)" v-bind="{ ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/box/index.ts">
{{ `
export { default as Box } from "./Box.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { Box } from "@/components/ui/box";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Box class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<Box class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
</template>
<template #code>
<PreviewCode>
{{ `
<Box class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Box raised="single" class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
</template>
<template #code>
<PreviewCode>
{{ `
<Box raised="single" class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Box raised="double" class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
</template>
<template #code>
<PreviewCode>
{{ `
<Box raised="double" class="w-70">
<CircleGauge class="size-7 stroke-1 fill-foreground/10" />
<div class="mt-6 text-2xl font-medium leading-8">
$724,091.47
</div>
<div class="mt-1.5 text-xs uppercase opacity-70">
Item Sales
</div>
</Box>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+181
View File
@@ -0,0 +1,181 @@
<script lang="ts" setup>
import { Breadcrumb } from "@/components/ui/breadcrumb";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Breadcrumb :items="['Dashboard', 'Users', 'Admins', 'Settings', 'Edit Profile']" />
</template>
<template #code>
<PreviewCode>
{{ `
<Breadcrumb :items="['Dashboard', 'Users', 'Admins', 'Settings', 'Edit Profile']" />
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/breadcrumb/Breadcrumb.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { ChevronRight, Ellipsis } from "@lucide/vue";
import {
MenuRoot,
MenuTrigger,
MenuPositioner,
MenuContent,
MenuItem,
} from "@/components/ui/menu";
import { BreadcrumbItem, BreadcrumbLink, BreadcrumbList } from ".";
const { class: className, ...props } = defineProps<{
class?: string;
items: string[];
}>();
</script>
<template>
<nav aria-label="breadcrumb" data-slot="breadcrumb" v-bind="{ ...props, ...$attrs }" :class="cn(className)">
<BreadcrumbList>
<template v-if="items.length <= 3">
<template v-for="(item, key) in items">
<BreadcrumbItem>
<BreadcrumbLink>\{\{ item \}\}</BreadcrumbLink>
</BreadcrumbItem>
<ChevronRight v-if="key < items.length - 1" />
</template>
</template>
<template v-else>
<BreadcrumbItem>
<BreadcrumbLink>\{\{ items[0] \}\}</BreadcrumbLink>
</BreadcrumbItem>
<ChevronRight />
<BreadcrumbItem>
<MenuRoot>
<MenuTrigger asChild>
<BreadcrumbLink>
<Ellipsis />
</BreadcrumbLink>
</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem v-for="(item, itemKey) in items.slice(1, -2)" :value="item" :key="itemKey">
\{\{ item \}\}
</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
</BreadcrumbItem>
<ChevronRight />
<template v-for="(item, index) in items.slice(-2)">
<BreadcrumbItem>
<BreadcrumbLink>\{\{ item \}\}</BreadcrumbLink>
</BreadcrumbItem>
<ChevronRight v-if="index < 1" />
</template>
</template>
</BreadcrumbList>
</nav>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/breadcrumb/BreadcrumbItem.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { breadcrumbItem } from "@mykopkb/core/styles/breadcrumb.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<li :class="cn(className, breadcrumbItem)" v-bind="{ ...props, ...$attrs }">
<slot />
</li>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/breadcrumb/BreadcrumbLink.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { breadcrumbLink } from "@mykopkb/core/styles/breadcrumb.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<a :class="cn(className, breadcrumbLink)" v-bind="{ ...props, ...$attrs }">
<slot />
</a>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/breadcrumb/BreadcrumbList.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { breadcrumbList } from "@mykopkb/core/styles/breadcrumb.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<ol :class="cn(className, breadcrumbList)" v-bind="{ ...props, ...$attrs }">
<slot />
</ol>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/breadcrumb/index.ts">
{{ `
export { default as Breadcrumb } from "./Breadcrumb.vue";
export { default as BreadcrumbItem } from "./BreadcrumbItem.vue";
export { default as BreadcrumbLink } from "./BreadcrumbLink.vue";
export { default as BreadcrumbList } from "./BreadcrumbList.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { Breadcrumb } from "@/components/ui/breadcrumb";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Breadcrumb :items="[
'Dashboard',
'Users',
'Admins',
'Settings',
'Edit Profile',
]" />
` }}
</PreviewCode>
</div>
</template>
File diff suppressed because it is too large Load Diff
+445
View File
@@ -0,0 +1,445 @@
<script lang="ts" setup>
import {
CarouselRoot,
CarouselControl,
CarouselPrevTrigger,
CarouselNextTrigger,
CarouselIndicatorGroup,
CarouselIndicator,
CarouselItemGroup,
CarouselItem,
} from "@/components/ui/carousel";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
const images = Array.from(
{ length: 5 },
(_, i) => `https://picsum.photos/seed/${i + 1}/500/300`
);
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<CarouselRoot :default-page="0" :slide-count="images.length" class="size-72">
<CarouselControl>
<CarouselPrevTrigger />
<CarouselNextTrigger />
</CarouselControl>
<CarouselIndicatorGroup>
<CarouselIndicator v-for="(_, index) in images" :key="index" :index="index" />
</CarouselIndicatorGroup>
<CarouselItemGroup>
<CarouselItem v-for="(image, index) in images" :key="index" :index="index"
class="text-5xl bold flex items-center justify-center">
{{ index + 1 }}
</CarouselItem>
</CarouselItemGroup>
</CarouselRoot>
</template>
<template #code>
<PreviewCode>
{{`
const images = Array.from(
{ length: 5 },
(_, i) => \`https://picsum.photos/seed/\${i + 1}/500/300\`
);
<CarouselRoot :default-page="0" :slide-count="images.length" class="size-72">
<CarouselControl>
<CarouselPrevTrigger />
<CarouselNextTrigger />
</CarouselControl>
<CarouselIndicatorGroup>
<CarouselIndicator v-for="(_, index) in images" :key="index" :index="index" />
</CarouselIndicatorGroup>
<CarouselItemGroup>
<CarouselItem v-for="(image, index) in images" :key="index" :index="index"
class="text-5xl bold flex items-center justify-center">
\{\{ index + 1 \}\}
</CarouselItem>
</CarouselItemGroup>
</CarouselRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/carousel</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/carousel/CarouselRoot.vue">
{{`
<script lang="ts" setup>
import * as carousel from "@zag-js/carousel";
import { useMachine, normalizeProps } from "@zag-js/vue";
import type { Props } from "@zag-js/carousel";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { carouselRoot } from "@mykopkb/core/styles/carousel.styles";
import { computed, provide } from "vue";
const {
class: className,
defaultPage,
slideCount,
spacing = "2rem",
allowMouseDrag = true,
asChild = false,
...props
} = defineProps<Partial<Props> & { asChild?: boolean; class?: string }>();
const service = useMachine(carousel.machine, {
defaultPage,
slideCount,
spacing,
allowMouseDrag,
...props,
id: crypto.randomUUID(),
});
const api = computed(() => carousel.connect(service, normalizeProps));
provide("carouselApi", api);
</script>
<template>
<Slot :class="cn(carouselRoot, className)" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/CarouselControl.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { carouselControl } from "@mykopkb/core/styles/carousel.styles";
import type { Api } from "@zag-js/carousel";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("carouselApi");
</script>
<template>
<Slot :class="cn(carouselControl, className)" v-bind="{ ...props, ...$attrs, ...api?.getControlProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/CarouselPrevTrigger.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { Button } from "@/components/ui/button";
import { ArrowLeft } from "@lucide/vue";
import { carouselPrevTrigger } from "@mykopkb/core/styles/carousel.styles";
import type { Api } from "@zag-js/carousel";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("carouselApi");
</script>
<template>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getPrevTriggerProps() }">
<slot v-if="asChild" />
<Button variant="ghost" v-else :class="cn(carouselPrevTrigger, className)">
<slot v-if="$slots.default" />
<ArrowLeft v-else />
</Button>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/CarouselNextTrigger.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { Button } from "@/components/ui/button";
import { ArrowRight } from "@lucide/vue";
import { carouselNextTrigger } from "@mykopkb/core/styles/carousel.styles";
import type { Api } from "@zag-js/carousel";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("carouselApi");
</script>
<template>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getNextTriggerProps() }">
<slot v-if="asChild" />
<Button variant="ghost" v-else :class="cn(carouselNextTrigger, className)">
<slot v-if="$slots.default" />
<ArrowRight v-else />
</Button>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/CarouselIndicatorGroup.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { carouselIndicatorGroup } from "@mykopkb/core/styles/carousel.styles";
import type { Api } from "@zag-js/carousel";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("carouselApi");
</script>
<template>
<Slot :class="cn(carouselIndicatorGroup, className)"
v-bind="{ ...props, ...$attrs, ...api?.getIndicatorGroupProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/CarouselIndicator.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { carouselIndicator } from "@mykopkb/core/styles/carousel.styles";
import type { Api, IndicatorProps } from "@zag-js/carousel";
import { inject } from "vue";
const {
class: className,
asChild = false,
index,
...props
} = defineProps<
{
class?: string;
asChild?: boolean;
} & IndicatorProps
>();
const api = inject<Api>("carouselApi");
</script>
<template>
<button :class="cn(carouselIndicator, className)"
v-bind="{ ...props, ...$attrs, ...api?.getIndicatorProps({ index }) }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/CarouselItemGroup.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { carouselItemGroup } from "@mykopkb/core/styles/carousel.styles";
import type { Api } from "@zag-js/carousel";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("carouselApi");
</script>
<template>
<Slot :class="cn(carouselItemGroup, className)" v-bind="{ ...props, ...$attrs, ...api?.getItemGroupProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/CarouselItem.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { Box } from "@/components/ui/box";
import { carouselItem } from "@mykopkb/core/styles/carousel.styles";
import type { Api, ItemProps } from "@zag-js/carousel";
import { inject } from "vue";
const {
class: className,
asChild = false,
index,
...props
} = defineProps<
{
class?: string;
asChild?: boolean;
} & ItemProps
>();
const api = inject<Api>("carouselApi");
</script>
<template>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getItemProps({ index }) }">
<slot v-if="asChild" />
<Box v-else :class="cn(carouselItem, className)">
<slot />
</Box>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/carousel/index.ts">
{{ `
export { default as CarouselRoot } from "./CarouselRoot.vue";
export { default as CarouselControl } from "./CarouselControl.vue";
export { default as CarouselPrevTrigger } from "./CarouselPrevTrigger.vue";
export { default as CarouselNextTrigger } from "./CarouselNextTrigger.vue";
export { default as CarouselIndicatorGroup } from "./CarouselIndicatorGroup.vue";
export { default as CarouselIndicator } from "./CarouselIndicator.vue";
export { default as CarouselItemGroup } from "./CarouselItemGroup.vue";
export { default as CarouselItem } from "./CarouselItem.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
CarouselRoot,
CarouselControl,
CarouselPrevTrigger,
CarouselNextTrigger,
CarouselIndicatorGroup,
CarouselIndicator,
CarouselItemGroup,
CarouselItem,
} from "@/components/ui/carousel";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<CarouselRoot :default-page="0" :slide-count="images.length" class="size-72">
<CarouselControl>
<CarouselPrevTrigger />
<CarouselNextTrigger />
</CarouselControl>
<CarouselIndicatorGroup>
<CarouselIndicator v-for="(_, index) in images" :key="index" :index="index" />
</CarouselIndicatorGroup>
<CarouselItemGroup>
<CarouselItem v-for="(image, index) in images" :key="index" :index="index"
class="text-5xl bold flex items-center justify-center">
\{\{ index + 1 \}\}
</CarouselItem>
</CarouselItemGroup>
</CarouselRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<CarouselRoot :default-page="0" :slide-count="images.length" class="size-72">
<CarouselControl>
<CarouselPrevTrigger />
<CarouselNextTrigger />
</CarouselControl>
<CarouselIndicatorGroup>
<CarouselIndicator v-for="(_, index) in images" :key="index" :index="index" />
</CarouselIndicatorGroup>
<CarouselItemGroup>
<CarouselItem v-for="(image, index) in images" :key="index" :index="index">
<img :src="image" :alt="`Slide $\{index\}`" />
</CarouselItem>
</CarouselItemGroup>
</CarouselRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<CarouselRoot :default-page="0" :slide-count="images.length" class="size-72">
<CarouselControl>
<CarouselPrevTrigger />
<CarouselNextTrigger />
</CarouselControl>
<CarouselIndicatorGroup>
<CarouselIndicator v-for="(_, index) in images" :key="index" :index="index" />
</CarouselIndicatorGroup>
<CarouselItemGroup>
<CarouselItem v-for="(image, index) in images" :key="index" :index="index">
<img :src="image" :alt="\`Slide $\{index\}\`" />
</CarouselItem>
</CarouselItemGroup>
</CarouselRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+235
View File
@@ -0,0 +1,235 @@
<script lang="ts" setup>
import { Chart, getColor } from "@/components/ui/chart";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Chart class="max-w-100" :config="{
type: 'bar',
data: {
labels: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
datasets: [
{
label: 'Html Template',
maxBarThickness: 12,
data: [
60, 150, 30, 200, 180, 50, 180, 120, 230, 180, 250, 270,
],
backgroundColor: () => getColor('--color-foreground', 0.3),
borderColor: () => getColor('--color-foreground'),
borderWidth: 1,
},
],
},
options: {
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
},
}" />
</template>
<template #code>
<PreviewCode>
{{`
<Chart class="max-w-100" :config="{
type: 'bar',
data: {
labels: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
datasets: [
{
label: 'Html Template',
maxBarThickness: 12,
data: [
60, 150, 30, 200, 180, 50, 180, 120, 230, 180, 250, 270,
],
backgroundColor: () => getColor('--color-foreground', 0.3),
borderColor: () => getColor('--color-foreground'),
borderWidth: 1,
},
],
},
options: {
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
},
}" />
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add chart.js</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/chart/Chart.vue">
{{`
<script lang="ts" setup generic="TType extends ChartType">
import ChartJs from "chart.js/auto";
import { ref, onMounted } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { chart } from "@mykopkb/core/styles/chart.styles";
import type { ChartType, ChartConfiguration } from "chart.js";
const {
class: className,
config,
getRef,
...props
} = defineProps<{
class?: string;
config: ChartConfiguration<TType>;
getRef?: (chart: ChartJs<TType>) => void;
}>();
const chartRef = ref<
| (HTMLCanvasElement & {
instance?: ChartJs<TType>;
})
| null
>(null);
onMounted(() => {
if (chartRef.value && !chartRef.value.instance) {
chartRef.value.instance = new ChartJs(chartRef.value, config);
getRef?.(chartRef.value.instance);
}
});
</script>
<template>
<canvas :class="cn(chart, className)" ref="chartRef" v-bind="props" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/chart/index.ts">
{{ `
export { default as Chart } from "./Chart.vue";
export { getColor } from "./utils";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { Chart, getColor } from "@/components/ui/chart";
` }}
</PreviewCode>
<PreviewCode>
{{`
<Chart class="max-w-100" :config="{
type: 'bar',
data: {
labels: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
datasets: [
{
label: 'Html Template',
maxBarThickness: 12,
data: [
60, 150, 30, 200, 180, 50, 180, 120, 230, 180, 250, 270,
],
backgroundColor: () => getColor('--color-foreground', 0.3),
borderColor: () => getColor('--color-foreground'),
borderWidth: 1,
},
],
},
options: {
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
},
}" />
` }}
</PreviewCode>
</div>
</template>
+235
View File
@@ -0,0 +1,235 @@
<script lang="ts" setup>
import {
CheckboxRoot,
CheckboxLabel,
CheckboxControl,
} from "@/components/ui/checkbox";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<CheckboxRoot>
<CheckboxControl />
<CheckboxLabel>Accept terms and conditions</CheckboxLabel>
</CheckboxRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<CheckboxRoot>
<CheckboxControl />
<CheckboxLabel>Accept terms and conditions</CheckboxLabel>
</CheckboxRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/checkbox</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/checkbox/CheckboxRoot.vue">
{{`
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { checkboxRoot } from "@mykopkb/core/styles/checkbox.styles";
import * as checkbox from "@zag-js/checkbox";
import { useMachine, normalizeProps } from "@zag-js/vue";
import type { Props } from "@zag-js/checkbox";
import { CheckboxHiddenInput } from ".";
import { computed, provide } from "vue";
const {
class: className,
checked = undefined,
...props
} = defineProps<Partial<Props> & { class?: string }>();
const service = useMachine(
checkbox.machine,
computed(() => ({
...props,
checked,
id: crypto.randomUUID(),
}))
);
const api = computed(() => checkbox.connect(service, normalizeProps));
provide("checkboxApi", api);
</script>
<template>
<label :class="cn(checkboxRoot, className)" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot />
<CheckboxHiddenInput />
</label>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/checkbox/CheckboxLabel.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import type { Api } from "@zag-js/checkbox";
import { checkboxLabel } from "@mykopkb/core/styles/checkbox.styles";
import { label } from "@mykopkb/core/styles/label.styles";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
asChild?: boolean;
class?: string;
}>();
const api = inject<Api>("checkboxApi");
</script>
<template>
<Slot :class="cn([label, checkboxLabel, className])" v-bind="{ ...props, ...$attrs, ...api?.getLabelProps() }">
<slot v-if="asChild" />
<span v-else>
<slot />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/checkbox/CheckboxControl.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { CheckIcon } from "@lucide/vue";
import { cn } from "@mykopkb/core/utils/cn";
import { checkboxControl } from "@mykopkb/core/styles/checkbox.styles";
import { CheckboxIndicator } from ".";
import type { Api } from "@zag-js/checkbox";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
asChild?: boolean;
class?: string;
}>();
const api = inject<Api>("checkboxApi");
</script>
<template>
<Slot :class="cn(checkboxControl, className)" v-bind="{ ...props, ...$attrs, ...api?.getControlProps() }">
<slot v-if="asChild" />
<div v-else>
<CheckboxIndicator>
<CheckIcon />
</CheckboxIndicator>
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/checkbox/CheckboxIndicator.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/checkbox";
import { cn } from "@mykopkb/core/utils/cn";
import { checkboxIndicator } from "@mykopkb/core/styles/checkbox.styles";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
asChild?: boolean;
class?: string;
}>();
const api = inject<Api>("checkboxApi");
</script>
<template>
<Slot :class="cn(checkboxIndicator, className)" v-bind="{ ...props, ...$attrs, ...api?.getIndicatorProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/checkbox/CheckboxHiddenInput.vue">
{{ `
<script lang="ts" setup>
import type { Api } from "@zag-js/checkbox";
import { cn } from "@mykopkb/core/utils/cn";
import { checkboxHiddenInput } from "@mykopkb/core/styles/checkbox.styles";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("checkboxApi");
</script>
<template>
<input :class="cn(checkboxHiddenInput, className)"
v-bind="{ ...props, ...$attrs, ...api?.getHiddenInputProps() }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/checkbox/index.ts">
{{ `
export { default as CheckboxRoot } from "./CheckboxRoot.vue";
export { default as CheckboxLabel } from "./CheckboxLabel.vue";
export { default as CheckboxControl } from "./CheckboxControl.vue";
export { default as CheckboxIndicator } from "./CheckboxIndicator.vue";
export { default as CheckboxHiddenInput } from "./CheckboxHiddenInput.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
CheckboxRoot,
CheckboxLabel,
CheckboxControl,
} from "@/components/ui/checkbox";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<CheckboxRoot>
<CheckboxControl />
<CheckboxLabel>Accept terms and conditions</CheckboxLabel>
</CheckboxRoot>
` }}
</PreviewCode>
</div>
</template>
File diff suppressed because it is too large Load Diff
+197
View File
@@ -0,0 +1,197 @@
<script lang="ts" setup>
import { onMounted, ref, watch } from "vue";
import debounce from "lodash/debounce";
import axios from "axios";
import {
SectionTitle,
SectionContent,
InstallPackage,
} from "@/components/docs";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import DataTable from "@/components/ui/usage/DataTable.vue";
import type { SortConfig, TableHeader } from "@/components/ui/usage/DataTable.vue";
import { api } from "@/core/services/api";
import { useApiPagination } from "@/composables/useApiPagination";
import type { PaginatedApiResponse } from "@/core/types/api";
type UserRole = {
id: string;
name: string;
guard_name: string;
};
type UserListItem = {
id: string;
name: string;
email: string;
ic_number: string;
position: string;
phone_number: string;
image_url: string | null;
status: string;
roles: UserRole[];
};
const users = ref<UserListItem[]>([]);
const loading = ref(false);
const error = ref<string | null>(null);
const search = ref("");
const statusFilter = ref("");
const sortBy = ref<SortConfig[]>([{ key: "name", order: "asc" }]);
const page = ref(1);
const itemsPerPage = ref(10);
const { pagination, applyPagination } = useApiPagination({ per_page: 10 });
const headers: TableHeader[] = [
{ title: "Name", key: "name", sortable: true },
{ title: "Email", key: "email", sortable: true },
{ title: "Position", key: "position", sortable: true },
{
title: "Role",
key: "roles",
sortable: false,
exportValue: (item) =>
item.roles?.map((role: UserRole) => role.name).join(", ") || "-",
},
{ title: "Status", key: "status", sortable: true },
];
function statusBadgeVariant(status: string) {
if (status === "active") return "success";
if (status === "inactive") return "danger";
return "pending";
}
async function fetchUsers(requestPage = page.value) {
loading.value = true;
error.value = null;
try {
const activeSort = sortBy.value[0];
const { data } = await api.get<PaginatedApiResponse<UserListItem>>(
"/v1/users",
{
params: {
page: requestPage,
per_page: itemsPerPage.value,
sort_by: activeSort?.key ?? "name",
sort_order: activeSort?.order ?? "asc",
...(search.value.trim() ? { search: search.value.trim() } : {}),
...(statusFilter.value.trim()
? { status: statusFilter.value.trim() }
: {}),
},
}
);
if (!data.success) {
throw new Error(data.message ?? "Failed to load users");
}
users.value = data.data;
applyPagination(data.pagination);
page.value = data.pagination.current_page;
} catch (err) {
users.value = [];
if (axios.isAxiosError(err)) {
const message = (err.response?.data as { message?: string } | undefined)
?.message;
error.value = message ?? err.message;
} else if (err instanceof Error) {
error.value = err.message;
} else {
error.value = "Failed to load users";
}
applyPagination({
current_page: 1,
per_page: itemsPerPage.value,
total: 0,
last_page: 1,
from: null,
to: null,
has_more_pages: false,
});
page.value = 1;
} finally {
loading.value = false;
}
}
function handleSortUpdate(value: SortConfig[]) {
sortBy.value = value;
fetchUsers(1);
}
const debouncedSearch = debounce(() => {
fetchUsers(1);
}, 400);
watch(search, () => {
debouncedSearch();
});
watch(statusFilter, () => {
fetchUsers(1);
});
watch(page, (nextPage, previousPage) => {
if (nextPage !== previousPage) {
fetchUsers(nextPage);
}
});
watch(itemsPerPage, (nextValue, previousValue) => {
if (nextValue !== previousValue) {
fetchUsers(1);
}
});
onMounted(() => {
fetchUsers(1);
});
</script>
<template>
<div id="preview" class="-mt-20 w-full space-y-4">
<div class="flex flex-wrap items-center gap-3">
<Input v-model="search" placeholder="Search name, email, IC, phone, role..." class="max-w-96" />
<Input v-model="statusFilter" placeholder="Filter status (e.g. active)" class="max-w-56" />
</div>
<p v-if="error" class="text-sm text-danger">{{ error }}</p>
<DataTable :headers="headers" :items="users" :loading="loading" :pagination="pagination" :current-sort="sortBy"
show-pagination exportable export-file-name="users" v-model:page="page" v-model:items-per-page="itemsPerPage"
@update:sort-by="handleSortUpdate">
<template #item.name="{ item }">
<span class="font-medium">{{ item.name }}</span>
</template>
<template #item.email="{ item }">
<span class="lowercase">{{ item.email }}</span>
</template>
<template #item.roles="{ item }">
{{item.roles?.map((role: UserRole) => role.name).join(", ") || "-"}}
</template>
<template #item.status="{ item }">
<Badge :variant="statusBadgeVariant(item.status)" class="capitalize">
{{ item.status }}
</Badge>
</template>
</DataTable>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage class="mb-0">
add xlsx jspdf jspdf-autotable file-saver
</InstallPackage>
</div>
</template>
File diff suppressed because it is too large Load Diff
+560
View File
@@ -0,0 +1,560 @@
<script lang="ts" setup>
import {
DialogRoot,
DialogTrigger,
DialogContent,
DialogTitle,
DialogDescription,
DialogCloseTrigger,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { SquareX, Save, ExternalLink } from "@lucide/vue";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
import { ref } from "vue";
const dialog = ref(false);
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<DialogRoot>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<DialogCloseTrigger>
<SquareX />
Close
</DialogCloseTrigger>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<DialogRoot>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<DialogCloseTrigger>
<SquareX />
Close
</DialogCloseTrigger>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/dialog</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/dialog/DialogRoot.vue">
{{`
<script lang="ts" setup>
import { provide, computed } from "vue";
import * as dialog from "@zag-js/dialog";
import type { Props } from "@zag-js/dialog";
import { useMachine, normalizeProps } from "@zag-js/vue";
const {
class: className,
asChild = false,
open = undefined,
closeOnInteractOutside = undefined,
...props
} = defineProps<
Partial<Props> & {
class?: string;
asChild?: boolean;
}
>();
const service = useMachine(dialog.machine, {
...props,
get open() {
return open;
},
closeOnInteractOutside,
id: crypto.randomUUID(),
});
const api = computed(() => dialog.connect(service, normalizeProps));
provide("dialogApi", api);
</script>
<template>
<slot />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/DialogTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { dialogTrigger } from "@mykopkb/core/styles/dialog.styles";
import { Button } from "@/components/ui/button";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("dialogApi");
</script>
<template>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getTriggerProps() }">
<Button variant="secondary" look="outline" v-if="!asChild" :class="cn(dialogTrigger, className)">
<slot />
</Button>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/DialogBackdrop.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { dialogBackdrop } from "@mykopkb/core/styles/dialog.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("dialogApi");
</script>
<template>
<Slot :class="cn(dialogBackdrop, className)" v-bind="{ ...props, ...$attrs, ...api?.getBackdropProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/DialogPositioner.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { dialogPositioner } from "@mykopkb/core/styles/dialog.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("dialogApi");
</script>
<template>
<Slot :class="cn(dialogPositioner, className)" v-bind="{ ...props, ...$attrs, ...api?.getPositionerProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/DialogContent.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { dialogContent } from "@mykopkb/core/styles/dialog.styles";
import { Box } from "@/components/ui/box";
import { DialogBackdrop, DialogPositioner } from "@/components/ui/dialog";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("dialogApi");
</script>
<template>
<Teleport to="body">
<DialogBackdrop />
<DialogPositioner>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getContentProps() }">
<slot v-if="asChild" />
<div v-else>
<Box raised="double" :class="cn(dialogContent, className)" v-bind="{ ...props }">
<div>
<slot />
</div>
</Box>
</div>
</Slot>
</DialogPositioner>
</Teleport>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/DialogTitle.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { dialogTitle } from "@mykopkb/core/styles/dialog.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("dialogApi");
</script>
<template>
<Slot :class="cn(dialogTitle, className)" v-bind="{ ...props, ...$attrs, ...api?.getTitleProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/DialogDescription.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { dialogDescription } from "@mykopkb/core/styles/dialog.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("dialogApi");
</script>
<template>
<Slot :class="cn(dialogDescription, className)" v-bind="{ ...props, ...$attrs, ...api?.getDescriptionProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/DialogCloseTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { dialogCloseTrigger } from "@mykopkb/core/styles/dialog.styles";
import { Button } from "@/components/ui/button";
import type { Api } from "@zag-js/dialog";
import {
buttonVariants,
type ButtonVariants,
} from "@mykopkb/core/styles/button.styles";
import { X } from "@lucide/vue";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
look = "outline",
variant = "secondary",
size,
asChild = false,
...props
} = defineProps<
ButtonVariants & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("dialogApi");
</script>
<template>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getCloseTriggerProps() }">
<Button variant="ghost" v-if="!$slots.default" :class="cn(dialogCloseTrigger, className)"
v-bind="{ ...props }">
<X class="size-4" />
</Button>
<template v-else>
<slot v-if="asChild" />
<Button v-else :class="
cn(buttonVariants({ look, variant, size, className }), className)
">
<slot />
</Button>
</template>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/dialog/index.ts">
{{ `
export { default as DialogRoot } from "./DialogRoot.vue";
export { default as DialogTrigger } from "./DialogTrigger.vue";
export { default as DialogBackdrop } from "./DialogBackdrop.vue";
export { default as DialogPositioner } from "./DialogPositioner.vue";
export { default as DialogContent } from "./DialogContent.vue";
export { default as DialogTitle } from "./DialogTitle.vue";
export { default as DialogDescription } from "./DialogDescription.vue";
export { default as DialogCloseTrigger } from "./DialogCloseTrigger.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
DialogRoot,
DialogTrigger,
DialogContent,
DialogTitle,
DialogDescription,
DialogCloseTrigger,
} from "@/components/ui/dialog";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<DialogRoot>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<DialogCloseTrigger>
<SquareX />
Close
</DialogCloseTrigger>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<DialogRoot>
<DialogTrigger>Custom Close</DialogTrigger>
<DialogContent>
<DialogTitle>Share Link</DialogTitle>
<DialogDescription>
Anyone who has this link will be able to view this.
</DialogDescription>
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<DialogCloseTrigger>
<ExternalLink />
Share Link
</DialogCloseTrigger>
</div>
</DialogContent>
</DialogRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<DialogRoot>
<DialogTrigger>Custom Close</DialogTrigger>
<DialogContent>
<DialogTitle>Share Link</DialogTitle>
<DialogDescription>
Anyone who has this link will be able to view this.
</DialogDescription>
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<DialogCloseTrigger>
<ExternalLink />
Share Link
</DialogCloseTrigger>
</div>
</DialogContent>
</DialogRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Button look="outline" variant="secondary" @click.prevent="dialog = true">
Programmatic Trigger
</Button>
<DialogRoot :open="dialog" @openChange="(details) => (dialog = details.open)">
<DialogContent>
<DialogTitle>Share Link</DialogTitle>
<DialogDescription>
Anyone who has this link will be able to view this.
</DialogDescription>
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<DialogCloseTrigger>
<ExternalLink />
Share Link
</DialogCloseTrigger>
</div>
</DialogContent>
</DialogRoot>
</template>
<template #code>
<PreviewCode>
{{`
const dialog = ref(false);
<Button look="outline" variant="secondary" @click.prevent="dialog = true">
Programmatic Trigger
</Button>
<DialogRoot :open="dialog" @openChange="(details) => (dialog = details.open)">
<DialogContent>
<DialogTitle>Share Link</DialogTitle>
<DialogDescription>
Anyone who has this link will be able to view this.
</DialogDescription>
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<DialogCloseTrigger>
<ExternalLink />
Share Link
</DialogCloseTrigger>
</div>
</DialogContent>
</DialogRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+484
View File
@@ -0,0 +1,484 @@
<script lang="ts" setup>
import { Button } from "@/components/ui/button";
import {
CheckboxRoot,
CheckboxLabel,
CheckboxControl,
} from "@/components/ui/checkbox";
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSeparator,
FieldSet,
FieldTitle,
FieldContent,
} from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import {
SelectRoot,
SelectControl,
SelectTrigger,
SelectValueText,
SelectContent,
SelectItemGroup,
SelectItemGroupLabel,
SelectItem,
SelectItemText,
} from "@/components/ui/select";
import * as select from "@zag-js/select";
import { Textarea } from "@/components/ui/textarea";
import {
RadioGroupRoot,
RadioGroupItem,
RadioGroupItemControl,
} from "@/components/ui/radio-group";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<div class="w-full max-w-md">
<form>
<FieldGroup>
<FieldSet>
<FieldLegend>Payment Method</FieldLegend>
<FieldDescription>
All transactions are secure and encrypted
</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel for="card-name">Name on Card</FieldLabel>
<Input id="card-name" placeholder="Evil Rabbit" required />
</Field>
<Field>
<FieldLabel for="card-number">Card Number</FieldLabel>
<Input id="card-number" placeholder="1234 5678 9012 3456" required />
<FieldDescription>Enter your 16-digit card number</FieldDescription>
</Field>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<FieldSet>
<FieldLegend>Billing Address</FieldLegend>
<FieldDescription>
The billing address associated with your payment method
</FieldDescription>
<CheckboxRoot>
<CheckboxControl />
<CheckboxLabel class="font-normal">
Same as shipping address
</CheckboxLabel>
</CheckboxRoot>
</FieldSet>
<Field orientation="horizontal">
<Button look="outline" type="submit">Submit</Button>
<Button type="button">Cancel</Button>
</Field>
</FieldGroup>
</form>
</div>
</template>
<template #code>
<PreviewCode>
{{ `
<div class="w-full max-w-md">
<form>
<FieldGroup>
<FieldSet>
<FieldLegend>Payment Method</FieldLegend>
<FieldDescription>
All transactions are secure and encrypted
</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel for="card-name">Name on Card</FieldLabel>
<Input id="card-name" placeholder="Evil Rabbit" required />
</Field>
<Field>
<FieldLabel for="card-number">Card Number</FieldLabel>
<Input id="card-number" placeholder="1234 5678 9012 3456" required />
<FieldDescription>Enter your 16-digit card number</FieldDescription>
</Field>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<FieldSet>
<FieldLegend>Billing Address</FieldLegend>
<FieldDescription>
The billing address associated with your payment method
</FieldDescription>
<CheckboxRoot>
<CheckboxControl />
<CheckboxLabel class="font-normal">
Same as shipping address
</CheckboxLabel>
</CheckboxRoot>
</FieldSet>
<Field orientation="horizontal">
<Button look="outline" type="submit">Submit</Button>
<Button type="button">Cancel</Button>
</Field>
</FieldGroup>
</form>
</div>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/field/Field.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import {
fieldVariants,
type FieldVariants,
} from "@mykopkb/core/styles/field.styles";
const {
class: className,
orientation = "vertical",
...props
} = defineProps<
FieldVariants & {
class?: string;
}
>();
</script>
<template>
<div role="group" data-part="field" :data-orientation="orientation"
:class="cn(fieldVariants({ orientation }), className)" v-bind="{ ...props }">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/field/FieldContent.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { fieldContent } from "@mykopkb/core/styles/field.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<div data-part="field-content" :class="cn(fieldContent, className)" v-bind="{ ...props }">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/field/FieldDescription.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { fieldDescription } from "@mykopkb/core/styles/field.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<p data-part="field-description" :class="cn(fieldDescription, className)" v-bind="{ ...props }">
<slot />
</p>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/field/FieldLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { Label } from "@/components/ui/label";
import { fieldLabel } from "@mykopkb/core/styles/field.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<Label data-part="field-label" :class="cn(fieldLabel, className)" v-bind="{ ...props }">
<slot />
</Label>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/field/FieldSeparator.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { fieldSeparator } from "@mykopkb/core/styles/field.styles";
import { Separator } from "@/components/ui/separator";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<div data-part="field-separator" :data-content="!!$slots.default" :class="cn(fieldSeparator, className)"
v-bind="{ ...props }">
<Separator class="absolute inset-0 top-1/2" />
<span v-if="$slots.default" data-part="field-separator-content">
<slot />
</span>
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/field/index.ts">
{{ `
export { default as Field } from "./Field.vue";
export { default as FieldContent } from "./FieldContent.vue";
export { default as FieldDescription } from "./FieldDescription.vue";
export { default as FieldError } from "./FieldError.vue";
export { default as FieldGroup } from "./FieldGroup.vue";
export { default as FieldLabel } from "./FieldLabel.vue";
export { default as FieldLegend } from "./FieldLegend.vue";
export { default as FieldSeparator } from "./FieldSeparator.vue";
export { default as FieldSet } from "./FieldSet.vue";
export { default as FieldTitle } from "./FieldTitle.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
Field,
FieldContent,
FieldDescription,
FieldError,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSeparator,
FieldSet,
FieldTitle,
} from "@/components/ui/field";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Field>
<FieldLabel for="email">Email</FieldLabel>
<Input id="email" placeholder="Enter your email" />
<FieldDescription>We'll never share your email.</FieldDescription>
</Field>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<form>
<FieldGroup>
<FieldSet>
<FieldLegend>Payment Method</FieldLegend>
<FieldDescription>
All transactions are secure and encrypted
</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel for="card-name">Name on Card</FieldLabel>
<Input id="card-name" placeholder="Evil Rabbit" required />
</Field>
<Field>
<FieldLabel for="card-number">Card Number</FieldLabel>
<Input id="card-number" placeholder="1234 5678 9012 3456" required />
<FieldDescription>Enter your 16-digit card number</FieldDescription>
</Field>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<FieldSet>
<FieldLegend>Billing Address</FieldLegend>
<FieldDescription>
The billing address associated with your payment method
</FieldDescription>
<CheckboxRoot>
<CheckboxControl />
<CheckboxLabel class="font-normal">
Same as shipping address
</CheckboxLabel>
</CheckboxRoot>
</FieldSet>
<FieldSet>
<FieldGroup>
<Field>
<FieldLabel for="comments">Comments</FieldLabel>
<Textarea id="comments" placeholder="Add any additional comments" class="resize-none" />
</Field>
</FieldGroup>
</FieldSet>
<Field orientation="horizontal">
<Button look="outline" type="submit">Submit</Button>
<Button type="button">Cancel</Button>
</Field>
</FieldGroup>
</form>
</template>
<template #code>
<PreviewCode>
{{ `
<form>
<FieldGroup>
<FieldSet>
<FieldLegend>Payment Method</FieldLegend>
<FieldDescription>
All transactions are secure and encrypted
</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel for="card-name">Name on Card</FieldLabel>
<Input id="card-name" placeholder="Evil Rabbit" required />
</Field>
<Field>
<FieldLabel for="card-number">Card Number</FieldLabel>
<Input id="card-number" placeholder="1234 5678 9012 3456" required />
<FieldDescription>Enter your 16-digit card number</FieldDescription>
</Field>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<FieldSet>
<FieldLegend>Billing Address</FieldLegend>
<FieldDescription>
The billing address associated with your payment method
</FieldDescription>
<CheckboxRoot>
<CheckboxControl />
<CheckboxLabel class="font-normal">
Same as shipping address
</CheckboxLabel>
</CheckboxRoot>
</FieldSet>
<FieldSet>
<FieldGroup>
<Field>
<FieldLabel for="comments">Comments</FieldLabel>
<Textarea id="comments" placeholder="Add any additional comments" class="resize-none" />
</Field>
</FieldGroup>
</FieldSet>
<Field orientation="horizontal">
<Button look="outline" type="submit">Submit</Button>
<Button type="button">Cancel</Button>
</Field>
</FieldGroup>
</form>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<FieldGroup class="w-full max-w-xs">
<FieldSet>
<FieldLegend variant="label">Compute Environment</FieldLegend>
<FieldDescription>
Select the compute environment for your cluster.
</FieldDescription>
<RadioGroupRoot defaultValue="React">
<FieldLabel>
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Kubernetes</FieldTitle>
<FieldDescription>
Run GPU workloads on a K8s cluster.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="React">
<RadioGroupItemControl />
</RadioGroupItem>
</Field>
</FieldLabel>
<FieldLabel>
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Virtual Machine</FieldTitle>
<FieldDescription>
Access a cluster to run GPU workloads.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="Solid">
<RadioGroupItemControl />
</RadioGroupItem>
</Field>
</FieldLabel>
</RadioGroupRoot>
</FieldSet>
</FieldGroup>
</template>
<template #code>
<PreviewCode>
{{ `
<FieldGroup class="w-full max-w-xs">
<FieldSet>
<FieldLegend variant="label">Compute Environment</FieldLegend>
<FieldDescription>
Select the compute environment for your cluster.
</FieldDescription>
<RadioGroupRoot defaultValue="React">
<FieldLabel>
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Kubernetes</FieldTitle>
<FieldDescription>
Run GPU workloads on a K8s cluster.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="React">
<RadioGroupItemControl />
</RadioGroupItem>
</Field>
</FieldLabel>
<FieldLabel>
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Virtual Machine</FieldTitle>
<FieldDescription>
Access a cluster to run GPU workloads.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="Solid">
<RadioGroupItemControl />
</RadioGroupItem>
</Field>
</FieldLabel>
</RadioGroupRoot>
</FieldSet>
</FieldGroup>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+74
View File
@@ -0,0 +1,74 @@
<script lang="ts" setup>
import { Input } from "@/components/ui/input";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Input class="w-84" type="email" placeholder="Email" />
</template>
<template #code>
<PreviewCode>
{{ `
<Input class="w-84" type="email" placeholder="Email" />
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/input/Input.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { input } from "@mykopkb/core/styles/input.styles";
const {
class: className,
type,
...props
} = defineProps<{
class?: string;
type?: string;
}>();
</script>
<template>
<input :type="type" :class="cn(input, className)" v-bind="{ ...props }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/input/index.ts">
{{ `
export { default as Input } from "./Input.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { Input } from "@/components/ui/input";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Input class="w-84" type="email" placeholder="Email" />
` }}
</PreviewCode>
</div>
</template>
+369
View File
@@ -0,0 +1,369 @@
<script lang="ts" setup>
import { Map } from "@/components/ui/map";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
const markersData = {
type: "FeatureCollection" as const,
features: [
{
type: "Feature" as const,
properties: { name: "Cafe Berlin", type: "cafe" },
geometry: {
type: "Point" as const,
coordinates: [13.388, 52.517],
},
},
{
type: "Feature" as const,
properties: { name: "Restaurant Alex", type: "restaurant" },
geometry: {
type: "Point" as const,
coordinates: [13.39, 52.518],
},
},
{
type: "Feature" as const,
properties: { name: "Coffee House", type: "cafe" },
geometry: {
type: "Point" as const,
coordinates: [13.385, 52.515],
},
},
{
type: "Feature" as const,
properties: { name: "Pizza Place", type: "restaurant" },
geometry: {
type: "Point" as const,
coordinates: [13.392, 52.519],
},
},
{
type: "Feature" as const,
properties: { name: "Burger Joint", type: "restaurant" },
geometry: {
type: "Point" as const,
coordinates: [13.387, 52.516],
},
},
{
type: "Feature" as const,
properties: { name: "Starbucks", type: "cafe" },
geometry: {
type: "Point" as const,
coordinates: [13.391, 52.52],
},
},
{
type: "Feature" as const,
properties: { name: "Sushi Bar", type: "restaurant" },
geometry: {
type: "Point" as const,
coordinates: [13.395, 52.522],
},
},
{
type: "Feature" as const,
properties: { name: "Bakery", type: "cafe" },
geometry: {
type: "Point" as const,
coordinates: [13.383, 52.514],
},
},
{
type: "Feature" as const,
properties: { name: "Italian Restaurant", type: "restaurant" },
geometry: {
type: "Point" as const,
coordinates: [13.398, 52.525],
},
},
{
type: "Feature" as const,
properties: { name: "Tea House", type: "cafe" },
geometry: {
type: "Point" as const,
coordinates: [13.38, 52.512],
},
},
],
};
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Map class="w-full h-96" :center="[13.388, 52.517]" :zoom="9.5" :markers="markersData" />
</template>
<template #code>
<PreviewCode>
{{ `
<Map class="w-full h-96" :center="[13.388, 52.517]" :zoom="9.5" :markers="markersData" />
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add maplibre-gl</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/map/Map.vue">
{{`
<script setup lang="ts">
import "maplibre-gl/dist/maplibre-gl.css";
import maplibregl, { type MapOptions } from "maplibre-gl";
import { ref, onMounted } from "vue";
import { Button } from "@/components/ui/button";
import { Plus, Minus, MapPin, Compass, Expand, X } from "@lucide/vue";
import type { FeatureCollection, Point } from "geojson";
import { cn } from "@mykopkb/core/utils/cn";
import { map } from "@mykopkb/core/styles/map.styles";
const mapRef = ref();
const mapInstance = ref<maplibregl.Map>();
const isFullscreen = ref(false);
const {
class: className,
markers,
...props
} = defineProps<
Partial<MapOptions> & {
class?: string;
markers?: FeatureCollection<Point>;
}
>();
onMounted(() => {
mapInstance.value = new maplibregl.Map({
...Object.fromEntries(Object.entries(props).filter(([_, value]) => value)),
style: "https://tiles.openfreemap.org/styles/positron",
container: mapRef.value,
});
markers &&
mapInstance.value.on("load", () => {
// Add source with clustering
mapInstance.value!.addSource("markers", {
type: "geojson",
data: markers,
cluster: true,
clusterMaxZoom: 14, // Max zoom for clustering
clusterRadius: 50, // Cluster radius in pixels
});
// Layer for clusters (circles)
mapInstance.value!.addLayer({
id: "clusters",
type: "circle",
source: "markers",
filter: ["has", "point_count"],
paint: {
"circle-color": [
"step",
["get", "point_count"],
"#cccccc", // Color for < 5 points
5,
"#cccccc", // Color for 5-10 points
10,
"#cccccc", // Color for > 10 points
],
"circle-radius": [
"step",
["get", "point_count"],
20, // Radius for < 5 points
5,
30, // Radius for 5-10 points
10,
40, // Radius for > 10 points
],
},
});
// Layer for cluster count numbers
mapInstance.value!.addLayer({
id: "cluster-count",
type: "symbol",
source: "markers",
filter: ["has", "point_count"],
layout: {
"text-field": "{point_count_abbreviated}",
"text-font": ["Open Sans Bold"],
"text-size": 12,
},
});
// Layer for individual points (unclustered)
mapInstance.value!.addLayer({
id: "unclustered-point",
type: "circle",
source: "markers",
filter: ["!", ["has", "point_count"]],
paint: {
"circle-color": "#333333",
"circle-radius": 8,
"circle-stroke-width": 2,
"circle-stroke-color": "#ffffff",
},
});
// Click on cluster to zoom in
mapInstance.value!.on("click", "clusters", async (e) => {
const features = mapInstance.value!.queryRenderedFeatures(e.point, {
layers: ["clusters"],
});
const clusterId = features[0]?.properties.cluster_id;
const source = mapInstance.value!.getSource(
"markers"
) as maplibregl.GeoJSONSource;
try {
const zoom = await source.getClusterExpansionZoom(clusterId);
mapInstance.value!.easeTo({
center: (features[0]?.geometry as any).coordinates,
zoom: zoom,
});
} catch (err) {
console.error("Error getting cluster expansion zoom:", err);
}
});
// Click on individual point to show popup
mapInstance.value!.on("click", "unclustered-point", (e) => {
const coordinates = (
e.features![0]?.geometry as any
).coordinates.slice();
const { name, type } = (e.features![0]?.properties || {}) as any;
new maplibregl.Popup()
.setLngLat(coordinates)
.setHTML(\`<h3>\${name}</h3><p>\${type}</p>\`)
.addTo(mapInstance.value!);
});
// Change cursor on hover cluster/point
mapInstance.value!.on("mouseenter", "clusters", () => {
mapInstance.value!.getCanvas().style.cursor = "pointer";
});
mapInstance.value!.on("mouseleave", "clusters", () => {
mapInstance.value!.getCanvas().style.cursor = "";
});
mapInstance.value!.on("mouseenter", "unclustered-point", () => {
mapInstance.value!.getCanvas().style.cursor = "pointer";
});
mapInstance.value!.on("mouseleave", "unclustered-point", () => {
mapInstance.value!.getCanvas().style.cursor = "";
});
});
});
const zoomIn = () => {
mapInstance.value?.zoomIn();
};
const zoomOut = () => {
mapInstance.value?.zoomOut();
};
const resetNorth = () => {
mapInstance.value?.easeTo({ bearing: 0, pitch: 0 });
};
const locateMe = () => {
if (!navigator.geolocation) {
alert("Geolocation is not supported by your browser");
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
const { longitude, latitude } = position.coords;
mapInstance.value?.flyTo({
center: [longitude, latitude],
zoom: 14,
});
new maplibregl.Marker({ color: "var(--color-foreground)" })
.setLngLat([longitude, latitude])
.addTo(mapInstance.value!);
},
(error) => {
alert("Failed to get location: " + error.message);
}
);
};
const toggleFullscreen = () => {
if (!mapRef.value) return;
if (!isFullscreen.value) {
if (mapRef.value.requestFullscreen) {
mapRef.value.requestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
isFullscreen.value = !isFullscreen.value;
};
</script>
<template>
<div data-scope="map" data-part="root" ref="mapRef" :class="cn(map, className)">
<div data-scope="map" data-part="controls">
<Button data-scope="map" data-part="zoom-in" @click="zoomIn" variant="ghost" size="sm">
<Plus />
</Button>
<Button data-scope="map" data-part="zoom-out" @click="zoomOut" variant="ghost" size="sm">
<Minus />
</Button>
<Button data-scope="map" data-part="reset-north" @click="resetNorth" variant="ghost" size="sm">
<Compass />
</Button>
<Button data-scope="map" data-part="locate" @click="locateMe" variant="ghost" size="sm">
<MapPin />
</Button>
<Button data-scope="map" data-part="toggle-fullscreen" @click="toggleFullscreen" variant="ghost" size="sm">
<Expand v-if="!isFullscreen" />
<X v-else />
</Button>
</div>
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/map/index.ts">
{{ `
export { default as Map } from "./Map.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { Map } from "@/components/ui/map";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Map class="w-full h-96" :center="[13.388, 52.517]" :zoom="9.5" :markers="markersData" />
` }}
</PreviewCode>
</div>
</template>
+831
View File
@@ -0,0 +1,831 @@
<script lang="ts" setup>
import {
MenuRoot,
MenuTrigger,
MenuPositioner,
MenuContent,
MenuItem,
MenuCheckboxItem,
MenuSeparator,
MenuTriggerItem,
MenuRadioItemGroup,
MenuItemGroupLabel,
MenuRadioItem,
} from "@/components/ui/menu";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
import { ref } from "vue";
const react = ref(false);
const solid = ref(false);
const vue = ref(false);
const svelte = ref(false);
const value = ref("react");
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/menu</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/menu/MenuRoot.vue">
{{`
<script lang="ts" setup>
import * as menu from "@zag-js/menu";
import type { Props } from "@zag-js/menu";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { menuRoot } from "@mykopkb/core/styles/menu.styles";
const {
class: className,
asChild = false,
closeOnSelect = false,
open = undefined,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(menu.machine, {
...props,
open,
closeOnSelect,
id: crypto.randomUUID(),
});
const api = computed(() => menu.connect(service, normalizeProps));
provide("menuApi", api);
</script>
<template>
<Slot :class="cn(menuRoot, className)" v-bind="{ ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuTrigger.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/menu";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Button } from "@/components/ui/button";
import { Slot } from "@/components/ui/slot";
import { menuTrigger } from "@mykopkb/core/styles/menu.styles";
import { MenuIndicator } from ".";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("menuApi");
</script>
<template>
<Slot v-bind="{ ...api?.getTriggerProps(), ...props, ...$attrs }">
<Button variant="ghost" v-if="!asChild" :class="cn(menuTrigger, className)">
<slot />
<MenuIndicator />
</Button>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuIndicator.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { ChevronDown } from "@lucide/vue";
import { menuIndicator } from "@mykopkb/core/styles/menu.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/menu";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("menuApi");
</script>
<template>
<Slot :class="cn(menuIndicator, className)" v-bind="{ ...api?.getIndicatorProps(), ...props, ...$attrs }">
<slot v-if="$slots.default" />
<ChevronDown v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuPositioner.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/menu";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { menuPositioner } from "@mykopkb/core/styles/menu.styles";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("menuApi");
</script>
<template>
<Teleport to="body">
<Slot :class="cn(menuPositioner, className)" v-bind="{ ...props, ...$attrs, ...api?.getPositionerProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</Teleport>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuContent.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/menu";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Box } from "@/components/ui/box";
import { Slot } from "@/components/ui/slot";
import { menuContent } from "@mykopkb/core/styles/menu.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("menuApi");
</script>
<template>
<Slot :class="cn(menuContent, className)" v-bind="{ ...api?.getContentProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<Box v-else raised="single" :class="cn(menuContent, className)">
<div>
<slot />
</div>
</Box>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuItem.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { type Api, type ItemProps } from "@zag-js/menu";
import { inject } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { menuItem } from "@mykopkb/core/styles/menu.styles";
const {
class: className,
shortcut,
asChild = false,
...props
} = defineProps<
ItemProps & {
class?: string;
shortcut?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("menuApi");
</script>
<template>
<Slot :class="cn(menuItem, className)" v-bind="{ ...api?.getItemProps(props), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<div>
<slot />
</div>
<div>\{\{ shortcut \}\}</div>
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuTriggerItem.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/menu";
import { inject } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { ChevronRight } from "@lucide/vue";
import { Slot } from "@/components/ui/slot";
import { menuItem } from "@mykopkb/core/styles/menu.styles";
const { class: className, ...props } = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("menuApi");
</script>
<template>
<Slot :class="cn(menuItem, className)" v-bind="{ ...api?.getTriggerItemProps(api), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<div>
<slot />
</div>
<ChevronRight data-part="nested-menu-chevron" />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuCheckboxItem.vue">
{{ `
<script lang="ts" setup>
import type { Api, OptionItemProps } from "@zag-js/menu";
import { cn } from "@mykopkb/core/utils/cn";
import { Check } from "@lucide/vue";
import { menuItem } from "@mykopkb/core/styles/menu.styles";
import { inject } from "vue";
const {
shortcut,
class: className,
type = "checkbox",
...props
} = defineProps<
Omit<OptionItemProps, "type"> & {
class?: string;
shortcut?: string;
type?: OptionItemProps["type"];
}
>();
const api = inject<Api>("menuApi");
</script>
<template>
<div :class="cn(menuItem, className)" v-bind="{
...props,
...$attrs,
...api?.getOptionItemProps({
...props,
type,
}),
}">
<div>
<span data-part="item-indicator" v-bind="{ ...api?.getItemIndicatorProps(props) }">
<Check />
</span>
<slot />
</div>
<div>\{\{ shortcut \}\}</div>
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuRadioItemGroup.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { menuRadioItemGroup } from "@mykopkb/core/styles/menu.styles";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
</script>
<template>
<Slot :class="cn(menuRadioItemGroup, className)" v-bind="{
...props,
...$attrs,
}">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuItemGroupLabel.vue">
{{ `
<script lang="ts" setup>
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { menuItemGroupLabel } from "@mykopkb/core/styles/menu.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
</script>
<template>
<Slot :class="cn(menuItemGroupLabel, className)" v-bind="{ ...props, ...$attrs }">
<slot v-if="asChild" />
<label v-else>
<slot />
</label>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuRadioItem.vue">
{{ `
<script lang="ts" setup>
import type { Api, OptionItemProps } from "@zag-js/menu";
import { cn } from "@mykopkb/core/utils/cn";
import { Dot } from "@lucide/vue";
import { menuItem } from "@mykopkb/core/styles/menu.styles";
import { inject } from "vue";
const {
shortcut,
class: className,
asChild = false,
type = "radio",
...props
} = defineProps<
Omit<OptionItemProps, "type"> & {
class?: string;
asChild?: boolean;
shortcut?: string;
type?: OptionItemProps["type"];
}
>();
const api = inject<Api>("menuApi");
</script>
<template>
<div :class="cn(menuItem, className)" v-bind="{
...props,
...$attrs,
...api?.getOptionItemProps({
...props,
type,
}),
}">
<div>
<span data-part="item-indicator" v-bind="{ ...api?.getItemIndicatorProps(props) }">
<Dot />
</span>
<slot />
</div>
<div>\{\{ shortcut \}\}</div>
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/MenuSeparator.vue">
{{ `
<script lang="ts" setup>
import type { Api } from "@zag-js/menu";
import { cn } from "@mykopkb/core/utils/cn";
import { menuSeparator } from "@mykopkb/core/styles/menu.styles";
import { Slot } from "@/components/ui/slot";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("menuApi");
</script>
<template>
<Slot :class="cn(menuSeparator, className)" v-bind="{
...props,
...$attrs,
...api?.getSeparatorProps(),
}">
<slot v-if="asChild" />
<hr v-else>
<slot />
</hr>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/menu/index.ts">
{{ `
export { default as MenuRoot } from "./MenuRoot.vue";
export { default as MenuTrigger } from "./MenuTrigger.vue";
export { default as MenuIndicator } from "./MenuIndicator.vue";
export { default as MenuPositioner } from "./MenuPositioner.vue";
export { default as MenuContent } from "./MenuContent.vue";
export { default as MenuItem } from "./MenuItem.vue";
export { default as MenuTriggerItem } from "./MenuTriggerItem.vue";
export { default as MenuCheckboxItem } from "./MenuCheckboxItem.vue";
export { default as MenuRadioItemGroup } from "./MenuRadioItemGroup.vue";
export { default as MenuItemGroupLabel } from "./MenuItemGroupLabel.vue";
export { default as MenuRadioItem } from "./MenuRadioItem.vue";
export { default as MenuSeparator } from "./MenuSeparator.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
MenuRoot,
MenuTrigger,
MenuPositioner,
MenuContent,
MenuItem,
MenuCheckboxItem,
MenuSeparator,
MenuTriggerItem,
MenuRadioItemGroup,
MenuItemGroupLabel,
MenuRadioItem,
} from "@/components/ui/menu";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
<MenuSeparator />
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
<MenuSeparator />
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem shortcut="⇧⌘P" value="react">
React
</MenuItem>
<MenuItem shortcut="⌘B" value="solid">
Solid
</MenuItem>
<MenuItem shortcut="⌘S" value="vue">
Vue
</MenuItem>
<MenuItem shortcut="⌘K" value="svelte">
Svelte
</MenuItem>
<MenuSeparator />
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem shortcut="⇧⌘Q" value="svelte">
Svelte
</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem shortcut="⇧⌘P" value="react">
React
</MenuItem>
<MenuItem shortcut="⌘B" value="solid">
Solid
</MenuItem>
<MenuItem shortcut="⌘S" value="vue">
Vue
</MenuItem>
<MenuItem shortcut="⌘K" value="svelte">
Svelte
</MenuItem>
<MenuSeparator />
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem shortcut="⇧⌘Q" value="svelte">
Svelte
</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem shortcut="⇧⌘P" value="react">
React
</MenuItem>
<MenuItem shortcut="⌘B" value="solid">
Solid
</MenuItem>
<MenuItem shortcut="⌘S" value="vue">
Vue
</MenuItem>
<MenuItem shortcut="⌘K" value="svelte">
Svelte
</MenuItem>
<MenuRoot :positioning="{ placement: 'right-start', gutter: 12 }">
<MenuTriggerItem>Frameworks</MenuTriggerItem>
<MenuPositioner>
<MenuContent>
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
<MenuSeparator />
<MenuItem disabled value="react">
React
</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem shortcut="⇧⌘Q" value="svelte">
Svelte
</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuItem shortcut="⇧⌘P" value="react">
React
</MenuItem>
<MenuItem shortcut="⌘B" value="solid">
Solid
</MenuItem>
<MenuItem shortcut="⌘S" value="vue">
Vue
</MenuItem>
<MenuItem shortcut="⌘K" value="svelte">
Svelte
</MenuItem>
<MenuRoot :positioning="{ placement: 'right-start', gutter: 12 }">
<MenuTriggerItem>Frameworks</MenuTriggerItem>
<MenuPositioner>
<MenuContent>
<MenuItem value="react">React</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem value="svelte">Svelte</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
<MenuSeparator />
<MenuItem disabled value="react">
React
</MenuItem>
<MenuItem value="solid">Solid</MenuItem>
<MenuItem value="vue">Vue</MenuItem>
<MenuItem shortcut="⇧⌘Q" value="svelte">
Svelte
</MenuItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuCheckboxItem :checked="react" :onCheckedChange="(checked) => (react = checked)" value="checked">
React
</MenuCheckboxItem>
<MenuCheckboxItem :checked="solid" :onCheckedChange="(checked) => (solid = checked)" value="checked">
Solid
</MenuCheckboxItem>
<MenuCheckboxItem :checked="vue" :onCheckedChange="(checked) => (vue = checked)" value="checked">
Vue
</MenuCheckboxItem>
<MenuCheckboxItem :checked="svelte" :onCheckedChange="(checked) => (svelte = checked)" value="checked">
Svelte
</MenuCheckboxItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
</template>
<template #code>
<PreviewCode>
{{`
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuCheckboxItem :checked="react" :onCheckedChange="(checked) => (react = checked)" value="checked">
React
</MenuCheckboxItem>
<MenuCheckboxItem :checked="solid" :onCheckedChange="(checked) => (solid = checked)" value="checked">
Solid
</MenuCheckboxItem>
<MenuCheckboxItem :checked="vue" :onCheckedChange="(checked) => (vue = checked)" value="checked">
Vue
</MenuCheckboxItem>
<MenuCheckboxItem :checked="svelte" :onCheckedChange="(checked) => (svelte = checked)" value="checked">
Svelte
</MenuCheckboxItem>
</MenuContent>
</MenuPositioner>
</MenuRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuRadioItemGroup>
<MenuItemGroupLabel>Frameworks</MenuItemGroupLabel>
<MenuRadioItem v-for="framework in ['React', 'Solid', 'Vue', 'Svelte']" :key="framework"
:value="framework" :checked="framework == value" :onCheckedChange="(checked) => (checked ? (value = framework) : '')
">
{{ framework }}
</MenuRadioItem>
</MenuRadioItemGroup>
</MenuContent>
</MenuPositioner>
</MenuRoot>
</template>
<template #code>
<PreviewCode>
{{`
<MenuRoot class="w-56">
<MenuTrigger>Open menu</MenuTrigger>
<MenuPositioner>
<MenuContent>
<MenuRadioItemGroup>
<MenuItemGroupLabel>Frameworks</MenuItemGroupLabel>
<MenuRadioItem v-for="framework in ['React', 'Solid', 'Vue', 'Svelte']" :key="framework"
:value="framework" :checked="framework == value" :onCheckedChange="
(checked) => (checked ? (value = framework) : '')
">
\{\{ framework \}\}
</MenuRadioItem>
</MenuRadioItemGroup>
</MenuContent>
</MenuPositioner>
</MenuRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+210
View File
@@ -0,0 +1,210 @@
<script lang="ts" setup>
import {
NativeSelect,
NativeSelectOption,
NativeSelectOptionGroup,
} from "@/components/ui/native-select";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<NativeSelect class="w-56">
<NativeSelectOption value="">Select status</NativeSelectOption>
<NativeSelectOption value="todo">Todo</NativeSelectOption>
<NativeSelectOption value="in-progress">In Progress</NativeSelectOption>
<NativeSelectOption value="done">Done</NativeSelectOption>
<NativeSelectOption value="cancelled">Cancelled</NativeSelectOption>
</NativeSelect>
</template>
<template #code>
<PreviewCode>
{{ `
<NativeSelect class="w-56">
<NativeSelectOption value="">Select status</NativeSelectOption>
<NativeSelectOption value="todo">Todo</NativeSelectOption>
<NativeSelectOption value="in-progress">In Progress</NativeSelectOption>
<NativeSelectOption value="done">Done</NativeSelectOption>
<NativeSelectOption value="cancelled">Cancelled</NativeSelectOption>
</NativeSelect>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/native-select/NativeSelect.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { input } from "@mykopkb/core/styles/input.styles";
import { nativeSelect } from "@mykopkb/core/styles/native-select.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<select :class="cn(input, nativeSelect, className)" v-bind="{ ...props, ...$attrs }">
<slot />
</select>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/native-select/NativeSelectOption.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { nativeSelectOption } from "@mykopkb/core/styles/native-select.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<option :class="cn(nativeSelectOption, className)" v-bind="{ ...props, ...$attrs }">
<slot />
</option>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/native-select/NativeSelectOptionGroup.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { NativeSelectOptGroup } from "@mykopkb/core/styles/native-select.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<optgroup :class="cn(NativeSelectOptGroup, className)" v-bind="{ ...props, ...$attrs }">
<slot />
</optgroup>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/native-select/index.ts">
{{ `
export { default as NativeSelect } from "./NativeSelect.vue";
export { default as NativeSelectOption } from "./NativeSelectOption.vue";
export { default as NativeSelectOptionGroup } from "./NativeSelectOptionGroup.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
NativeSelect,
NativeSelectOption,
NativeSelectOptionGroup,
} from "@/components/ui/native-select";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<NativeSelect class="w-56">
<NativeSelectOption value="">Select status</NativeSelectOption>
<NativeSelectOption value="todo">Todo</NativeSelectOption>
<NativeSelectOption value="in-progress">In Progress</NativeSelectOption>
<NativeSelectOption value="done">Done</NativeSelectOption>
<NativeSelectOption value="cancelled">Cancelled</NativeSelectOption>
</NativeSelect>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<NativeSelect class="w-56">
<NativeSelectOption value="">Select department</NativeSelectOption>
<NativeSelectOptionGroup label="Engineering">
<NativeSelectOption value="frontend">Frontend</NativeSelectOption>
<NativeSelectOption value="backend">Backend</NativeSelectOption>
<NativeSelectOption value="devops">DevOps</NativeSelectOption>
</NativeSelectOptionGroup>
<NativeSelectOptionGroup label="Sales">
<NativeSelectOption value="sales-rep">Sales Rep</NativeSelectOption>
<NativeSelectOption value="account-manager">Account Manager</NativeSelectOption>
<NativeSelectOption value="sales-director">Sales Director</NativeSelectOption>
</NativeSelectOptionGroup>
<NativeSelectOptionGroup label="Operations">
<NativeSelectOption value="support">Customer Support</NativeSelectOption>
<NativeSelectOption value="product-manager">Product Manager</NativeSelectOption>
<NativeSelectOption value="ops-manager">Operations Manager</NativeSelectOption>
</NativeSelectOptionGroup>
</NativeSelect>
</template>
<template #code>
<PreviewCode>
{{ `
<NativeSelect class="w-56">
<NativeSelectOption value="">Select department</NativeSelectOption>
<NativeSelectOptionGroup label="Engineering">
<NativeSelectOption value="frontend">Frontend</NativeSelectOption>
<NativeSelectOption value="backend">Backend</NativeSelectOption>
<NativeSelectOption value="devops">DevOps</NativeSelectOption>
</NativeSelectOptionGroup>
<NativeSelectOptionGroup label="Sales">
<NativeSelectOption value="sales-rep">Sales Rep</NativeSelectOption>
<NativeSelectOption value="account-manager">Account Manager</NativeSelectOption>
<NativeSelectOption value="sales-director">Sales Director</NativeSelectOption>
</NativeSelectOptionGroup>
<NativeSelectOptionGroup label="Operations">
<NativeSelectOption value="support">Customer Support</NativeSelectOption>
<NativeSelectOption value="product-manager">Product Manager</NativeSelectOption>
<NativeSelectOption value="ops-manager">Operations Manager</NativeSelectOption>
</NativeSelectOptionGroup>
</NativeSelect>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<NativeSelect class="w-56" disabled>
<NativeSelectOption value="">Select status</NativeSelectOption>
<NativeSelectOption value="todo">Todo</NativeSelectOption>
<NativeSelectOption value="in-progress">In Progress</NativeSelectOption>
<NativeSelectOption value="done">Done</NativeSelectOption>
<NativeSelectOption value="cancelled">Cancelled</NativeSelectOption>
</NativeSelect>
</template>
<template #code>
<PreviewCode>
{{ `
<NativeSelect class="w-56" disabled>
<NativeSelectOption value="">Select status</NativeSelectOption>
<NativeSelectOption value="todo">Todo</NativeSelectOption>
<NativeSelectOption value="in-progress">In Progress</NativeSelectOption>
<NativeSelectOption value="done">Done</NativeSelectOption>
<NativeSelectOption value="cancelled">Cancelled</NativeSelectOption>
</NativeSelect>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+298
View File
@@ -0,0 +1,298 @@
<script lang="ts" setup>
import {
PaginationContext,
PaginationRoot,
PaginationItem,
PaginationPrevTrigger,
PaginationNextTrigger,
PaginationEllipsis,
} from "@/components/ui/pagination";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<PaginationRoot :count="5000" :pageSize="10" :siblingCount="2">
<PaginationPrevTrigger>Previous</PaginationPrevTrigger>
<PaginationContext v-slot="{ pagination }">
<template v-for="(page, index) in pagination?.pages" :key="index">
<PaginationItem v-if="page.type === 'page'" v-bind="{ ...page }">
{{ page.value }}
</PaginationItem>
<PaginationEllipsis v-else :index="index" />
</template>
</PaginationContext>
<PaginationNextTrigger>Next</PaginationNextTrigger>
</PaginationRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<PaginationRoot :count="5000" :pageSize="10" :siblingCount="2">
<PaginationPrevTrigger>Previous</PaginationPrevTrigger>
<PaginationContext v-slot="{ pagination }">
<template v-for="(page, index) in pagination?.pages" :key="index">
<PaginationItem v-if="page.type === 'page'" v-bind="{ ...page }">
\{\{ page.value \}\}
</PaginationItem>
<PaginationEllipsis v-else :index="index" />
</template>
</PaginationContext>
<PaginationNextTrigger>Next</PaginationNextTrigger>
</PaginationRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/pagination</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/pagination/PaginationContext.vue">
{{ `
<script setup lang="ts">
import type { Api } from "@zag-js/pagination";
import { inject } from "vue";
const api = inject<Api>("paginationApi");
</script>
<template>
<slot :pagination="api"></slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/pagination/PaginationEllipsis.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { paginationEllipsis } from "@mykopkb/core/styles/pagination.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, EllipsisProps } from "@zag-js/pagination";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<
EllipsisProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("paginationApi");
</script>
<template>
<Slot :class="cn(paginationEllipsis, className)"
v-bind="{ ...api?.getEllipsisProps(props), ...props, ...$attrs }">
<div v-if="!$slots.default">…</div>
<template v-else>
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</template>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/pagination/PaginationItem.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { paginationItem } from "@mykopkb/core/styles/pagination.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/pagination";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<
ItemProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("paginationApi");
</script>
<template>
<Slot :class="cn(paginationItem, className)" v-bind="{ ...api?.getItemProps(props), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/pagination/PaginationNextTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { paginationNextTrigger } from "@mykopkb/core/styles/pagination.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/pagination";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("paginationApi");
</script>
<template>
<Slot :class="cn(paginationNextTrigger, className)"
v-bind="{ ...api?.getNextTriggerProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/pagination/PaginationPrevTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { paginationPrevTrigger } from "@mykopkb/core/styles/pagination.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/pagination";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("paginationApi");
</script>
<template>
<Slot :class="cn(paginationPrevTrigger, className)"
v-bind="{ ...api?.getPrevTriggerProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/pagination/PaginationRoot.vue">
{{`
<script lang="ts" setup>
import * as pagination from "@zag-js/pagination";
import type { Props } from "@zag-js/pagination";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { paginationRoot } from "@mykopkb/core/styles/pagination.styles";
const {
class: className,
asChild = false,
count,
pageSize,
siblingCount,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(pagination.machine, {
...props,
count,
pageSize,
siblingCount,
id: crypto.randomUUID(),
});
const api = computed(() => pagination.connect(service, normalizeProps));
provide("paginationApi", api);
</script>
<template>
<Slot :class="cn(paginationRoot, className)" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/pagination/index.ts">
{{ `
export { default as PaginationContext } from "./PaginationContext.vue";
export { default as PaginationEllipsis } from "./PaginationEllipsis.vue";
export { default as PaginationItem } from "./PaginationItem.vue";
export { default as PaginationNextTrigger } from "./PaginationNextTrigger.vue";
export { default as PaginationPrevTrigger } from "./PaginationPrevTrigger.vue";
export { default as PaginationRoot } from "./PaginationRoot.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
PaginationContext,
PaginationRoot,
PaginationItem,
PaginationPrevTrigger,
PaginationNextTrigger,
PaginationEllipsis,
} from "@/components/ui/pagination";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<PaginationRoot :count="5000" :pageSize="10" :siblingCount="2">
<PaginationPrevTrigger>Previous</PaginationPrevTrigger>
<PaginationContext v-slot="{ pagination }">
<template v-for="(page, index) in pagination?.pages" :key="index">
<PaginationItem v-if="page.type === 'page'" v-bind="{ ...page }">
\{\{ page.value \}\}
</PaginationItem>
<PaginationEllipsis v-else :index="index" />
</template>
</PaginationContext>
<PaginationNextTrigger>Next</PaginationNextTrigger>
</PaginationRoot>
` }}
</PreviewCode>
</div>
</template>
+447
View File
@@ -0,0 +1,447 @@
<script lang="ts" setup>
import {
PopoverRoot,
PopoverTrigger,
PopoverPositioner,
PopoverContent,
PopoverTitle,
PopoverDescription,
} from "@/components/ui/popover";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<PopoverRoot>
<PopoverTrigger class="w-56">Open Popover</PopoverTrigger>
<PopoverPositioner>
<PopoverContent class="w-100">
<PopoverTitle>Dimensions</PopoverTitle>
<PopoverDescription>
Set the dimensions for the layer.
</PopoverDescription>
<div class="grid gap-3 mt-4 mb-2">
<div class="grid grid-cols-3 items-center gap-4">
<Label for="width">Width</Label>
<Input id="width" defaultValue="100%" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="maxWidth">Max. width</Label>
<Input id="maxWidth" defaultValue="300px" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="height">Height</Label>
<Input id="height" defaultValue="25px" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="maxHeight">Max. height</Label>
<Input id="maxHeight" defaultValue="none" class="col-span-2" />
</div>
</div>
</PopoverContent>
</PopoverPositioner>
</PopoverRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<PopoverRoot>
<PopoverTrigger class="w-56">Open Popover</PopoverTrigger>
<PopoverPositioner>
<PopoverContent class="w-100">
<PopoverTitle>Dimensions</PopoverTitle>
<PopoverDescription>
Set the dimensions for the layer.
</PopoverDescription>
<div class="grid gap-3 mt-4 mb-2">
<div class="grid grid-cols-3 items-center gap-4">
<Label for="width">Width</Label>
<Input id="width" defaultValue="100%" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="maxWidth">Max. width</Label>
<Input id="maxWidth" defaultValue="300px" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="height">Height</Label>
<Input id="height" defaultValue="25px" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="maxHeight">Max. height</Label>
<Input id="maxHeight" defaultValue="none" class="col-span-2" />
</div>
</div>
</PopoverContent>
</PopoverPositioner>
</PopoverRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/popover</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/popover/PopoverArrow.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { popoverArrow } from "@mykopkb/core/styles/popover.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<div :class="cn(popoverArrow, className)" v-bind="{ ...api?.getArrowProps(), ...props, ...$attrs }">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverArrowTip.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { popoverArrowTip } from "@mykopkb/core/styles/popover.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<div :class="cn(popoverArrowTip, className)" v-bind="{ ...api?.getArrowTipProps(), ...props, ...$attrs }">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverContent.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
import { popoverContent } from "@mykopkb/core/styles/popover.styles";
import { PopoverArrow, PopoverArrowTip } from ".";
import { Box } from "@/components/ui/box";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<Slot :class="cn(popoverContent, className)" v-bind="{ ...api?.getContentProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<Box v-else raised="single" :class="cn(popoverContent, className)">
<div>
<slot />
</div>
<PopoverArrow>
<PopoverArrowTip />
</PopoverArrow>
</Box>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverDescription.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { popoverDescription } from "@mykopkb/core/styles/popover.styles";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<Slot :class="cn(popoverDescription, className)"
v-bind="{ ...api?.getDescriptionProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverIndicator.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
import { popoverIndicator } from "@mykopkb/core/styles/popover.styles";
import { ChevronDown } from "@lucide/vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<Slot :class="cn(popoverIndicator, className)" v-bind="{ ...api?.getIndicatorProps(), ...props, ...$attrs }">
<slot v-if="$slots.default" />
<ChevronDown v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverPositioner.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { popoverPositioner } from "@mykopkb/core/styles/popover.styles";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<Teleport to="body">
<Slot :class="cn(popoverPositioner, className)"
v-bind="{ ...api?.getPositionerProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</Teleport>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverRoot.vue">
{{`
<script lang="ts" setup>
import * as popover from "@zag-js/popover";
import type { Props } from "@zag-js/popover";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { popoverRoot } from "@mykopkb/core/styles/popover.styles";
const {
class: className,
asChild = false,
open = undefined,
closeOnInteractOutside = undefined,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(popover.machine, {
...props,
open,
closeOnInteractOutside,
id: crypto.randomUUID(),
});
const api = computed(() => popover.connect(service, normalizeProps));
provide("popoverApi", api);
</script>
<template>
<Slot :class="cn(popoverRoot, className)" v-bind="{ ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverTitle.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
import { popoverTitle } from "@mykopkb/core/styles/popover.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<Slot :class="cn(popoverTitle, className)" v-bind="{ ...api?.getTitleProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/PopoverTrigger.vue">
{{ `
<script lang="ts" setup>
import { type Api } from "@zag-js/popover";
import { cn } from "@mykopkb/core/utils/cn";
import { inject } from "vue";
import { Button } from "@/components/ui/button";
import { Slot } from "@/components/ui/slot";
import { popoverTrigger } from "@mykopkb/core/styles/popover.styles";
import { PopoverIndicator } from ".";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("popoverApi");
</script>
<template>
<Slot v-bind="{ ...api?.getTriggerProps(), ...props, ...$attrs }">
<Button variant="ghost" v-if="!asChild" :class="cn(popoverTrigger, className)">
<slot />
<PopoverIndicator />
</Button>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/popover/index.ts">
{{ `
export { default as PopoverArrow } from "./PopoverArrow.vue";
export { default as PopoverArrowTip } from "./PopoverArrowTip.vue";
export { default as PopoverContent } from "./PopoverContent.vue";
export { default as PopoverDescription } from "./PopoverDescription.vue";
export { default as PopoverIndicator } from "./PopoverIndicator.vue";
export { default as PopoverPositioner } from "./PopoverPositioner.vue";
export { default as PopoverRoot } from "./PopoverRoot.vue";
export { default as PopoverTitle } from "./PopoverTitle.vue";
export { default as PopoverTrigger } from "./PopoverTrigger.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
PopoverRoot,
PopoverTrigger,
PopoverPositioner,
PopoverContent,
PopoverTitle,
PopoverDescription,
} from "@/components/ui/popover";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<PopoverRoot>
<PopoverTrigger class="w-56"> Open Popover </PopoverTrigger>
<PopoverPositioner>
<PopoverContent class="w-100">
<PopoverTitle>Dimensions</PopoverTitle>
<PopoverDescription>
Set the dimensions for the layer.
</PopoverDescription>
<div class="grid gap-3 mt-4 mb-2">
<div class="grid grid-cols-3 items-center gap-4">
<Label for="width">Width</Label>
<Input id="width" defaultValue="100%" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="maxWidth">Max. width</Label>
<Input id="maxWidth" defaultValue="300px" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="height">Height</Label>
<Input id="height" defaultValue="25px" class="col-span-2" />
</div>
<div class="grid grid-cols-3 items-center gap-4">
<Label for="maxHeight">Max. height</Label>
<Input id="maxHeight" defaultValue="none" class="col-span-2" />
</div>
</div>
</PopoverContent>
</PopoverPositioner>
</PopoverRoot>
` }}
</PreviewCode>
</div>
</template>
+255
View File
@@ -0,0 +1,255 @@
<script lang="ts" setup>
import {
ProgressRoot,
ProgressLabel,
ProgressValueText,
ProgressCircle,
ProgressCircleTrack,
ProgressCircleRange,
} from "@/components/ui/progress-circular";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<ProgressRoot :defaultValue="42">
<ProgressLabel>Progress Circular</ProgressLabel>
<ProgressCircle class="max-w-48">
<ProgressCircleTrack />
<ProgressCircleRange />
</ProgressCircle>
<ProgressValueText />
</ProgressRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<ProgressRoot :defaultValue="42">
<ProgressLabel>Progress Circular</ProgressLabel>
<ProgressCircle class="max-w-48">
<ProgressCircleTrack />
<ProgressCircleRange />
</ProgressCircle>
<ProgressValueText />
</ProgressRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/progress</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/progress-circular/ProgressCircle.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressCircle } from "@mykopkb/core/styles/progress-circular.styles";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<svg :class="cn(progressCircle, className)" v-bind="{ ...api?.getCircleProps(), ...props, ...$attrs }">
<slot />
</svg>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-circular/ProgressCircleRange.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressCircleRange } from "@mykopkb/core/styles/progress-circular.styles";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<circle :class="cn(progressCircleRange, className)"
v-bind="{ ...api?.getCircleRangeProps(), ...props, ...$attrs }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-circular/ProgressCircleTrack.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressCircleTrack } from "@mykopkb/core/styles/progress-circular.styles";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<circle :class="cn(progressCircleTrack, className)"
v-bind="{ ...api?.getCircleTrackProps(), ...props, ...$attrs }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-circular/ProgressLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressLabel } from "@mykopkb/core/styles/progress-circular.styles";
import { Label } from "@/components/ui/label";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<Slot v-bind="{ ...api?.getLabelProps(), ...props, ...$attrs }">
<Label v-if="!asChild" :class="cn(progressLabel, className)">
<slot />
</Label>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-circular/ProgressRoot.vue">
{{`
<script lang="ts" setup>
import * as progress from "@zag-js/progress";
import type { Props } from "@zag-js/progress";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { progressRoot } from "@mykopkb/core/styles/progress-circular.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(progress.machine, {
...props,
id: crypto.randomUUID(),
});
const api = computed(() => progress.connect(service, normalizeProps));
provide("progressApi", api);
</script>
<template>
<Slot :class="cn(progressRoot, className)" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-circular/ProgressValueText.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressValueText } from "@mykopkb/core/styles/progress-circular.styles";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<div :class="cn(progressValueText, className)" v-bind="{ ...api?.getValueTextProps(), ...props, ...$attrs }">
\{\{ api?.valueAsString \}\}
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-circular/index.ts">
{{ `
export { default as ProgressCircle } from "./ProgressCircle.vue";
export { default as ProgressCircleRange } from "./ProgressCircleRange.vue";
export { default as ProgressCircleTrack } from "./ProgressCircleTrack.vue";
export { default as ProgressLabel } from "./ProgressLabel.vue";
export { default as ProgressRoot } from "./ProgressRoot.vue";
export { default as ProgressValueText } from "./ProgressValueText.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
ProgressRoot,
ProgressLabel,
ProgressValueText,
ProgressCircle,
ProgressCircleTrack,
ProgressCircleRange,
} from "@/components/ui/progress-circular";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<ProgressRoot :defaultValue="42">
<ProgressLabel>Progress Circular</ProgressLabel>
<ProgressCircle class="max-w-48">
<ProgressCircleTrack />
<ProgressCircleRange />
</ProgressCircle>
<ProgressValueText />
</ProgressRoot>
` }}
</PreviewCode>
</div>
</template>
+227
View File
@@ -0,0 +1,227 @@
<script lang="ts" setup>
import {
ProgressRoot,
ProgressLabel,
ProgressValueText,
ProgressTrack,
ProgressRange,
} from "@/components/ui/progress-linear";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<ProgressRoot :defaultValue="42">
<ProgressLabel>Progress Linear</ProgressLabel>
<ProgressTrack class="max-w-72">
<ProgressRange />
</ProgressTrack>
<ProgressValueText />
</ProgressRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<ProgressRoot :defaultValue="42">
<ProgressLabel>Progress Linear</ProgressLabel>
<ProgressTrack class="max-w-72">
<ProgressRange />
</ProgressTrack>
<ProgressValueText />
</ProgressRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/progress</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/progress-linear/ProgressLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressLabel } from "@mykopkb/core/styles/progress-linear.styles";
import { Label } from "@/components/ui/label";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<Slot v-bind="{ ...api?.getLabelProps(), ...props, ...$attrs }">
<Label v-if="!asChild" :class="cn(progressLabel, className)">
<slot />
</Label>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-linear/ProgressRange.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressRange } from "@mykopkb/core/styles/progress-linear.styles";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<div :class="cn(progressRange, className)" v-bind="{ ...api?.getRangeProps(), ...props, ...$attrs }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-linear/ProgressRoot.vue">
{{`
<script lang="ts" setup>
import * as progress from "@zag-js/progress";
import type { Props } from "@zag-js/progress";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { progressRoot } from "@mykopkb/core/styles/progress-linear.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(progress.machine, {
...props,
id: crypto.randomUUID(),
});
const api = computed(() => progress.connect(service, normalizeProps));
provide("progressApi", api);
</script>
<template>
<Slot :class="cn(progressRoot, className)" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-linear/ProgressTrack.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressTrack } from "@mykopkb/core/styles/progress-linear.styles";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<div :class="cn(progressTrack, className)" v-bind="{ ...api?.getTrackProps(), ...props, ...$attrs }">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-linear/ProgressValueText.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { progressValueText } from "@mykopkb/core/styles/progress-linear.styles";
import type { Api } from "@zag-js/progress";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("progressApi");
</script>
<template>
<div :class="cn(progressValueText, className)" v-bind="{ ...api?.getValueTextProps(), ...props, ...$attrs }">
\{\{ api?.valueAsString \}\}
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/progress-linear/index.ts">
{{ `
export { default as ProgressLabel } from "./ProgressLabel.vue";
export { default as ProgressRange } from "./ProgressRange.vue";
export { default as ProgressRoot } from "./ProgressRoot.vue";
export { default as ProgressTrack } from "./ProgressTrack.vue";
export { default as ProgressValueText } from "./ProgressValueText.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
ProgressRoot,
ProgressLabel,
ProgressValueText,
ProgressTrack,
ProgressRange,
} from "@/components/ui/progress-linear";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<ProgressRoot :defaultValue="42">
<ProgressLabel>Progress Linear</ProgressLabel>
<ProgressTrack class="max-w-72">
<ProgressRange />
</ProgressTrack>
<ProgressValueText />
</ProgressRoot>
` }}
</PreviewCode>
</div>
</template>
+325
View File
@@ -0,0 +1,325 @@
<script lang="ts" setup>
import {
RadioGroupRoot,
RadioGroupLabel,
RadioGroupItem,
RadioGroupItemText,
RadioGroupItemControl,
} from "@/components/ui/radio-group";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
const frameworks = ["React", "Solid", "Vue", "Svelte"];
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<RadioGroupRoot defaultValue="React">
<RadioGroupLabel>Framework</RadioGroupLabel>
<RadioGroupItem v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroupItemControl />
<RadioGroupItemText>{{ framework }}</RadioGroupItemText>
</RadioGroupItem>
</RadioGroupRoot>
</template>
<template #code>
<PreviewCode>
{{ `
const frameworks = ["React", "Solid", "Vue", "Svelte"];
<RadioGroupRoot defaultValue="React">
<RadioGroupLabel>Framework</RadioGroupLabel>
<RadioGroupItem v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroupItemControl />
<RadioGroupItemText>\{\{ framework \}\}</RadioGroupItemText>
</RadioGroupItem>
</RadioGroupRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/radio-group</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/radio-group/RadioGroupRoot.vue">
{{`
<script lang="ts" setup>
import * as radioGroup from "@zag-js/radio-group";
import type { Props } from "@zag-js/radio-group";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { radioGroupRoot } from "@mykopkb/core/styles/radio-group.styles";
import { Dot } from "@lucide/vue";
import { RadioGroupIndicator } from ".";
const {
class: className,
asChild = false,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(radioGroup.machine, {
...props,
id: crypto.randomUUID(),
});
const api = computed(() => radioGroup.connect(service, normalizeProps));
provide("radioGroupApi", api);
</script>
<template>
<Slot :class="cn(radioGroupRoot, className)" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
<RadioGroupIndicator>
<Dot />
</RadioGroupIndicator>
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/radio-group/RadioGroupLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { radioGroupLabel } from "@mykopkb/core/styles/radio-group.styles";
import { label } from "@mykopkb/core/styles/label.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/radio-group";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("radioGroupApi");
</script>
<template>
<Slot :class="cn([label, radioGroupLabel, className])"
v-bind="{ ...api?.getLabelProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<span v-else>
<slot />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/radio-group/RadioGroupIndicator.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { radioGroupIndicator } from "@mykopkb/core/styles/radio-group.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/radio-group";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("radioGroupApi");
</script>
<template>
<Slot :class="cn(radioGroupIndicator, className)" v-bind="{ ...api?.getIndicatorProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/radio-group/RadioGroupItem.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { radioGroupItem } from "@mykopkb/core/styles/radio-group.styles";
import { Slot } from "@/components/ui/slot";
import { RadioGroupItemHiddenInput } from ".";
import type { Api, ItemProps } from "@zag-js/radio-group";
import { provide, inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<
ItemProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("radioGroupApi");
provide("radioGroupItem", props);
</script>
<template>
<Slot :class="cn(radioGroupItem, className)" v-bind="{ ...api?.getItemProps(props), ...props, ...$attrs }">
<slot v-if="asChild" />
<label v-else>
<slot />
<RadioGroupItemHiddenInput />
</label>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/radio-group/RadioGroupItemText.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { radioGroupItemText } from "@mykopkb/core/styles/radio-group.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/radio-group";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("radioGroupApi");
const itemProps = inject<ItemProps>("radioGroupItem");
</script>
<template>
<Slot :class="cn(radioGroupItemText, className)"
v-bind="{ ...api?.getItemTextProps(itemProps!), ...props, ...$attrs }">
<slot v-if="asChild" />
<span v-else>
<slot />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/radio-group/RadioGroupItemControl.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { radioGroupItemControl } from "@mykopkb/core/styles/radio-group.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/radio-group";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("radioGroupApi");
const itemProps = inject<ItemProps>("radioGroupItem");
</script>
<template>
<Slot :class="cn(radioGroupItemControl, className)"
v-bind="{ ...api?.getItemControlProps(itemProps!), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/radio-group/RadioGroupItemHiddenInput.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { radioGroupItemHiddenInput } from "@mykopkb/core/styles/radio-group.styles";
import type { Api, ItemProps } from "@zag-js/radio-group";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("radioGroupApi");
const itemProps = inject<ItemProps>("radioGroupItem");
</script>
<template>
<input :class="cn(radioGroupItemHiddenInput, className)"
v-bind="{ ...api?.getItemHiddenInputProps(itemProps!), ...props, ...$attrs }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/radio-group/index.ts">
{{ `
export { default as RadioGroupRoot } from "./RadioGroupRoot.vue";
export { default as RadioGroupLabel } from "./RadioGroupLabel.vue";
export { default as RadioGroupIndicator } from "./RadioGroupIndicator.vue";
export { default as RadioGroupItem } from "./RadioGroupItem.vue";
export { default as RadioGroupItemText } from "./RadioGroupItemText.vue";
export { default as RadioGroupItemControl } from "./RadioGroupItemControl.vue";
export { default as RadioGroupItemHiddenInput } from "./RadioGroupItemHiddenInput.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
RadioGroupRoot,
RadioGroupLabel,
RadioGroupItem,
RadioGroupItemText,
RadioGroupItemControl,
} from "@/components/ui/radio-group";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<RadioGroupRoot defaultValue="React">
<RadioGroupLabel>Framework</RadioGroupLabel>
<RadioGroupItem v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroupItemControl />
<RadioGroupItemText>\{\{ framework \}\}</RadioGroupItemText>
</RadioGroupItem>
</RadioGroupRoot>
` }}
</PreviewCode>
</div>
</template>
+259
View File
@@ -0,0 +1,259 @@
<script lang="ts" setup>
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
import {
ScrollAreaRoot,
ScrollAreaViewport,
ScrollAreaContent,
ScrollAreaScrollbar,
ScrollAreaThumb,
ScrollAreaCorner,
} from "@/components/ui/scroll-area";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<ScrollAreaRoot class="h-72 w-70">
<ScrollAreaViewport>
<ScrollAreaContent>
<div class="text-base font-medium mb-4">Scroll Area Example</div>
<div v-for="i in 20" :key="i" class="mb-4 last:mb-0 opacity-80">
This is line number {{ i }} of the scrollable content. It helps
demonstrate how the custom scrollbar works within the Midone UI
system.
</div>
</ScrollAreaContent>
</ScrollAreaViewport>
<ScrollAreaScrollbar>
<ScrollAreaThumb />
</ScrollAreaScrollbar>
<ScrollAreaCorner />
</ScrollAreaRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<script setup lang="ts">
import {
ScrollAreaRoot,
ScrollAreaViewport,
ScrollAreaContent,
ScrollAreaScrollbar,
ScrollAreaThumb,
ScrollAreaCorner,
} from "@/components/ui/scroll-area";
</script>
<template>
<ScrollAreaRoot class="h-72 w-70">
<ScrollAreaViewport>
<ScrollAreaContent>
<div class="text-base font-medium mb-4">Scroll Area Example</div>
<div v-for="i in 20" :key="i" class="mb-4 last:mb-0 opacity-80">
This is line number \{\{ i \}\} of the scrollable content. It helps
demonstrate how the custom scrollbar works within the Midone UI
system.
</div>
</ScrollAreaContent>
</ScrollAreaViewport>
<ScrollAreaScrollbar>
<ScrollAreaThumb />
</ScrollAreaScrollbar>
<ScrollAreaCorner />
</ScrollAreaRoot>
</template>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/scroll-area</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/scroll-area/ScrollAreaRoot.vue">
{{`
<script lang="ts" setup>
import * as scrollArea from "@zag-js/scroll-area";
import type { Props } from "@zag-js/scroll-area";
import { useMachine, normalizeProps } from "@zag-js/vue";
import { cn } from "@mykopkb/core/utils/cn";
import { computed, provide } from "vue";
import { scrollAreaRoot } from "@mykopkb/core/styles/scroll-area.styles";
const { class: className, ...props } = defineProps<
Partial<Props> & {
class?: string;
}
>();
const service = useMachine(scrollArea.machine, {
...props,
id: crypto.randomUUID(),
});
const api = computed(() => scrollArea.connect(service, normalizeProps));
provide("scrollAreaApi", api);
</script>
<template>
<div v-bind="{ ...api.getRootProps() }" :class="cn(scrollAreaRoot, className)">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/scroll-area/ScrollAreaViewport.vue">
{{ `
<script lang="ts" setup>
import type { Api } from "@zag-js/scroll-area";
import { inject } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { scrollAreaViewport } from "@mykopkb/core/styles/scroll-area.styles";
const { class: className, ...props } = defineProps<{ class?: string }>();
const api = inject<Api<any>>("scrollAreaApi");
</script>
<template>
<div v-bind="{ ...api?.getViewportProps(), ...props }" :class="cn(scrollAreaViewport, className)">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/scroll-area/ScrollAreaContent.vue">
{{ `
<script lang="ts" setup>
import type { Api } from "@zag-js/scroll-area";
import { inject } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { scrollAreaContent } from "@mykopkb/core/styles/scroll-area.styles";
const { class: className, ...props } = defineProps<{ class?: string }>();
const api = inject<Api<any>>("scrollAreaApi");
</script>
<template>
<div v-bind="{ ...api?.getContentProps(), ...props }" :class="cn(scrollAreaContent, className)">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/scroll-area/ScrollAreaScrollbar.vue">
{{ `
<script lang="ts" setup>
import type { Api, ScrollbarProps } from "@zag-js/scroll-area";
import { inject } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { scrollAreaScrollbar } from "@mykopkb/core/styles/scroll-area.styles";
const { class: className, ...props } = defineProps<
ScrollbarProps & { class?: string }
>();
const api = inject<Api<any>>("scrollAreaApi");
</script>
<template>
<div v-bind="{ ...api?.getScrollbarProps(), ...props }" :class="cn(scrollAreaScrollbar, className)">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/scroll-area/ScrollAreaThumb.vue">
{{ `
<script lang="ts" setup>
import type { Api, ScrollbarProps } from "@zag-js/scroll-area";
import { inject } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { scrollAreaThumb } from "@mykopkb/core/styles/scroll-area.styles";
const { class: className, ...props } = defineProps<
ScrollbarProps & { class?: string }
>();
const api = inject<Api<any>>("scrollAreaApi");
</script>
<template>
<div v-bind="{ ...api?.getThumbProps(props), ...props }" :class="cn(scrollAreaThumb, className)" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/scroll-area/ScrollAreaCorner.vue">
{{ `
<script lang="ts" setup>
import type { Api } from "@zag-js/scroll-area";
import { inject } from "vue";
import { cn } from "@mykopkb/core/utils/cn";
import { scrollAreaCorner } from "@mykopkb/core/styles/scroll-area.styles";
const { class: className, ...props } = defineProps<{ class?: string }>();
const api = inject<Api<any>>("scrollAreaApi");
</script>
<template>
<div v-bind="{ ...api?.getCornerProps(), ...props }" :class="cn(scrollAreaCorner, className)" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/scroll-area/index.ts">
{{ `
export { default as ScrollAreaRoot } from "./ScrollAreaRoot.vue";
export { default as ScrollAreaViewport } from "./ScrollAreaViewport.vue";
export { default as ScrollAreaContent } from "./ScrollAreaContent.vue";
export { default as ScrollAreaScrollbar } from "./ScrollAreaScrollbar.vue";
export { default as ScrollAreaThumb } from "./ScrollAreaThumb.vue";
export { default as ScrollAreaCorner } from "./ScrollAreaCorner.vue";
` }}
</PreviewCode>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
ScrollAreaRoot,
ScrollAreaViewport,
ScrollAreaContent,
ScrollAreaScrollbar,
ScrollAreaThumb,
ScrollAreaCorner,
} from "@/components/ui/scroll-area";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<ScrollAreaRoot class="h-72 w-70">
<ScrollAreaViewport>
<ScrollAreaContent>
<!-- Scrollable content here -->
</ScrollAreaContent>
</ScrollAreaViewport>
<ScrollAreaScrollbar>
<ScrollAreaThumb />
</ScrollAreaScrollbar>
<ScrollAreaCorner />
</ScrollAreaRoot>
` }}
</PreviewCode>
</div>
</template>
+886
View File
@@ -0,0 +1,886 @@
<script lang="ts" setup>
import {
SelectRoot,
SelectLabel,
SelectControl,
SelectTrigger,
SelectValueText,
SelectContent,
SelectItemGroup,
SelectItemGroupLabel,
SelectItem,
SelectItemText,
} from "@/components/ui/select";
import * as select from "@zag-js/select";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
const comboboxData = [
{ label: "React", code: "react" },
{ label: "Solid", code: "solid" },
{ label: "Vue", code: "vue" },
{ label: "Svelte", code: "svelte" },
];
const timezoneData = [
{
label: "North America",
items: [
{ value: "est", label: "Eastern Standard Time (EST)" },
{ value: "cst", label: "Central Standard Time (CST)" },
{ value: "mst", label: "Mountain Standard Time (MST)" },
{ value: "pst", label: "Pacific Standard Time (PST)" },
{ value: "akst", label: "Alaska Standard Time (AKST)" },
{ value: "hst", label: "Hawaii Standard Time (HST)" },
],
},
{
label: "Europe & Africa",
items: [
{ value: "gmt", label: "Greenwich Mean Time (GMT)" },
{ value: "cet", label: "Central European Time (CET)" },
{ value: "eet", label: "Eastern European Time (EET)" },
{ value: "west", label: "Western European Summer Time (WEST)" },
{ value: "cat", label: "Central Africa Time (CAT)" },
{ value: "eat", label: "East Africa Time (EAT)" },
],
},
{
label: "Asia",
items: [
{ value: "msk", label: "Moscow Time (MSK)" },
{ value: "ist", label: "India Standard Time (IST)" },
{ value: "cst_china", label: "China Standard Time (CST)" },
{ value: "jst", label: "Japan Standard Time (JST)" },
{ value: "kst", label: "Korea Standard Time (KST)" },
{
value: "ist_indonesia",
label: "Indonesia Central Standard Time (WITA)",
},
],
},
{
label: "Australia & Pacific",
items: [
{ value: "awst", label: "Australian Western Standard Time (AWST)" },
{ value: "acst", label: "Australian Central Standard Time (ACST)" },
{ value: "aest", label: "Australian Eastern Standard Time (AEST)" },
{ value: "nzst", label: "New Zealand Standard Time (NZST)" },
{ value: "fjt", label: "Fiji Time (FJT)" },
],
},
{
label: "South America",
items: [
{ value: "art", label: "Argentina Time (ART)" },
{ value: "bot", label: "Bolivia Time (BOT)" },
{ value: "brt", label: "Brasilia Time (BRT)" },
{ value: "clt", label: "Chile Standard Time (CLT)" },
],
},
];
const collection = select.collection({
items: comboboxData,
itemToValue: (item) => item.label,
});
const collectionTimezone = select.collection({
items: timezoneData.flatMap((region) =>
region.items.map((item) => ({
region: region.label,
value: item.value,
label: item.label,
}))
),
});
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<SelectRoot class="w-56" :collection="collection">
<SelectLabel>Single</SelectLabel>
<SelectControl>
<SelectTrigger>
<SelectValueText placeholder="Select a Framework" />
</SelectTrigger>
</SelectControl>
<SelectContent>
<SelectItemGroup>
<SelectItemGroupLabel> Frameworks </SelectItemGroupLabel>
<SelectItem v-for="item in collection.items" :key="item.code" :item="item">
<SelectItemText>{{ item.label }}</SelectItemText>
</SelectItem>
</SelectItemGroup>
</SelectContent>
</SelectRoot>
</template>
<template #code>
<PreviewCode>
{{`
const comboboxData = [
{ label: "React", code: "react" },
{ label: "Solid", code: "solid" },
{ label: "Vue", code: "vue" },
{ label: "Svelte", code: "svelte" },
];
const timezoneData = [
{
label: "North America",
items: [
{ value: "est", label: "Eastern Standard Time (EST)" },
{ value: "cst", label: "Central Standard Time (CST)" },
{ value: "mst", label: "Mountain Standard Time (MST)" },
{ value: "pst", label: "Pacific Standard Time (PST)" },
{ value: "akst", label: "Alaska Standard Time (AKST)" },
{ value: "hst", label: "Hawaii Standard Time (HST)" },
],
},
{
label: "Europe & Africa",
items: [
{ value: "gmt", label: "Greenwich Mean Time (GMT)" },
{ value: "cet", label: "Central European Time (CET)" },
{ value: "eet", label: "Eastern European Time (EET)" },
{ value: "west", label: "Western European Summer Time (WEST)" },
{ value: "cat", label: "Central Africa Time (CAT)" },
{ value: "eat", label: "East Africa Time (EAT)" },
],
},
{
label: "Asia",
items: [
{ value: "msk", label: "Moscow Time (MSK)" },
{ value: "ist", label: "India Standard Time (IST)" },
{ value: "cst_china", label: "China Standard Time (CST)" },
{ value: "jst", label: "Japan Standard Time (JST)" },
{ value: "kst", label: "Korea Standard Time (KST)" },
{
value: "ist_indonesia",
label: "Indonesia Central Standard Time (WITA)",
},
],
},
{
label: "Australia & Pacific",
items: [
{ value: "awst", label: "Australian Western Standard Time (AWST)" },
{ value: "acst", label: "Australian Central Standard Time (ACST)" },
{ value: "aest", label: "Australian Eastern Standard Time (AEST)" },
{ value: "nzst", label: "New Zealand Standard Time (NZST)" },
{ value: "fjt", label: "Fiji Time (FJT)" },
],
},
{
label: "South America",
items: [
{ value: "art", label: "Argentina Time (ART)" },
{ value: "bot", label: "Bolivia Time (BOT)" },
{ value: "brt", label: "Brasilia Time (BRT)" },
{ value: "clt", label: "Chile Standard Time (CLT)" },
],
},
];
const collection = select.collection({
items: comboboxData,
itemToValue: (item) => item.label,
});
const collectionTimezone = select.collection({
items: timezoneData.flatMap((region) =>
region.items.map((item) => ({
region: region.label,
value: item.value,
label: item.label,
}))
),
});
<SelectRoot class="w-56" :collection="collection">
<SelectLabel>Single</SelectLabel>
<SelectControl>
<SelectTrigger>
<SelectValueText placeholder="Select a Framework" />
</SelectTrigger>
</SelectControl>
<SelectContent>
<SelectItemGroup>
<SelectItemGroupLabel> Frameworks </SelectItemGroupLabel>
<SelectItem v-for="item in collection.items" :key="item.code" :item="item">
<SelectItemText>\{\{ item.label \}\}</SelectItemText>
</SelectItem>
</SelectItemGroup>
</SelectContent>
</SelectRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/select</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/select/SelectClearTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectClearTrigger } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Slot v-bind="{ ...api?.getClearTriggerProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<span v-else :class="cn(selectClearTrigger, className)">
<slot />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectContent.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectContent } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import { Box } from "@/components/ui/box";
import { SelectPositioner } from ".";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Teleport to="body">
<SelectPositioner>
<Slot v-bind="{ ...api?.getContentProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<Box v-else raised="single" :class="cn(selectContent, className)">
<div>
<slot />
</div>
</Box>
</Slot>
</SelectPositioner>
</Teleport>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectControl.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectControl } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Slot :class="cn(selectControl, className)" v-bind="{ ...api?.getControlProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectHiddenSelect.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectHiddenSelect } from "@mykopkb/core/styles/select.styles";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<select :class="cn(selectHiddenSelect, className)"
v-bind="{ ...api?.getHiddenSelectProps(), ...props, ...$attrs }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectIndicator.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectIndicator } from "@mykopkb/core/styles/select.styles";
import { ChevronDownIcon } from "@lucide/vue";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Slot :class="cn(selectIndicator, className)" v-bind="{ ...api?.getIndicatorProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot v-if="$slots.default" />
<ChevronDownIcon v-else class="size-3.5" />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectItem.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectItem } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import { SelectItemIndicator } from ".";
import type { Api, ItemProps } from "@zag-js/select";
import { provide, inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<
ItemProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("selectApi");
provide("selectItem", props);
</script>
<template>
<Slot :class="cn(selectItem, className)" v-bind="{ ...api?.getItemProps(props), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
<SelectItemIndicator />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectItemGroup.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectItemGroup } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/select";
import { provide, inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
const itemGroupId = { id: crypto.randomUUID() };
provide("selectItemGroup", props);
</script>
<template>
<Slot :class="cn(selectItemGroup, className)"
v-bind="{ ...api?.getItemGroupProps(itemGroupId), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectItemGroupLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectItemGroupLabel } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemGroupProps } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
const itemGroupId = inject<ItemGroupProps>("selectItemGroup");
</script>
<template>
<Slot :class="cn(selectItemGroupLabel, className)" v-bind="{ ...api?.getItemGroupLabelProps({
htmlFor: itemGroupId?.id!,
}), ...props, ...$attrs }">
<slot v-if="asChild" />
<label v-else>
<slot />
</label>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectItemIndicator.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectItemIndicator } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/select";
import { Check } from "@lucide/vue";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
const item = inject<ItemProps>("selectItem");
</script>
<template>
<Slot :class="cn(selectItemIndicator, className)"
v-bind="{ ...api?.getItemIndicatorProps(item!), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot v-if="$slots.default" />
<Check v-else class="size-3.5" />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectItemText.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectItemText } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, ItemProps } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
const item = inject<ItemProps>("selectItem");
</script>
<template>
<Slot :class="cn(selectItemText, className)" v-bind="{ ...api?.getItemTextProps(item!), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectLabel } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import { Label } from "@/components/ui/label";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Slot v-bind="{ ...api?.getLabelProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<Label v-else :class="cn(selectLabel, className)">
<slot />
</Label>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectPositioner.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectPositioner } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Slot :class="cn(selectPositioner, className)" v-bind="{ ...api?.getPositionerProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectRoot.vue">
{{`
<script lang="ts" setup>
import * as select from "@zag-js/select";
import type { Props } from "@zag-js/select";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { selectRoot } from "@mykopkb/core/styles/select.styles";
import { SelectHiddenSelect } from ".";
const {
class: className,
asChild = false,
multiple = undefined,
open = undefined,
closeOnSelect = undefined,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(select.machine, {
...props,
multiple,
open,
closeOnSelect,
id: crypto.randomUUID(),
});
const api = computed(() => select.connect(service, normalizeProps));
provide("selectApi", api);
</script>
<template>
<Slot :class="cn(selectRoot, className)" :data-multiple="multiple"
v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
<SelectHiddenSelect />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectTrigger } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import { Button } from "@/components/ui/button";
import { SelectClearTrigger, SelectIndicator } from ".";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Slot v-bind="{ ...api?.getTriggerProps(), ...props, ...$attrs }">
<Button variant="ghost" v-if="!asChild" :class="cn(selectTrigger, className)">
<slot />
<SelectClearTrigger>Clear</SelectClearTrigger>
<SelectIndicator />
</Button>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/SelectValueText.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { selectValueText } from "@mykopkb/core/styles/select.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/select";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
placeholder?: string;
}>();
const api = inject<Api>("selectApi");
</script>
<template>
<Slot :class="cn(selectValueText, className)" v-bind="{ ...api?.getValueTextProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>\{\{ api?.valueAsString || props.placeholder \}\}</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/select/index.ts">
{{ `
export { default as SelectClearTrigger } from "./SelectClearTrigger.vue";
export { default as SelectContent } from "./SelectContent.vue";
export { default as SelectControl } from "./SelectControl.vue";
export { default as SelectHiddenSelect } from "./SelectHiddenSelect.vue";
export { default as SelectIndicator } from "./SelectIndicator.vue";
export { default as SelectItem } from "./SelectItem.vue";
export { default as SelectItemGroup } from "./SelectItemGroup.vue";
export { default as SelectItemGroupLabel } from "./SelectItemGroupLabel.vue";
export { default as SelectItemIndicator } from "./SelectItemIndicator.vue";
export { default as SelectItemText } from "./SelectItemText.vue";
export { default as SelectLabel } from "./SelectLabel.vue";
export { default as SelectPositioner } from "./SelectPositioner.vue";
export { default as SelectRoot } from "./SelectRoot.vue";
export { default as SelectTrigger } from "./SelectTrigger.vue";
export { default as SelectValueText } from "./SelectValueText.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
SelectRoot,
SelectLabel,
SelectControl,
SelectTrigger,
SelectValueText,
SelectContent,
SelectItemGroup,
SelectItemGroupLabel,
SelectItem,
SelectItemText,
} from "@/components/ui/select";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<SelectRoot class="w-56" :collection="collection">
<SelectLabel>Single</SelectLabel>
<SelectControl>
<SelectTrigger>
<SelectValueText placeholder="Select a Framework" />
</SelectTrigger>
</SelectControl>
<SelectContent>
<SelectItemGroup>
<SelectItemGroupLabel> Frameworks </SelectItemGroupLabel>
<SelectItem v-for="item in collection.items" :key="item.code" :item="item">
<SelectItemText>\{\{ item.label \}\}</SelectItemText>
</SelectItem>
</SelectItemGroup>
</SelectContent>
</SelectRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<SelectRoot class="w-56" :collection="collection" multiple>
<SelectLabel>Multiple</SelectLabel>
<SelectControl>
<SelectTrigger>
<SelectValueText placeholder="Select a Framework" />
</SelectTrigger>
</SelectControl>
<SelectContent>
<SelectItemGroup>
<SelectItemGroupLabel> Frameworks </SelectItemGroupLabel>
<SelectItem v-for="item in collection.items" :key="item.code" :item="item">
<SelectItemText>{{ item.label }}</SelectItemText>
</SelectItem>
</SelectItemGroup>
</SelectContent>
</SelectRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<SelectRoot class="w-56" :collection="collection" multiple>
<SelectLabel>Multiple</SelectLabel>
<SelectControl>
<SelectTrigger>
<SelectValueText placeholder="Select a Framework" />
</SelectTrigger>
</SelectControl>
<SelectContent>
<SelectItemGroup>
<SelectItemGroupLabel> Frameworks </SelectItemGroupLabel>
<SelectItem v-for="item in collection.items" :key="item.code" :item="item">
<SelectItemText>\{\{ item.label \}\}</SelectItemText>
</SelectItem>
</SelectItemGroup>
</SelectContent>
</SelectRoot>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<SelectRoot class="w-56" :collection="collectionTimezone" multiple>
<SelectLabel>Scrollable</SelectLabel>
<SelectControl>
<SelectTrigger>
<SelectValueText placeholder="Select a Timezone" />
</SelectTrigger>
</SelectControl>
<SelectContent>
<SelectItemGroup v-for="item in timezoneData" :key="item.label">
<SelectItemGroupLabel>{{ item.label }}</SelectItemGroupLabel>
<SelectItem v-for="timezoneItem in item.items" :key="timezoneItem.value" :item="timezoneItem.value">
<SelectItemText>{{ timezoneItem.label }}</SelectItemText>
</SelectItem>
</SelectItemGroup>
</SelectContent>
</SelectRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<SelectRoot class="w-56" :collection="collectionTimezone" multiple>
<SelectLabel>Scrollable</SelectLabel>
<SelectControl>
<SelectTrigger>
<SelectValueText placeholder="Select a Timezone" />
</SelectTrigger>
</SelectControl>
<SelectContent>
<SelectItemGroup v-for="item in timezoneData" :key="item.label">
<SelectItemGroupLabel>\{\{ item.label \}\}</SelectItemGroupLabel>
<SelectItem v-for="timezoneItem in item.items" :key="timezoneItem.value" :item="timezoneItem.value">
<SelectItemText>\{\{ timezoneItem.label \}\}</SelectItemText>
</SelectItem>
</SelectItemGroup>
</SelectContent>
</SelectRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+508
View File
@@ -0,0 +1,508 @@
<script lang="ts" setup>
import {
SheetRoot,
SheetTrigger,
SheetContent,
SheetTitle,
SheetDescription,
SheetCloseTrigger,
} from "@/components/ui/sheet";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { SquareX, Save, ExternalLink } from "@lucide/vue";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<SheetRoot>
<SheetTrigger>Open Sheet</SheetTrigger>
<SheetContent>
<SheetTitle>Sheet Title</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<SheetCloseTrigger>
<SquareX />
Close
</SheetCloseTrigger>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
<SheetCloseTrigger />
</SheetContent>
</SheetRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<SheetRoot>
<SheetTrigger>Open Sheet</SheetTrigger>
<SheetContent>
<SheetTitle>Sheet Title</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<SheetCloseTrigger>
<SquareX />
Close
</SheetCloseTrigger>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
<SheetCloseTrigger />
</SheetContent>
</SheetRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/dialog</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/sheet/SheetRoot.vue">
{{`
<script lang="ts" setup>
import { provide, computed } from "vue";
import * as dialog from "@zag-js/dialog";
import type { Props } from "@zag-js/dialog";
import { useMachine, normalizeProps } from "@zag-js/vue";
const {
class: className,
asChild = false,
open = undefined,
closeOnInteractOutside = undefined,
...props
} = defineProps<
Partial<Props> & {
class?: string;
asChild?: boolean;
}
>();
const service = useMachine(dialog.machine, {
...props,
get open() {
return open;
},
closeOnInteractOutside,
id: crypto.randomUUID(),
});
const api = computed(() => dialog.connect(service, normalizeProps));
provide("sheetApi", api);
</script>
<template>
<slot />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/SheetTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sheetTrigger } from "@mykopkb/core/styles/sheet.styles";
import { Button } from "@/components/ui/button";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sheetApi");
</script>
<template>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getTriggerProps() }">
<Button variant="secondary" look="outline" v-if="!asChild" :class="cn(sheetTrigger, className)">
<slot />
</Button>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/SheetBackdrop.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sheetBackdrop } from "@mykopkb/core/styles/sheet.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sheetApi");
</script>
<template>
<Slot :class="cn(sheetBackdrop, className)" v-bind="{ ...props, ...$attrs, ...api?.getBackdropProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/SheetPositioner.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sheetPositioner } from "@mykopkb/core/styles/sheet.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sheetApi");
</script>
<template>
<Slot :class="cn(sheetPositioner, className)" v-bind="{ ...props, ...$attrs, ...api?.getPositionerProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/SheetContent.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sheetContent } from "@mykopkb/core/styles/sheet.styles";
import { Box } from "@/components/ui/box";
import { SheetBackdrop, SheetPositioner } from "@/components/ui/sheet";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
side = "right",
...props
} = defineProps<{
class?: string;
asChild?: boolean;
side?: "top" | "right" | "bottom" | "left";
}>();
const api = inject<Api>("sheetApi");
</script>
<template>
<Teleport to="body">
<SheetBackdrop />
<SheetPositioner>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getContentProps() }">
<slot v-if="asChild" />
<div v-else>
<Box raised="double" :data-side="side" :class="cn(sheetContent, className)" v-bind="{ ...props }">
<div>
<slot />
</div>
</Box>
</div>
</Slot>
</SheetPositioner>
</Teleport>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/SheetTitle.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sheetTitle } from "@mykopkb/core/styles/sheet.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sheetApi");
</script>
<template>
<Slot :class="cn(sheetTitle, className)" v-bind="{ ...props, ...$attrs, ...api?.getTitleProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/SheetDescription.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sheetDescription } from "@mykopkb/core/styles/sheet.styles";
import type { Api } from "@zag-js/dialog";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sheetApi");
</script>
<template>
<Slot :class="cn(sheetDescription, className)" v-bind="{ ...props, ...$attrs, ...api?.getDescriptionProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/SheetCloseTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sheetCloseTrigger } from "@mykopkb/core/styles/sheet.styles";
import { Button } from "@/components/ui/button";
import type { Api } from "@zag-js/dialog";
import {
buttonVariants,
type ButtonVariants,
} from "@mykopkb/core/styles/button.styles";
import { X } from "@lucide/vue";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
look = "outline",
variant = "secondary",
size,
asChild = false,
...props
} = defineProps<
ButtonVariants & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("sheetApi");
</script>
<template>
<Slot v-bind="{ ...props, ...$attrs, ...api?.getCloseTriggerProps() }">
<Button variant="ghost" v-if="!$slots.default" :class="cn(sheetCloseTrigger, className)"
v-bind="{ ...props }">
<X class="size-4" />
</Button>
<template v-else>
<slot v-if="asChild" />
<Button v-else :class="
cn(buttonVariants({ look, variant, size, className }), className)
">
<slot />
</Button>
</template>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/sheet/index.ts">
{{ `
export { default as SheetRoot } from "./SheetRoot.vue";
export { default as SheetTrigger } from "./SheetTrigger.vue";
export { default as SheetBackdrop } from "./SheetBackdrop.vue";
export { default as SheetPositioner } from "./SheetPositioner.vue";
export { default as SheetContent } from "./SheetContent.vue";
export { default as SheetTitle } from "./SheetTitle.vue";
export { default as SheetDescription } from "./SheetDescription.vue";
export { default as SheetCloseTrigger } from "./SheetCloseTrigger.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
SheetRoot,
SheetTrigger,
SheetContent,
SheetTitle,
SheetDescription,
SheetCloseTrigger,
} from "@/components/ui/sheet";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<SheetRoot>
<SheetTrigger>Open Sheet</SheetTrigger>
<SheetContent>
<SheetTitle>Sheet Title</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<SheetCloseTrigger>
<SquareX />
Close
</SheetCloseTrigger>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
<SheetCloseTrigger />
</SheetContent>
</SheetRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<SheetRoot>
<SheetTrigger>Custom Close</SheetTrigger>
<SheetContent>
<SheetTitle>Share Link</SheetTitle>
<SheetDescription>
Anyone who has this link will be able to view this.
</SheetDescription>
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<SheetCloseTrigger>
<ExternalLink />
Share Link
</SheetCloseTrigger>
</div>
</SheetContent>
</SheetRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<SheetRoot>
<SheetTrigger>Custom Close</SheetTrigger>
<SheetContent>
<SheetTitle>Share Link</SheetTitle>
<SheetDescription>
Anyone who has this link will be able to view this.
</SheetDescription>
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<SheetCloseTrigger>
<ExternalLink />
Share Link
</SheetCloseTrigger>
</div>
</SheetContent>
</SheetRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+493
View File
@@ -0,0 +1,493 @@
<script lang="ts" setup>
import {
SliderRoot,
SliderLabel,
SliderValueText,
SliderControl,
SliderTrack,
SliderRange,
SliderThumb,
SliderHiddenInput,
SliderMarkerGroup,
SliderMarker,
} from "@/components/ui/slider";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<SliderRoot class="w-72" :defaultValue="[20]">
<SliderLabel>Max Items</SliderLabel>
<SliderControl>
<SliderTrack>
<SliderRange />
</SliderTrack>
<SliderThumb :index="0">
<SliderHiddenInput />
</SliderThumb>
</SliderControl>
<div class="flex items-center text-xs gap-1 font-medium justify-center opacity-70">
<SliderValueText /> Items
</div>
</SliderRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<SliderRoot class="w-72" :defaultValue="[20]">
<SliderLabel>Max Items</SliderLabel>
<SliderControl>
<SliderTrack>
<SliderRange />
</SliderTrack>
<SliderThumb :index="0">
<SliderHiddenInput />
</SliderThumb>
</SliderControl>
<div class="flex items-center text-xs gap-1 font-medium justify-center opacity-70">
<SliderValueText /> Items
</div>
</SliderRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/slider</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/slider/SliderRoot.vue">
{{`
<script lang="ts" setup>
import * as slider from "@zag-js/slider";
import type { Props } from "@zag-js/slider";
import { Slot } from "@/components/ui/slot";
import { cn } from "@mykopkb/core/utils/cn";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { sliderRoot } from "@mykopkb/core/styles/slider.styles";
const {
class: className,
asChild = false,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(slider.machine, {
...props,
id: crypto.randomUUID(),
});
const api = computed(() => slider.connect(service, normalizeProps));
provide("sliderApi", api);
</script>
<template>
<Slot :class="cn(sliderRoot, className)" v-bind="{ ...props, ...$attrs, ...api.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderLabel } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import { Label } from "@/components/ui/label";
import type { Api } from "@zag-js/slider";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sliderApi");
</script>
<template>
<Slot v-bind="{ ...api?.getLabelProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<Label v-else :class="cn(sliderLabel, className)">
<slot />
</Label>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderValueText.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderValueText } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/slider";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sliderApi");
</script>
<template>
<Slot :class="cn(sliderValueText, className)" v-bind="{ ...api?.getValueTextProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<output v-else>\{\{ api?.value?.[0] \}\}</output>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderControl.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderControl } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/slider";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sliderApi");
</script>
<template>
<Slot :class="cn(sliderControl, className)" v-bind="{ ...api?.getControlProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderTrack.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderTrack } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/slider";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sliderApi");
</script>
<template>
<Slot :class="cn(sliderTrack, className)" v-bind="{ ...api?.getTrackProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderRange.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderRange } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/slider";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sliderApi");
</script>
<template>
<Slot :class="cn(sliderRange, className)" v-bind="{ ...api?.getRangeProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderThumb.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderThumb } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, ThumbProps } from "@zag-js/slider";
import { provide, inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<
ThumbProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("sliderApi");
provide("sliderThumb", props);
</script>
<template>
<Slot :class="cn(sliderThumb, className)" v-bind="{ ...api?.getThumbProps(props), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderHiddenInput.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderHiddenInput } from "@mykopkb/core/styles/slider.styles";
import type { Api, ThumbProps } from "@zag-js/slider";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const api = inject<Api>("sliderApi");
const thumbProps = inject<ThumbProps>("sliderThumb");
</script>
<template>
<input :class="cn(sliderHiddenInput, className)"
v-bind="{ ...api?.getHiddenInputProps(thumbProps!), ...props, ...$attrs }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderMarkerGroup.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderMarkerGroup } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/slider";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("sliderApi");
</script>
<template>
<Slot :class="cn(sliderMarkerGroup, className)" v-bind="{ ...api?.getMarkerGroupProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/SliderMarker.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { sliderMarker } from "@mykopkb/core/styles/slider.styles";
import { Slot } from "@/components/ui/slot";
import type { Api, MarkerProps } from "@zag-js/slider";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<
MarkerProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("sliderApi");
</script>
<template>
<Slot :class="cn(sliderMarker, className)" v-bind="{ ...api?.getMarkerProps(props), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/slider/index.ts">
{{ `
export { default as SliderRoot } from "./SliderRoot.vue";
export { default as SliderLabel } from "./SliderLabel.vue";
export { default as SliderValueText } from "./SliderValueText.vue";
export { default as SliderControl } from "./SliderControl.vue";
export { default as SliderTrack } from "./SliderTrack.vue";
export { default as SliderRange } from "./SliderRange.vue";
export { default as SliderThumb } from "./SliderThumb.vue";
export { default as SliderHiddenInput } from "./SliderHiddenInput.vue";
export { default as SliderMarkerGroup } from "./SliderMarkerGroup.vue";
export { default as SliderMarker } from "./SliderMarker.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
SliderRoot,
SliderLabel,
SliderValueText,
SliderControl,
SliderTrack,
SliderRange,
SliderThumb,
SliderHiddenInput,
SliderMarkerGroup,
SliderMarker,
} from "@/components/ui/slider";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<SliderRoot class="w-72" :defaultValue="[20]">
<SliderLabel>Max Items</SliderLabel>
<SliderControl>
<SliderTrack>
<SliderRange />
</SliderTrack>
<SliderThumb :index="0">
<SliderHiddenInput />
</SliderThumb>
</SliderControl>
<div class="flex items-center text-xs gap-1 font-medium justify-center opacity-70">
<SliderValueText /> Items
</div>
</SliderRoot>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<SliderRoot class="w-72" :value="[20, 80]">
<SliderLabel>Price Range</SliderLabel>
<SliderControl>
<SliderTrack>
<SliderRange />
</SliderTrack>
<SliderThumb :index="0">
<SliderHiddenInput />
</SliderThumb>
<SliderThumb :index="1">
<SliderHiddenInput />
</SliderThumb>
</SliderControl>
<SliderMarkerGroup>
<SliderMarker :value="0">$0</SliderMarker>
<SliderMarker :value="25">$25</SliderMarker>
<SliderMarker :value="50">$50</SliderMarker>
<SliderMarker :value="75">$75</SliderMarker>
<SliderMarker :value="100">$100</SliderMarker>
</SliderMarkerGroup>
</SliderRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<SliderRoot class="w-72" :value="[20, 80]">
<SliderLabel>Price Range</SliderLabel>
<SliderControl>
<SliderTrack>
<SliderRange />
</SliderTrack>
<SliderThumb :index="0">
<SliderHiddenInput />
</SliderThumb>
<SliderThumb :index="1">
<SliderHiddenInput />
</SliderThumb>
</SliderControl>
<SliderMarkerGroup>
<SliderMarker :value="0">$0</SliderMarker>
<SliderMarker :value="25">$25</SliderMarker>
<SliderMarker :value="50">$50</SliderMarker>
<SliderMarker :value="75">$75</SliderMarker>
<SliderMarker :value="100">$100</SliderMarker>
</SliderMarkerGroup>
</SliderRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+196
View File
@@ -0,0 +1,196 @@
<script lang="ts" setup>
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
import { Box } from "@/components/ui/box";
import { Button } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "@lucide/vue";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<div class="justify-center items-center flex gap-2">
<Box as-child>
<Button variant="ghost" class="me-2 px-2">
<ChevronLeft class="size-5" />
</Button>
</Box>
<Box as-child>
<Button variant="ghost" class="px-2">
<ChevronRight class="size-5" />
</Button>
</Box>
</div>
</template>
<template #code>
<PreviewCode>
{{ `
<div class="justify-center items-center flex gap-2">
<Box as-child>
<Button variant="ghost" class="me-2 px-2">
<ChevronLeft class="size-5" />
</Button>
</Box>
<Box as-child>
<Button variant="ghost" class="px-2">
<ChevronRight class="size-5" />
</Button>
</Box>
</div>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
By using <code>Slot</code> at the root, you ensure that props are correctly merged whether
you're using it as a direct wrapper or an <code>asChild</code> bridge.
</SectionContent>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/slot/index.ts">
{{ `import {
defineComponent,
h,
cloneVNode,
Fragment,
isVNode,
type VNode,
type PropType,
} from "vue";
import { calculateSlot, flattenItems, type AnyProps } from "./slot";
export const Slot = defineComponent({
name: "Slot",
inheritAttrs: false,
props: {
children: {
type: [Object, Array] as PropType<any>,
},
},
setup(props, { attrs, slots }) {
return () => {
const raw = props.children ?? slots.default?.();
const isValidVNode = (item: any): item is VNode => isVNode(item) && typeof item.type !== "symbol";
const items = flattenItems<VNode>(
raw as any,
(item) => isVNode(item) && item.type === Fragment,
(item) => (isVNode(item) && Array.isArray(item.children) ? (item.children as VNode[]) : [])
).filter(isValidVNode);
const result = calculateSlot<VNode>({
props: attrs as AnyProps,
items,
isValid: isValidVNode,
getProps: (item) => (item.props as AnyProps) || {},
getChildren: (item) => item.children,
});
if (result.type === "wrapper") {
return h("div", result.props, result.children as any);
}
const target = result.target;
return cloneVNode(target, result.props, false);
};
},
});
export { Slot as Root };` }}
</PreviewCode>
<PreviewCode title="components/ui/slot/slot.ts">
{{ `export type AnyProps = Record<string, any>;
export interface SlotParams<T> {
props: AnyProps;
items: T[];
isValid: (item: T) => boolean;
getProps: (item: T) => AnyProps;
getChildren: (item: T) => any;
}
export type SlotResult<T> =
| { type: "slotted"; target: T; props: AnyProps; children: any }
| { type: "wrapper"; target: "div"; props: AnyProps; children: T[] };
export function mergeProps(slotProps: AnyProps, childProps: AnyProps): AnyProps {
const result: AnyProps = { ...childProps };
for (const key in slotProps) {
const slotValue = slotProps[key];
const isHandler = /^on[A-Z]/.test(key);
if (isHandler) {
const childValue = childProps[key];
if (typeof slotValue === "function" && typeof childValue === "function") {
result[key] = (...args: any[]) => {
childValue(...args);
slotValue(...args);
};
} else if (slotValue) {
result[key] = slotValue;
}
continue;
}
if (key === "class" || key === "className") {
const slotClasses = (slotValue || "").split(/\\s+/);
const childClasses = (childProps.class || childProps.className || "").split(/\\s+/);
const combined = Array.from(new Set([...slotClasses, ...childClasses])).filter(Boolean).join(" ");
result[key] = combined;
continue;
}
if (key === "style") {
result[key] = { ...slotValue, ...childProps.style };
continue;
}
if (childProps[key] === undefined) {
result[key] = slotValue;
}
}
return result;
}
export function flattenItems<T>(items: T | T[], isFragment: (item: T) => boolean, getChildren: (item: T) =>
T
| T[]): T[] {
const result: T[] = [];
const list = Array.isArray(items) ? items : [items];
list.forEach((item) => {
if (item === null || item === undefined) return;
if (isFragment(item)) {
const children = getChildren(item);
result.push(...flattenItems(children, isFragment, getChildren));
} else {
result.push(item);
}
});
return result;
}
export function calculateSlot<T>(params: SlotParams<T>): SlotResult<T> {
const { props, items, isValid, getProps, getChildren } = params;
if (items.length === 1) {
const primary = items[0];
if (isValid(primary)) {
return {
type: "slotted",
target: primary,
props: mergeProps(props, getProps(primary)),
children: getChildren(primary),
};
}
}
return { type: "wrapper", target: "div", props: props, children: items };
}` }}
</PreviewCode>
</div>
</template>
+230
View File
@@ -0,0 +1,230 @@
<script lang="ts" setup>
import { SwitchRoot, SwitchControl, SwitchLabel } from "@/components/ui/switch";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<SwitchRoot>
<SwitchControl />
<SwitchLabel>Airplane Mode</SwitchLabel>
</SwitchRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<SwitchRoot>
<SwitchControl />
<SwitchLabel>Airplane Mode</SwitchLabel>
</SwitchRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/switch</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/switch/SwitchRoot.vue">
{{`
<script lang="ts" setup>
import * as zagSwitch from "@zag-js/switch";
import type { Props } from "@zag-js/switch";
import { cn } from "@mykopkb/core/utils/cn";
import { switchRoot } from "@mykopkb/core/styles/switch.styles";
import { SwitchHiddenInput } from ".";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
checked = undefined,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(zagSwitch.machine, {
...props,
checked,
id: crypto.randomUUID(),
});
const api = computed(() => zagSwitch.connect(service, normalizeProps));
provide("switchApi", api);
</script>
<template>
<Slot :class="cn(switchRoot, className)" v-bind="{ ...props, ...$attrs, ...api?.getRootProps() }">
<slot v-if="asChild" />
<label v-else>
<slot />
<SwitchHiddenInput />
</label>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/switch/SwitchControl.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { switchControl } from "@mykopkb/core/styles/switch.styles";
import { SwitchThumb } from ".";
import type { Api } from "@zag-js/switch";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("switchApi");
</script>
<template>
<Slot :class="cn(switchControl, className)" v-bind="{ ...props, ...$attrs, ...api?.getControlProps() }">
<slot v-if="asChild" />
<span v-else>
<SwitchThumb />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/switch/SwitchThumb.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { switchThumb } from "@mykopkb/core/styles/switch.styles";
import type { Api } from "@zag-js/switch";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("switchApi");
</script>
<template>
<Slot :class="cn(switchThumb, className)" v-bind="{ ...props, ...$attrs, ...api?.getThumbProps() }">
<slot v-if="asChild" />
<span v-else>
<slot />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/switch/SwitchLabel.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { switchLabel } from "@mykopkb/core/styles/switch.styles";
import { label } from "@mykopkb/core/styles/label.styles";
import type { Api } from "@zag-js/switch";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("switchApi");
</script>
<template>
<Slot :class="cn([label, switchLabel, className])" v-bind="{ ...props, ...$attrs, ...api?.getLabelProps() }">
<slot v-if="asChild" />
<span v-else>
<slot />
</span>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/switch/SwitchHiddenInput.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { switchHiddenInput } from "@mykopkb/core/styles/switch.styles";
import type { Api } from "@zag-js/switch";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("switchApi");
</script>
<template>
<input :class="cn(switchHiddenInput, className)"
v-bind="{ ...props, ...$attrs, ...api?.getHiddenInputProps() }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/switch/index.ts">
{{ `
export { default as SwitchRoot } from "./SwitchRoot.vue";
export { default as SwitchControl } from "./SwitchControl.vue";
export { default as SwitchThumb } from "./SwitchThumb.vue";
export { default as SwitchLabel } from "./SwitchLabel.vue";
export { default as SwitchHiddenInput } from "./SwitchHiddenInput.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { SwitchRoot, SwitchControl, SwitchLabel } from "@/components/ui/switch";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<SwitchRoot>
<SwitchControl />
<SwitchLabel>Airplane Mode</SwitchLabel>
</SwitchRoot>
` }}
</PreviewCode>
</div>
</template>
+653
View File
@@ -0,0 +1,653 @@
<script lang="ts" setup>
import {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
} from "@/components/ui/table";
import { Badge } from "@/components/ui/badge";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
const invoices: {
invoice: string;
paymentStatus: string;
badge: "success" | "pending" | "danger";
totalAmount: string;
paymentMethod: string;
}[] = [
{
invoice: "INV001",
paymentStatus: "Paid",
badge: "success",
totalAmount: "$250.00",
paymentMethod: "Credit Card",
},
{
invoice: "INV002",
paymentStatus: "Pending",
badge: "pending",
totalAmount: "$150.00",
paymentMethod: "PayPal",
},
{
invoice: "INV003",
paymentStatus: "Unpaid",
badge: "danger",
totalAmount: "$350.00",
paymentMethod: "Bank Transfer",
},
{
invoice: "INV004",
paymentStatus: "Paid",
badge: "success",
totalAmount: "$450.00",
paymentMethod: "Credit Card",
},
{
invoice: "INV005",
paymentStatus: "Paid",
badge: "success",
totalAmount: "$550.00",
paymentMethod: "PayPal",
},
{
invoice: "INV006",
paymentStatus: "Pending",
badge: "pending",
totalAmount: "$200.00",
paymentMethod: "Bank Transfer",
},
{
invoice: "INV007",
paymentStatus: "Unpaid",
badge: "danger",
totalAmount: "$300.00",
paymentMethod: "Credit Card",
},
];
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
{{ invoice.invoice }}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
{{ invoice.paymentStatus }}
</Badge>
</TableCell>
<TableCell>{{ invoice.paymentMethod }}</TableCell>
<TableCell class="text-right">
{{ invoice.totalAmount }}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</template>
<template #code>
<PreviewCode>
{{ `
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
\{\{ invoice.invoice \}\}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
\{\{ invoice.paymentStatus \}\}
</Badge>
</TableCell>
<TableCell>\{\{ invoice.paymentMethod \}\}</TableCell>
<TableCell class="text-right">
\{\{ invoice.totalAmount \}\}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/table/Table.vue">
{{`
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import {
tableVariants,
type TableVariants,
} from "@mykopkb/core/styles/table.styles";
import { provide, computed } from "vue";
import TableContainer from "./TableContainer.vue";
const { class: className, ...props } = defineProps<
TableVariants & {
class?: string;
}
>();
provide(
"tableVariant",
computed(() => ({
variant: props.variant,
raised: props.raised,
}))
);
</script>
<template>
<TableContainer>
<table :class="cn(tableVariants({ variant, raised, className }), className)" v-bind="{ ...props }">
<slot />
</table>
</TableContainer>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableContainer.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableContainer } from "@mykopkb/core/styles/table.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<div :class="cn(tableContainer, className)" v-bind="{ ...props }">
<slot />
</div>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableHeader.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableHeader } from "@mykopkb/core/styles/table.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<thead :class="cn(tableHeader, className)" v-bind="{ ...props }">
<slot />
</thead>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableBody.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableBody } from "@mykopkb/core/styles/table.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<tbody :class="cn(tableBody, className)" v-bind="{ ...props }">
<slot />
</tbody>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableFooter.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableFooter } from "@mykopkb/core/styles/table.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<tfoot :class="cn(tableFooter, className)" v-bind="{ ...props }">
<slot />
</tfoot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableHead.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableHead } from "@mykopkb/core/styles/table.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<th :class="cn(tableHead, className)" v-bind="{ ...props }">
<slot />
</th>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableRow.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableRow } from "@mykopkb/core/styles/table.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<tr :class="cn(tableRow, className)" v-bind="{ ...props }">
<slot />
</tr>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableCell.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableCellVariants } from "@mykopkb/core/styles/table.styles";
import { inject } from "vue";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
const variant = inject<
| {
variant?: "default" | "boxed" | null;
raised?: "single" | "double" | null;
}
| undefined
>("tableVariant", undefined);
</script>
<template>
<td :class="cn(tableCellVariants({ ...variant, className }), className)" v-bind="{ ...props }">
<slot />
</td>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/TableCaption.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tableCaption } from "@mykopkb/core/styles/table.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<caption :class="cn(tableCaption, className)" v-bind="{ ...props }">
<slot />
</caption>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/table/index.ts">
{{ `
export { default as Table } from "./Table.vue";
export { default as TableContainer } from "./TableContainer.vue";
export { default as TableHeader } from "./TableHeader.vue";
export { default as TableBody } from "./TableBody.vue";
export { default as TableFooter } from "./TableFooter.vue";
export { default as TableHead } from "./TableHead.vue";
export { default as TableRow } from "./TableRow.vue";
export { default as TableCell } from "./TableCell.vue";
export { default as TableCaption } from "./TableCaption.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
} from "@/components/ui/table";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
\{\{ invoice.invoice \}\}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
\{\{ invoice.paymentStatus \}\}
</Badge>
</TableCell>
<TableCell>\{\{ invoice.paymentMethod \}\}</TableCell>
<TableCell class="text-right">
\{\{ invoice.totalAmount \}\}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
` }}
</PreviewCode>
</div>
<div id="variants">
<SectionTitle>Variants</SectionTitle>
<SectionContent>A collection of components you can use.</SectionContent>
<Preview>
<template #preview>
<Table variant="boxed">
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
{{ invoice.invoice }}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
{{ invoice.paymentStatus }}
</Badge>
</TableCell>
<TableCell>{{ invoice.paymentMethod }}</TableCell>
<TableCell class="text-right">
{{ invoice.totalAmount }}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</template>
<template #code>
<PreviewCode>
{{ `
<Table variant="boxed">
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
\{\{ invoice.invoice \}\}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
\{\{ invoice.paymentStatus \}\}
</Badge>
</TableCell>
<TableCell>\{\{ invoice.paymentMethod \}\}</TableCell>
<TableCell class="text-right">
\{\{ invoice.totalAmount \}\}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Table variant="boxed" raised="single">
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
{{ invoice.invoice }}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
{{ invoice.paymentStatus }}
</Badge>
</TableCell>
<TableCell>{{ invoice.paymentMethod }}</TableCell>
<TableCell class="text-right">
{{ invoice.totalAmount }}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</template>
<template #code>
<PreviewCode>
{{ `
<Table variant="boxed" raised="single">
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
\{\{ invoice.invoice \}\}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
\{\{ invoice.paymentStatus \}\}
</Badge>
</TableCell>
<TableCell>\{\{ invoice.paymentMethod \}\}</TableCell>
<TableCell class="text-right">
\{\{ invoice.totalAmount \}\}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
` }}
</PreviewCode>
</template>
</Preview>
<Preview>
<template #preview>
<Table variant="boxed" raised="double">
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
{{ invoice.invoice }}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
{{ invoice.paymentStatus }}
</Badge>
</TableCell>
<TableCell>{{ invoice.paymentMethod }}</TableCell>
<TableCell class="text-right">
{{ invoice.totalAmount }}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</template>
<template #code>
<PreviewCode>
{{ `
<Table variant="boxed" raised="double">
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead class="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead class="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="invoice in invoices" :key="invoice.invoice">
<TableCell class="font-medium">
\{\{ invoice.invoice \}\}
</TableCell>
<TableCell>
<Badge :variant="invoice.badge">
\{\{ invoice.paymentStatus \}\}
</Badge>
</TableCell>
<TableCell>\{\{ invoice.paymentMethod \}\}</TableCell>
<TableCell class="text-right">
\{\{ invoice.totalAmount \}\}
</TableCell>
</TableRow>
</TableBody>
<TableFooter>
<TableRow>
<TableCell :colspan="3">Total</TableCell>
<TableCell class="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
` }}
</PreviewCode>
</template>
</Preview>
</div>
</template>
+361
View File
@@ -0,0 +1,361 @@
<script lang="ts" setup>
import { Box } from "@/components/ui/box";
import {
TabsRoot,
TabsList,
TabsTrigger,
TabsContent,
} from "@/components/ui/tabs";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { SquareX, Save, ExternalLink } from "@lucide/vue";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<TabsRoot defaultValue="update-profile">
<TabsList>
<TabsTrigger value="update-profile"> Update Profile </TabsTrigger>
<TabsTrigger value="share-profile"> Share Profile </TabsTrigger>
</TabsList>
<Box raised="single" class="w-90">
<TabsContent value="update-profile">
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<Button>
<SquareX />
Close
</Button>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
</TabsContent>
<TabsContent value="share-profile">
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<Button>
<ExternalLink />
Share Link
</Button>
</div>
</TabsContent>
</Box>
</TabsRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<TabsRoot defaultValue="update-profile">
<TabsList>
<TabsTrigger value="update-profile"> Update Profile </TabsTrigger>
<TabsTrigger value="share-profile"> Share Profile </TabsTrigger>
</TabsList>
<Box raised="single" class="w-90">
<TabsContent value="update-profile">
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<Button>
<SquareX />
Close
</Button>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
</TabsContent>
<TabsContent value="share-profile">
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<Button>
<ExternalLink />
Share Link
</Button>
</div>
</TabsContent>
</Box>
</TabsRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/react @zag-js/tabs</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/tabs/TabsContent.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tabsContent } from "@mykopkb/core/styles/tabs.styles";
import type { Api, ContentProps } from "@zag-js/tabs";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<
ContentProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("tabsApi");
</script>
<template>
<Slot :class="cn(tabsContent, className)" v-bind="{ ...props, ...$attrs, ...api?.getContentProps(props) }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tabs/TabsIndicator.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tabsIndicator } from "@mykopkb/core/styles/tabs.styles";
import type { Api } from "@zag-js/tabs";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("tabsApi");
</script>
<template>
<Slot :class="cn(tabsIndicator, className)" v-bind="{ ...props, ...$attrs, ...api?.getIndicatorProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tabs/TabsList.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tabsList } from "@mykopkb/core/styles/tabs.styles";
import type { Api } from "@zag-js/tabs";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
import { TabsIndicator } from ".";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("tabsApi");
</script>
<template>
<Slot :class="cn(tabsList, className)" v-bind="{ ...props, ...$attrs, ...api?.getListProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
<TabsIndicator />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tabs/TabsRoot.vue">
{{`
<script lang="ts" setup>
import * as tabs from "@zag-js/tabs";
import type { Props } from "@zag-js/tabs";
import { cn } from "@mykopkb/core/utils/cn";
import { tabsRoot } from "@mykopkb/core/styles/tabs.styles";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(tabs.machine, {
...props,
id: crypto.randomUUID(),
});
const api = computed(() => tabs.connect(service, normalizeProps));
provide("tabsApi", api);
</script>
<template>
<Slot :class="cn(tabsRoot, className)" v-bind="{ ...props, ...$attrs, ...api?.getRootProps() }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tabs/TabsTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tabsTrigger } from "@mykopkb/core/styles/tabs.styles";
import type { Api, TriggerProps } from "@zag-js/tabs";
import { inject } from "vue";
import { Slot } from "@/components/ui/slot";
const {
class: className,
asChild = false,
...props
} = defineProps<
TriggerProps & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("tabsApi");
</script>
<template>
<Slot :class="cn(tabsTrigger, className)" v-bind="{ ...props, ...$attrs, ...api?.getTriggerProps(props) }">
<slot v-if="asChild" />
<button v-else>
<slot />
</button>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tabs/index.ts">
{{ `
export { default as TabsContent } from "./TabsContent.vue";
export { default as TabsIndicator } from "./TabsIndicator.vue";
export { default as TabsList } from "./TabsList.vue";
export { default as TabsRoot } from "./TabsRoot.vue";
export { default as TabsTrigger } from "./TabsTrigger.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
TabsRoot,
TabsList,
TabsTrigger,
TabsContent,
} from "@/components/ui/tabs";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<TabsRoot defaultValue="update-profile">
<TabsList>
<TabsTrigger value="update-profile"> Update Profile </TabsTrigger>
<TabsTrigger value="share-profile"> Share Profile </TabsTrigger>
</TabsList>
<Box raised="single" class="w-90">
<TabsContent value="update-profile">
<div class="grid gap-4 mt-2">
<div class="grid gap-2.5">
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
</div>
<div class="grid gap-2.5">
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" defaultValue="@peduarte" />
</div>
</div>
<div class="flex gap-2 justify-end mt-7">
<Button>
<SquareX />
Close
</Button>
<Button variant="primary">
<Save />
Submit
</Button>
</div>
</TabsContent>
<TabsContent value="share-profile">
<div class="grid gap-4 mt-2">
<Input id="name-1" name="name" defaultValue="https://midone-ui.com/docs/installation" />
</div>
<div class="flex gap-2 mt-5">
<Button>
<ExternalLink />
Share Link
</Button>
</div>
</TabsContent>
</Box>
</TabsRoot>
` }}
</PreviewCode>
</div>
</template>
+69
View File
@@ -0,0 +1,69 @@
<script lang="ts" setup>
import { Textarea } from "@/components/ui/textarea";
import {
Preview,
SectionTitle,
SectionContent,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Textarea class="w-86" placeholder="Type your message here." />
</template>
<template #code>
<PreviewCode>
{{ `
<Textarea class="w-86" placeholder="Type your message here." />
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/textarea/Textarea.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { textarea } from "@mykopkb/core/styles/textarea.styles";
const { class: className, ...props } = defineProps<{
class?: string;
}>();
</script>
<template>
<textarea :class="cn(textarea, className)" v-bind="{ ...props }" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/textarea/index.ts">
{{ `
export { default as Textarea } from "./Textarea.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import { Textarea } from "@/components/ui/textarea";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<Textarea class="w-86" placeholder="Type your message here." />
` }}
</PreviewCode>
</div>
</template>
+371
View File
@@ -0,0 +1,371 @@
<script lang="ts" setup>
import { Button } from "@/components/ui/button";
import {
toaster,
ToasterContainer,
ToastRoot,
ToastTitle,
ToastDescription,
ToastCloseTrigger,
} from "@/components/ui/toast";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<Button @click="
() =>
toaster.create({
title: 'Event has been created',
description: 'Sunday, December 03, 2023 at 9:00 AM',
type: 'info',
})
">
Show Toast
</Button>
<ToasterContainer :toaster="toaster" v-slot="{ toast }">
<ToastRoot :key="toast.id">
<ToastTitle>{{ toast.title }}</ToastTitle>
<ToastDescription>
{{ toast.description }}
</ToastDescription>
<ToastCloseTrigger />
</ToastRoot>
</ToasterContainer>
</template>
<template #code>
<PreviewCode>
{{`
<Button @click="
() =>
toaster.create({
title: 'Event has been created',
description: 'Sunday, December 03, 2023 at 9:00 AM',
type: 'info',
})
">
Show Toast
</Button>
<ToasterContainer :toaster="toaster" v-slot="{ toast }">
<ToastRoot :key="toast.id">
<ToastTitle>\{\{ toast.title \}\}</ToastTitle>
<ToastDescription>
\{\{ toast.description \}\}
</ToastDescription>
<ToastCloseTrigger />
</ToastRoot>
</ToasterContainer>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/toast</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/toast/toaster.ts">
{{ `
import * as toast from "@zag-js/toast";
const toaster = toast.createStore({
placement: "bottom-end",
overlap: true,
gap: 24,
});
export default toaster;
` }}
</PreviewCode>
<PreviewCode title="components/ui/toast/ToastRoot.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { toastRoot } from "@mykopkb/core/styles/toast.styles";
import {
boxVariants,
type BoxVariants,
} from "@mykopkb/core/styles/box.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/toast";
import { inject } from "vue";
const {
class: className,
asChild = false,
raised = "single",
...props
} = defineProps<
BoxVariants & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("toastApi");
</script>
<template>
<Slot :class="cn([boxVariants({ raised, className }), toastRoot, className])"
v-bind="{ ...api?.getRootProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<span v-bind="{ ...api?.getGhostBeforeProps() }" />
<div data-scope="toast" data-part="progressbar" />
<slot />
<span v-bind="{ ...api?.getGhostAfterProps() }" />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/toast/ToastTitle.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { toastTitle } from "@mykopkb/core/styles/toast.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/toast";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("toastApi");
</script>
<template>
<Slot :class="cn(toastTitle, className)" v-bind="{ ...api?.getTitleProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/toast/ToastDescription.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { toastDescription } from "@mykopkb/core/styles/toast.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/toast";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("toastApi");
</script>
<template>
<Slot :class="cn(toastDescription, className)" v-bind="{ ...api?.getDescriptionProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/toast/ToastCloseTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { toastCloseTrigger } from "@mykopkb/core/styles/toast.styles";
import {
buttonVariants,
type ButtonVariants,
} from "@mykopkb/core/styles/button.styles";
import { Slot } from "@/components/ui/slot";
import { Button } from "@/components/ui/button";
import { X } from "@lucide/vue";
import type { Api } from "@zag-js/toast";
import { inject } from "vue";
const {
class: className,
asChild = false,
look = "outline",
variant = "secondary",
size,
...props
} = defineProps<
ButtonVariants & {
class?: string;
asChild?: boolean;
}
>();
const api = inject<Api>("toastApi");
</script>
<template>
<Slot v-bind="{ ...api?.getCloseTriggerProps(), ...props, ...$attrs }">
<Button variant="ghost" v-if="!$slots.default" :class="cn(toastCloseTrigger, className)"
v-bind="{ ...props }">
<X class="size-4" />
</Button>
<template v-else>
<slot v-if="asChild" />
<Button v-else :class="
cn(buttonVariants({ look, variant, size, className }), className)
">
<slot />
</Button>
</template>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/toast/ToastItem.vue">
{{`
<script lang="ts" setup>
import * as toast from "@zag-js/toast";
import { provide, computed } from "vue";
import { useMachine, normalizeProps } from "@zag-js/vue";
const { toastGroup, serviceGroup, index } = defineProps<{
class?: string;
asChild?: boolean;
toastGroup: toast.Options;
serviceGroup: toast.GroupService;
index: number;
}>();
const composedProps = computed(() => ({
...toastGroup,
index,
parent: serviceGroup,
}));
const service = useMachine(toast.machine, composedProps);
const api = toast.connect(service, normalizeProps);
provide("toastApi", api);
</script>
<template>
<slot :toast="{
...api,
id: toastGroup.id,
}" />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/toast/ToasterContainer.vue">
{{`
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import * as toast from "@zag-js/toast";
import { toasterContainer } from "@mykopkb/core/styles/toast.styles";
import type { Store } from "@zag-js/toast";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed } from "vue";
import { ToastItem } from ".";
const {
class: className,
asChild = false,
toaster,
...props
} = defineProps<{ class?: string; asChild?: boolean; toaster: Store }>();
const serviceGroup = useMachine(toast.group.machine, {
id: crypto.randomUUID(),
store: toaster,
});
const apiGroup = computed(() =>
toast.group.connect(serviceGroup, normalizeProps)
);
</script>
<template>
<Teleport to="body">
<div :class="cn(toasterContainer, className)" v-bind="{ ...apiGroup?.getGroupProps(), ...props, ...$attrs }">
<ToastItem v-for="(toastGroup, index) in apiGroup.getToasts()" :key="toastGroup.id" :index="index"
:toastGroup="toastGroup" :serviceGroup="serviceGroup" v-slot="{ toast }">
<slot :toast="toast" />
</ToastItem>
</div>
</Teleport>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/toast/index.ts">
{{ `
export { default as toaster } from "./toaster";
export { default as ToastRoot } from "./ToastRoot.vue";
export { default as ToastTitle } from "./ToastTitle.vue";
export { default as ToastDescription } from "./ToastDescription.vue";
export { default as ToastCloseTrigger } from "./ToastCloseTrigger.vue";
export { default as ToastItem } from "./ToastItem.vue";
export { default as ToasterContainer } from "./ToasterContainer.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
toaster,
ToasterContainer,
ToastRoot,
ToastTitle,
ToastDescription,
ToastCloseTrigger,
} from "@/components/ui/toast";
` }}
</PreviewCode>
<PreviewCode>
{{`
<Button @click="
() =>
toaster.create({
title: 'Event has been created',
description: 'Sunday, December 03, 2023 at 9:00 AM',
type: 'info',
})
">
Show Toast
</Button>
<ToasterContainer :toaster="toaster" v-slot="{ toast }">
<ToastRoot :key="toast.id">
<ToastTitle>\{\{ toast.title \}\}</ToastTitle>
<ToastDescription>
\{\{ toast.description \}\}
</ToastDescription>
<ToastCloseTrigger />
</ToastRoot>
</ToasterContainer>
` }}
</PreviewCode>
</div>
</template>
+287
View File
@@ -0,0 +1,287 @@
<script lang="ts" setup>
import {
TooltipRoot,
TooltipTrigger,
TooltipPositioner,
TooltipContent,
} from "@/components/ui/tooltip";
import {
Preview,
SectionTitle,
SectionContent,
InstallPackage,
PreviewCode,
} from "@/components/docs";
</script>
<template>
<div id="preview" class="-mt-20">
<Preview>
<template #preview>
<TooltipRoot>
<TooltipTrigger>Hover Me</TooltipTrigger>
<TooltipPositioner>
<TooltipContent>I am a tooltip!</TooltipContent>
</TooltipPositioner>
</TooltipRoot>
</template>
<template #code>
<PreviewCode>
{{ `
<TooltipRoot>
<TooltipTrigger>Hover Me</TooltipTrigger>
<TooltipPositioner>
<TooltipContent>I am a tooltip!</TooltipContent>
</TooltipPositioner>
</TooltipRoot>
` }}
</PreviewCode>
</template>
</Preview>
</div>
<div id="installation">
<SectionTitle>Installation</SectionTitle>
<SectionContent>Install the following dependencies:</SectionContent>
<InstallPackage>add @zag-js/vue @zag-js/tooltip</InstallPackage>
<SectionContent>
Copy and paste the following code into your project.
</SectionContent>
<PreviewCode title="components/ui/tooltip/TooltipRoot.vue">
{{`
<script lang="ts" setup>
import * as tooltip from "@zag-js/tooltip";
import type { Props } from "@zag-js/tooltip";
import { normalizeProps, useMachine } from "@zag-js/vue";
import { computed, provide } from "vue";
const {
class: className,
asChild = false,
open = undefined,
disabled = false,
...props
} = defineProps<Partial<Props> & { class?: string; asChild?: boolean }>();
const service = useMachine(tooltip.machine, {
...props,
positioning: {
placement: "top",
offset: { mainAxis: 10 },
},
closeDelay: 0,
openDelay: 0,
open,
disabled,
id: crypto.randomUUID(),
});
const api = computed(() => tooltip.connect(service, normalizeProps));
provide("tooltipApi", api);
</script>
<template>
<slot />
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tooltip/TooltipTrigger.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tooltipTrigger } from "@mykopkb/core/styles/tooltip.styles";
import { Slot } from "@/components/ui/slot";
import { Button } from "@/components/ui/button";
import type { Api } from "@zag-js/tooltip";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("tooltipApi");
</script>
<template>
<Slot v-bind="{ ...api?.getTriggerProps(), ...props, ...$attrs }">
<Button variant="secondary" look="outline" v-if="!asChild" :class="cn(tooltipTrigger, className)">
<slot />
</Button>
<slot v-else />
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tooltip/TooltipPositioner.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tooltipPositioner } from "@mykopkb/core/styles/tooltip.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/tooltip";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("tooltipApi");
</script>
<template>
<Teleport to="body">
<Slot :class="cn(tooltipPositioner, className)"
v-bind="{ ...api?.getPositionerProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</Teleport>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tooltip/TooltipContent.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tooltipContent } from "@mykopkb/core/styles/tooltip.styles";
import { Slot } from "@/components/ui/slot";
import { TooltipArrow, TooltipArrowTip } from ".";
import type { Api } from "@zag-js/tooltip";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("tooltipApi");
</script>
<template>
<Slot :class="cn(tooltipContent, className)" v-bind="{ ...api?.getContentProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
<TooltipArrow>
<TooltipArrowTip />
</TooltipArrow>
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tooltip/TooltipArrow.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tooltipArrow } from "@mykopkb/core/styles/tooltip.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/tooltip";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("tooltipApi");
</script>
<template>
<Slot :class="cn(tooltipArrow, className)" v-bind="{ ...api?.getArrowProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tooltip/TooltipArrowTip.vue">
{{ `
<script lang="ts" setup>
import { cn } from "@mykopkb/core/utils/cn";
import { tooltipArrowTip } from "@mykopkb/core/styles/tooltip.styles";
import { Slot } from "@/components/ui/slot";
import type { Api } from "@zag-js/tooltip";
import { inject } from "vue";
const {
class: className,
asChild = false,
...props
} = defineProps<{
class?: string;
asChild?: boolean;
}>();
const api = inject<Api>("tooltipApi");
</script>
<template>
<Slot :class="cn(tooltipArrowTip, className)" v-bind="{ ...api?.getArrowTipProps(), ...props, ...$attrs }">
<slot v-if="asChild" />
<div v-else>
<slot />
</div>
</Slot>
</template>
` }}
</PreviewCode>
<PreviewCode title="components/ui/tooltip/index.ts">
{{ `
export { default as TooltipRoot } from "./TooltipRoot.vue";
export { default as TooltipTrigger } from "./TooltipTrigger.vue";
export { default as TooltipPositioner } from "./TooltipPositioner.vue";
export { default as TooltipContent } from "./TooltipContent.vue";
export { default as TooltipArrow } from "./TooltipArrow.vue";
export { default as TooltipArrowTip } from "./TooltipArrowTip.vue";
` }}
</PreviewCode>
<SectionContent>
Update the import paths to match your project setup.
</SectionContent>
</div>
<div id="usage">
<SectionTitle>Usage</SectionTitle>
<PreviewCode>
{{ `
import {
TooltipRoot,
TooltipTrigger,
TooltipPositioner,
TooltipContent,
} from "@/components/ui/tooltip";
` }}
</PreviewCode>
<PreviewCode>
{{ `
<TooltipRoot>
<TooltipTrigger>Hover Me</TooltipTrigger>
<TooltipPositioner>
<TooltipContent>I am a tooltip!</TooltipContent>
</TooltipPositioner>
</TooltipRoot>
` }}
</PreviewCode>
</div>
</template>