first init
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user