UNPKG

ui-thing

Version:

CLI used to add Nuxt 3 components to a project

341 lines 518 kB
export default [ { name: "Accordion", value: "accordion", instructions: ["Remember to add the accordion animations to your tailwind.config.js"], files: [ { fileName: "Accordion/Accordion.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AccordionRoot v-slot="rootSlotProps" v-bind="forwarded">\n <slot v-bind="rootSlotProps" :items="items">\n <template v-for="(item, i) in items" :key="i">\n <UiAccordionItem v-slot="itemSlotProps" :disabled="item.disabled" :value="item.value">\n <slot v-bind="{ ...itemSlotProps, ...rootSlotProps, items, item }" name="header">\n <UiAccordionHeader>\n <slot v-bind="{ ...itemSlotProps, ...rootSlotProps, items, item }" name="trigger">\n <UiAccordionTrigger :title="item.title" :icon="item.icon" />\n </slot>\n </UiAccordionHeader>\n </slot>\n <slot name="content" v-bind="{ ...itemSlotProps, ...rootSlotProps, items, item }">\n <UiAccordionContent :content="item.content" />\n </slot>\n </UiAccordionItem>\n </template>\n </slot>\n </AccordionRoot>\n</template>\n\n<script setup lang="ts">\n import { AccordionRoot, useForwardPropsEmits } from "radix-vue";\n import type { AccordionRootEmits, AccordionRootProps } from "radix-vue";\n\n export interface AccordionItem {\n title?: string;\n content?: string;\n value: string;\n disabled?: boolean;\n icon?: string;\n [key: string]: any;\n }\n\n const props = withDefaults(\n defineProps<\n AccordionRootProps & {\n items?: AccordionItem[];\n }\n >(),\n { type: "single", collapsible: true, items: () => [] }\n );\n\n const emits = defineEmits<AccordionRootEmits>();\n const forwarded = useForwardPropsEmits(reactiveOmit(props, "items"), emits);\n</script>\n', }, { fileName: "Accordion/Content.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AccordionContent v-bind="forwarded" :class="styles({ class: props.class })">\n <div class="pb-4 pt-0">\n <slot>{{ content }}</slot>\n </div>\n </AccordionContent>\n</template>\n\n<script lang="ts" setup>\n import { AccordionContent } from "radix-vue";\n import type { AccordionContentProps } from "radix-vue";\n\n const props = defineProps<\n AccordionContentProps & {\n /** Custom class(es) to add to the parent */\n class?: any;\n /** The content of the accordion */\n content?: any;\n }\n >();\n\n const forwarded = reactiveOmit(props, "class", "content");\n\n const styles = tv({\n base: "overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",\n });\n</script>\n', }, { fileName: "Accordion/Header.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AccordionHeader v-bind="forwarded" :class="styles({ class: props.class })">\n <slot />\n </AccordionHeader>\n</template>\n\n<script lang="ts" setup>\n import { AccordionHeader } from "radix-vue";\n import type { AccordionHeaderProps } from "radix-vue";\n\n const props = defineProps<\n AccordionHeaderProps & {\n class?: any;\n }\n >();\n\n const forwarded = reactiveOmit(props, "class");\n\n const styles = tv({\n base: "flex",\n });\n</script>\n', }, { fileName: "Accordion/Item.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AccordionItem v-slot="slotProps" v-bind="forwarded" :class="styles({ class: props.class })">\n <slot v-bind="slotProps" />\n </AccordionItem>\n</template>\n\n<script setup lang="ts">\n import { AccordionItem } from "radix-vue";\n import type { AccordionItemProps } from "radix-vue";\n\n const props = defineProps<\n AccordionItemProps & {\n /** Custom class(es) to add to the parent */\n class?: any;\n }\n >();\n\n const forwarded = reactiveOmit(props, "class");\n\n const styles = tv({\n base: "border-b",\n });\n</script>\n', }, { fileName: "Accordion/Trigger.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AccordionTrigger v-bind="forwarded" :class="styles({ class: props.class })">\n <slot :props="props">\n {{ title }}\n </slot>\n <slot name="icon" :props="props">\n <Icon\n v-if="icon"\n mode="svg"\n :name="icon"\n class="h-4 w-4 shrink-0 transition-transform duration-200"\n />\n </slot>\n </AccordionTrigger>\n</template>\n\n<script lang="ts" setup>\n import { AccordionTrigger } from "radix-vue";\n import type { AccordionTriggerProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n AccordionTriggerProps & {\n /** Custom class(es) to add to the parent */\n class?: any;\n /** The title of the accordion trigger */\n title?: string;\n /** The icon to show next to the title */\n icon?: string;\n }\n >(),\n {\n class: undefined,\n title: "",\n icon: "lucide:chevron-down",\n }\n );\n\n const forwarded = reactiveOmit(props, "class", "icon", "title");\n\n const styles = tv({\n base: "flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline focus-visible:rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background [&[data-state=open]>svg]:rotate-180",\n });\n</script>\n', }, ], utils: [], composables: [], plugins: [], }, { name: "Alert", value: "alert", devDeps: ["@vueuse/core"], files: [ { fileName: "Alert/Alert.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <div v-if="shown" :class="styles().base({ variant, filled, class: props.class })">\n <slot :props="props" name="icon">\n <Icon\n v-if="icon"\n :name="icon"\n :class="styles().icon({ variant, filled, class: props.iconClass })"\n />\n </slot>\n <div :class="styles().content({ variant, filled })">\n <slot :props="props">\n <slot name="title">\n <UiAlertTitle v-if="title" :title="title" />\n </slot>\n <slot name="description">\n <UiAlertDescription v-if="description" :description="description" />\n </slot>\n </slot>\n </div>\n </div>\n</template>\n\n<script lang="ts" setup>\n const props = withDefaults(\n defineProps<{\n /** Custom class to add to the `Alert` parent */\n class?: any;\n /** Classes to add to the icon */\n iconClass?: any;\n /** Whether the alert should have a filled/colored background */\n filled?: boolean;\n /**\n * Whether or not the `Alert` is shown.\n * @default true\n */\n modelValue?: boolean;\n /** The variant of the `Alert` */\n variant?: VariantProps<typeof styles>["variant"];\n /** The title that is passed to the `AlertTitle` component */\n title?: string;\n /** The description that is passed to the `AlertDescription` component */\n description?: string;\n /** The icon that should be displayed*/\n icon?: string;\n }>(),\n {\n modelValue: true,\n variant: "default",\n }\n );\n\n const shown = defineModel<boolean>({ default: true });\n\n const styles = tv({\n slots: {\n base: "relative flex w-full gap-3 rounded-lg border p-4",\n icon: "size-4 shrink-0",\n content: "grow",\n },\n variants: {\n variant: {\n default: {\n base: "bg-background text-foreground",\n icon: "text-foreground",\n },\n destructive: {\n base: "border-destructive/50 text-destructive dark:border-destructive",\n icon: "text-destructive",\n },\n info: {\n base: "border-blue-500/50 text-blue-600",\n icon: "text-blue-600",\n },\n success: {\n base: "border-emerald-500/50 text-emerald-600",\n icon: "text-emerald-500",\n },\n warning: {\n base: "border-amber-500/50 text-amber-600",\n icon: "text-amber-600",\n },\n },\n filled: {\n true: {},\n },\n },\n defaultVariants: {\n variant: "default",\n filled: false,\n },\n compoundVariants: [\n {\n filled: true,\n variant: "default",\n class: { base: "bg-muted/50 text-foreground", icon: "text-foreground" },\n },\n {\n filled: true,\n variant: "destructive",\n class: {\n base: "bg-destructive text-destructive-foreground",\n icon: "text-destructive-foreground",\n },\n },\n {\n filled: true,\n variant: "info",\n class: { base: "bg-blue-500 text-blue-50", icon: "text-blue-50" },\n },\n {\n filled: true,\n variant: "success",\n class: { base: "bg-emerald-500 text-emerald-50", icon: "text-emerald-50" },\n },\n {\n filled: true,\n variant: "warning",\n class: { base: "bg-amber-500 text-amber-50", icon: "text-amber-50" },\n },\n ],\n });\n</script>\n', }, { fileName: "Alert/Description.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <Primitive v-bind="forwarded" :class="styles({ class: props.class })">\n <slot>{{ description }}</slot>\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { Primitive } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class to add to the parent */\n class?: any;\n /** The description text that should be displayed */\n description?: string;\n }\n >(),\n { as: "div", class: undefined, description: undefined }\n );\n\n const forwarded = reactiveOmit(props, "class", "description");\n\n const styles = tv({\n base: "text-sm [&_p]:leading-relaxed",\n });\n</script>\n', }, { fileName: "Alert/Title.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <Primitive v-bind="forwarded" :class="styles({ class: props.class })">\n <slot>{{ title }}</slot>\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { Primitive } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class to add to the parent */\n class?: any;\n /** The title text that should be displayed */\n title?: string;\n }\n >(),\n { as: "h5", class: undefined, title: undefined }\n );\n\n const forwarded = reactiveOmit(props, "class", "title");\n\n const styles = tv({\n base: "mb-1 font-medium leading-none tracking-tight",\n });\n</script>\n', }, ], utils: [], composables: [], plugins: [], }, { name: "Alert Dialog", value: "alert-dialog", devDeps: ["@vueuse/core"], utils: [ { fileName: "shared.styles.ts", dirPath: "utils", fileContent: '// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "group inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n expandIcon: "group relative bg-primary text-primary-foreground hover:bg-primary/90",\n ringHover:\n "bg-primary text-primary-foreground transition-all duration-300 hover:bg-primary/90 hover:ring-2 hover:ring-primary/90 hover:ring-offset-2",\n shine:\n "animate-shine bg-gradient-to-r from-primary via-primary/75 to-primary bg-[length:400%_100%] text-primary-foreground",\n gooeyRight:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 before:absolute before:inset-0 before:-z-10 before:translate-x-[150%] before:translate-y-[150%] before:scale-[2.5] before:rounded-[100%] before:bg-gradient-to-r before:transition-transform before:duration-1000 hover:before:translate-x-[0%] hover:before:translate-y-[0%]",\n gooeyLeft:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 after:absolute after:inset-0 after:-z-10 after:translate-x-[-150%] after:translate-y-[150%] after:scale-[2.5] after:rounded-[100%] after:bg-gradient-to-l after:transition-transform after:duration-1000 hover:after:translate-x-[0%] hover:after:translate-y-[0%]",\n linkHover1:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-left after:scale-x-100 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-right hover:after:scale-x-0",\n linkHover2:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-right after:scale-x-0 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-left hover:after:scale-x-100",\n },\n size: {\n xs: "h-8 px-2",\n sm: "h-9 px-3",\n default: "h-10 px-4 py-2",\n lg: "h-11 px-8",\n "icon-xs": "h-8 w-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n hasIcon: {\n false: "gap-2",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n', }, ], files: [ { fileName: "AlertDialog/Action.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogAction\n v-bind="forwarded"\n :class="buttonStyles({ variant, size, disabled, class: props.class })"\n >\n <slot>{{ text }} </slot>\n </AlertDialogAction>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogAction } from "radix-vue";\n import type { AlertDialogActionProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n AlertDialogActionProps & {\n /** Action to perform when the button is clicked */\n onClick?: () => void;\n /** Text to display in the button */\n text?: string;\n /** Custom class(es) to add to the button */\n class?: any;\n /** Whether the button is disabled */\n disabled?: boolean;\n /** The button\'s visual variant */\n variant?: VariantProps<typeof buttonStyles>["variant"];\n /** The button\'s visual size */\n size?: VariantProps<typeof buttonStyles>["size"];\n }\n >(),\n {\n text: "Continue",\n variant: "default",\n size: "default",\n class: undefined,\n onClick: undefined,\n }\n );\n\n const forwarded = reactiveOmit(props, "class", "text", "variant", "size");\n</script>\n', }, { fileName: "AlertDialog/AlertDialog.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogRoot v-bind="forwarded">\n <slot>\n <slot name="trigger">\n <UiAlertDialogTrigger v-if="triggerText" as-child>\n <UiButton variant="outline">{{ triggerText }}</UiButton>\n </UiAlertDialogTrigger>\n </slot>\n <slot name="content">\n <UiAlertDialogContent>\n <slot name="header">\n <UiAlertDialogHeader>\n <slot name="title">\n <UiAlertDialogTitle v-if="title" :title="title" />\n </slot>\n <slot name="description">\n <UiAlertDialogDescription v-if="description" :description="description" />\n </slot>\n </UiAlertDialogHeader>\n </slot>\n <slot name="footer">\n <UiAlertDialogFooter>\n <slot name="cancel">\n <UiAlertDialogCancel />\n </slot>\n <slot name="action">\n <UiAlertDialogAction />\n </slot>\n </UiAlertDialogFooter>\n </slot>\n </UiAlertDialogContent>\n </slot>\n </slot>\n </AlertDialogRoot>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogRoot, useForwardPropsEmits } from "radix-vue";\n import type { AlertDialogEmits, AlertDialogProps } from "radix-vue";\n\n const props = defineProps<\n AlertDialogProps & {\n /** Text to display in the trigger button */\n triggerText?: string;\n /** Text to be passed to the `AlertDialogTitle` */\n title?: string;\n /** Text to be passed to the `AlertDialogDescription` */\n description?: string;\n }\n >();\n\n const emits = defineEmits<AlertDialogEmits>();\n\n const forwarded = useForwardPropsEmits(\n reactiveOmit(props, "description", "title", "triggerText"),\n emits\n );\n</script>\n', }, { fileName: "AlertDialog/Cancel.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogCancel\n v-bind="forwarded"\n :class="buttonStyles({ variant, size, disabled, class: props.class })"\n >\n <slot>{{ text }}</slot>\n </AlertDialogCancel>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogCancel } from "radix-vue";\n import type { AlertDialogCancelProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n AlertDialogCancelProps & {\n /** Action to perform when the button is clicked */\n onClick?: () => void;\n /** Text to display in the button */\n text?: string;\n /** Custom class(es) to add to the button */\n class?: any;\n /** Whether the button is disabled */\n disabled?: boolean;\n /** The button\'s visual variant */\n variant?: VariantProps<typeof buttonStyles>["variant"];\n /** The button\'s visual size */\n size?: VariantProps<typeof buttonStyles>["size"];\n }\n >(),\n {\n text: "Cancel",\n variant: "outline",\n size: "default",\n class: undefined,\n onClick: undefined,\n }\n );\n\n const forwarded = reactiveOmit(props, "class", "text", "variant", "size");\n</script>\n', }, { fileName: "AlertDialog/Content.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <UiAlertDialogPortal :to="to">\n <slot name="overlay">\n <UiAlertDialogOverlay />\n </slot>\n <AlertDialogContent\n :class="styles({ class: props.class })"\n v-bind="{ ...forwarded, ...$attrs }"\n >\n <slot />\n </AlertDialogContent>\n </UiAlertDialogPortal>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogContent, useForwardPropsEmits } from "radix-vue";\n import type { AlertDialogContentEmits, AlertDialogContentProps } from "radix-vue";\n\n defineOptions({ inheritAttrs: false });\n\n const props = defineProps<\n AlertDialogContentProps & {\n /** Custom class(es) to add to the `AlertDialogContent` */\n class?: any;\n /** The element to render the portal into */\n to?: string | HTMLElement;\n }\n >();\n const emit = defineEmits<AlertDialogContentEmits>();\n const forwarded = useForwardPropsEmits(reactiveOmit(props, "class", "to"), emit);\n\n const styles = tv({\n base: "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",\n });\n</script>\n', }, { fileName: "AlertDialog/Description.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogDescription v-bind="forwarded" :class="styles({ class: props.class })">\n <slot>{{ description }}</slot>\n </AlertDialogDescription>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogDescription } from "radix-vue";\n import type { AlertDialogDescriptionProps } from "radix-vue";\n\n const props = defineProps<\n AlertDialogDescriptionProps & {\n /** Text to display in the description */\n description?: string;\n /** Custom class(es) to add to the description */\n class?: any;\n }\n >();\n\n const forwarded = reactiveOmit(props, "class", "description");\n\n const styles = tv({\n base: "text-sm text-muted-foreground",\n });\n</script>\n', }, { fileName: "AlertDialog/Footer.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <Primitive :class="styles({ class: props.class })" v-bind="forwarded">\n <slot />\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { Primitive } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class(es) to add to the element */\n class?: any;\n }\n >(),\n {\n as: "div",\n class: undefined,\n }\n );\n\n const forwarded = reactiveOmit(props, "class");\n const styles = tv({\n base: "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",\n });\n</script>\n', }, { fileName: "AlertDialog/Header.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <Primitive :class="styles({ class: props.class })" v-bind="forwarded">\n <slot />\n </Primitive>\n</template>\n\n<script lang="ts" setup>\n import { Primitive } from "radix-vue";\n import type { PrimitiveProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n PrimitiveProps & {\n /** Custom class(es) to add to the element */\n class?: any;\n }\n >(),\n {\n as: "div",\n class: undefined,\n }\n );\n const forwarded = reactiveOmit(props, "class");\n const styles = tv({\n base: "flex flex-col gap-2 text-center sm:text-left",\n });\n</script>\n', }, { fileName: "AlertDialog/Overlay.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogOverlay v-bind="forwarded" :class="styles({ class: props.class })" />\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogOverlay } from "radix-vue";\n import type { AlertDialogOverlayProps } from "radix-vue";\n\n const props = defineProps<\n AlertDialogOverlayProps & {\n /** Custom class(es) to add to the overlay */\n class?: any;\n }\n >();\n const forwarded = reactiveOmit(props, "class");\n const styles = tv({\n base: "fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=closed]:animate-fadeOut data-[state=open]:animate-fadeIn",\n });\n</script>\n', }, { fileName: "AlertDialog/Portal.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogPortal v-bind="props">\n <slot />\n </AlertDialogPortal>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogPortal } from "radix-vue";\n import type { AlertDialogPortalProps } from "radix-vue";\n\n const props = defineProps<AlertDialogPortalProps>();\n</script>\n', }, { fileName: "AlertDialog/Title.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogTitle v-bind="forwarded" :class="styles({ class: props.class })">\n <slot>{{ title }}</slot>\n </AlertDialogTitle>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogTitle } from "radix-vue";\n import type { AlertDialogTitleProps } from "radix-vue";\n\n const props = defineProps<\n AlertDialogTitleProps & {\n /** Text to display in the title */\n title?: string;\n /** Custom class(es) to add to the title */\n class?: any;\n }\n >();\n const forwarded = reactiveOmit(props, "class", "title");\n const styles = tv({\n base: "text-lg font-semibold",\n });\n</script>\n', }, { fileName: "AlertDialog/Trigger.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AlertDialogTrigger v-bind="props">\n <slot />\n </AlertDialogTrigger>\n</template>\n\n<script lang="ts" setup>\n import { AlertDialogTrigger } from "radix-vue";\n import type { AlertDialogTriggerProps } from "radix-vue";\n\n const props = defineProps<AlertDialogTriggerProps>();\n</script>\n', }, ], composables: [], plugins: [], }, { name: "Aspect Ratio", value: "aspect-ratio", files: [ { fileName: "AspectRatio.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AspectRatio v-bind="props">\n <slot />\n </AspectRatio>\n</template>\n\n<script lang="ts" setup>\n import { AspectRatio } from "radix-vue";\n import type { AspectRatioProps } from "radix-vue";\n\n const props = defineProps<AspectRatioProps>();\n</script>\n', }, ], utils: [], composables: [], plugins: [], }, { name: "Autocomplete", value: "autocomplete", devDeps: ["@vueuse/core"], files: [ { fileName: "Autocomplete/Anchor.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxAnchor v-bind="props" :class="styles({ class: props.class })">\n <slot />\n </ComboboxAnchor>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxAnchor } from "radix-vue";\n import type { ComboboxAnchorProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxAnchorProps & {\n class?: any;\n }\n >();\n\n const styles = tv({\n base: "flex h-10 w-full items-center rounded-md border border-input bg-background px-3 py-2 ring-offset-background focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",\n });\n</script>\n', }, { fileName: "Autocomplete/Arrow.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxArrow v-bind="props" :class="styles({ class: props.class })" />\n</template>\n\n<script lang="ts" setup>\n import { ComboboxArrow } from "radix-vue";\n import type { ComboboxArrowProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxArrowProps & {\n class?: any;\n }\n >();\n\n const styles = tv({\n base: "rotate-45 border bg-muted",\n });\n</script>\n', }, { fileName: "Autocomplete/Autocomplete.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxRoot v-bind="forwarded" :class="styles({ class: props.class })">\n <slot />\n </ComboboxRoot>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxRoot, useForwardPropsEmits } from "radix-vue";\n import type { ComboboxRootEmits, ComboboxRootProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxRootProps & {\n class?: any;\n }\n >();\n\n const emits = defineEmits<ComboboxRootEmits>();\n const forwarded = useForwardPropsEmits(reactiveOmit(props, "class"), emits);\n const styles = tv({\n base: "relative",\n });\n</script>\n', }, { fileName: "Autocomplete/Cancel.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxCancel v-bind="props">\n <slot />\n </ComboboxCancel>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxCancel } from "radix-vue";\n import type { ComboboxCancelProps } from "radix-vue";\n\n const props = defineProps<ComboboxCancelProps>();\n</script>\n', }, { fileName: "Autocomplete/Content.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <!-- <UiAutocompletePortal> -->\n <ComboboxContent v-bind="forwarded" :class="styles({ class: props.class })">\n <UiAutocompleteViewport>\n <slot />\n </UiAutocompleteViewport>\n </ComboboxContent>\n <!-- </UiAutocompletePortal> -->\n</template>\n\n<script lang="ts" setup>\n import { ComboboxContent, useForwardPropsEmits } from "radix-vue";\n import type { ComboboxContentEmits, ComboboxContentProps } from "radix-vue";\n\n defineOptions({ inheritAttrs: false });\n const props = withDefaults(\n defineProps<\n ComboboxContentProps & {\n class?: any;\n }\n >(),\n {\n position: "popper",\n bodyLock: true,\n side: "bottom",\n sideOffset: 8,\n class: undefined,\n }\n );\n\n const emits = defineEmits<ComboboxContentEmits>();\n const forwarded = useForwardPropsEmits(props, emits);\n\n const styles = tv({\n base: "z-50 max-h-[300px] w-[var(--radix-popper-anchor-width)] min-w-[8rem] overflow-hidden overflow-y-auto rounded-md border bg-popover p-1 text-accent-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",\n });\n</script>\n', }, { fileName: "Autocomplete/Empty.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxEmpty v-bind="props">\n <slot />\n </ComboboxEmpty>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxEmpty } from "radix-vue";\n import type { ComboboxEmptyProps } from "radix-vue";\n\n const props = defineProps<ComboboxEmptyProps>();\n</script>\n', }, { fileName: "Autocomplete/Group.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxGroup v-bind="props">\n <slot />\n </ComboboxGroup>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxGroup } from "radix-vue";\n import type { ComboboxGroupProps } from "radix-vue";\n\n const props = defineProps<ComboboxGroupProps>();\n</script>\n', }, { fileName: "Autocomplete/Input.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxInput v-bind="props" :class="styles({ class: props.class })" />\n</template>\n\n<script lang="ts" setup>\n import { ComboboxInput } from "radix-vue";\n import type { ComboboxInputProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxInputProps & {\n placeholder?: string;\n class?: any;\n }\n >();\n\n const styles = tv({\n base: "size-full grow rounded-md bg-background placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 sm:text-sm",\n });\n</script>\n', }, { fileName: "Autocomplete/Item.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxItem v-bind="forwarded" :class="styles({ class: props.class })">\n <slot name="icon">\n <span class="absolute inset-y-0 left-2 flex items-center justify-center">\n <UiAutocompleteItemIndicator class="animate-in fade-in-0 zoom-in-0" :icon="icon" />\n </span>\n </slot>\n <slot />\n </ComboboxItem>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxItem, useForwardPropsEmits } from "radix-vue";\n import type { ComboboxItemEmits, ComboboxItemProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxItemProps & {\n class?: any;\n icon?: string;\n }\n >();\n\n const emits = defineEmits<{\n select: ComboboxItemEmits["select"];\n }>();\n const forwarded = useForwardPropsEmits(props, emits);\n\n const styles = tv({\n base: "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 pl-9 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",\n });\n</script>\n', }, { fileName: "Autocomplete/ItemIndicator.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxItemIndicator v-bind="props">\n <slot><Icon :name="icon || \'ph:check\'" class="h-4 w-4" /></slot>\n </ComboboxItemIndicator>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxItemIndicator } from "radix-vue";\n import type { ComboboxItemIndicatorProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxItemIndicatorProps & {\n icon?: string;\n }\n >();\n</script>\n', }, { fileName: "Autocomplete/Label.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxLabel :class="styles({ class: props.class })" v-bind="props">\n <slot />\n </ComboboxLabel>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxLabel } from "radix-vue";\n import type { ComboboxLabelProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxLabelProps & {\n class?: any;\n }\n >();\n\n const styles = tv({\n base: "px-2 py-1.5 pl-9 text-sm font-medium text-muted-foreground",\n });\n</script>\n', }, { fileName: "Autocomplete/Portal.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxPortal position="popper" v-bind="props">\n <slot />\n </ComboboxPortal>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxPortal } from "radix-vue";\n import type { ComboboxPortalProps } from "radix-vue";\n\n const props = defineProps<ComboboxPortalProps>();\n</script>\n', }, { fileName: "Autocomplete/Separator.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxSeparator v-bind="props">\n <slot />\n </ComboboxSeparator>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxSeparator } from "radix-vue";\n import type { ComboboxSeparatorProps } from "radix-vue";\n\n const props = defineProps<ComboboxSeparatorProps>();\n</script>\n', }, { fileName: "Autocomplete/Trigger.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxTrigger v-bind="forwarded" :class="styles({ class: props.class })">\n <slot />\n </ComboboxTrigger>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxTrigger } from "radix-vue";\n import type { ComboboxTriggerProps } from "radix-vue";\n\n const props = defineProps<\n ComboboxTriggerProps & {\n class?: any;\n }\n >();\n const forwarded = reactiveOmit(props, "class");\n const styles = tv({\n base: "inline-flex shrink-0 cursor-pointer items-center justify-center",\n });\n</script>\n', }, { fileName: "Autocomplete/Viewport.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <ComboboxViewport v-bind="props">\n <slot />\n </ComboboxViewport>\n</template>\n\n<script lang="ts" setup>\n import { ComboboxViewport } from "radix-vue";\n import type { ComboboxViewportProps } from "radix-vue";\n\n const props = defineProps<ComboboxViewportProps>();\n</script>\n', }, ], utils: [], composables: [], plugins: [], }, { name: "Avatar", value: "avatar", files: [ { fileName: "Avatar/Avatar.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AvatarRoot :as="as" :as-child="asChild" :class="styles({ class: props.class })">\n <slot>\n <slot name="image">\n <UiAvatarImage\n v-if="src"\n :src="src"\n :alt="alt"\n :class="imageClass"\n @loading-status-change="emits(\'loadingStatusChange\', $event)"\n />\n </slot>\n <slot name="fallback">\n <UiAvatarFallback :delay-ms="delayMs" :class="fallbackClass" :fallback="fallback" />\n </slot>\n </slot>\n </AvatarRoot>\n</template>\n\n<script lang="ts" setup>\n import { AvatarRoot } from "radix-vue";\n import type { AvatarImageEmits, AvatarImageProps, AvatarRootProps } from "radix-vue";\n\n const props = withDefaults(\n defineProps<\n AvatarRootProps &\n Partial<AvatarImageProps> & {\n class?: any;\n imageClass?: any;\n fallbackClass?: any;\n alt?: string;\n fallback?: string;\n delayMs?: number;\n }\n >(),\n {\n class: undefined,\n imageClass: undefined,\n fallbackClass: undefined,\n alt: undefined,\n fallback: undefined,\n delayMs: undefined,\n }\n );\n\n const emits = defineEmits<AvatarImageEmits>();\n const styles = tv({\n base: "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",\n });\n</script>\n', }, { fileName: "Avatar/Fallback.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AvatarFallback :class="styles({ class: props.class })" v-bind="forwarded">\n <slot>\n {{ fallback }}\n </slot>\n </AvatarFallback>\n</template>\n\n<script lang="ts" setup>\n import { AvatarFallback } from "radix-vue";\n import type { AvatarFallbackProps } from "radix-vue";\n\n const props = defineProps<\n AvatarFallbackProps & {\n /** The text to display inside th eavatar */\n fallback?: string;\n /** Custom class(es) to add to the element */\n class?: any;\n }\n >();\n const forwarded = reactiveOmit(props, "class", "fallback");\n const styles = tv({\n base: "flex h-full w-full items-center justify-center rounded-[inherit] bg-muted font-medium",\n });\n</script>\n', }, { fileName: "Avatar/Image.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <AvatarImage v-bind="forwarded" :class="styles({ class: props.class })" />\n</template>\n\n<script lang="ts" setup>\n import { AvatarImage, useForwardPropsEmits } from "radix-vue";\n import type { AvatarImageEmits, AvatarImageProps } from "radix-vue";\n\n const props = defineProps<\n AvatarImageProps & {\n /** The alt text for the image */\n alt?: string;\n /** Custom class(es) to add to the element */\n class?: any;\n }\n >();\n const emits = defineEmits<AvatarImageEmits>();\n\n const forwarded = useForwardPropsEmits(reactiveOmit(props, "class"), emits);\n\n const styles = tv({\n base: "aspect-square h-full w-full object-cover",\n });\n</script>\n', }, ], utils: [], composables: [], plugins: [], }, { name: "Badge", value: "badge", files: [ { fileName: "Badge.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <component\n :is="elementType"\n :class="badgeVariants({ disabled, size, variant, class: props.class })"\n v-bind="forwarded"\n @click="onClick"\n >\n <slot />\n </component>\n</template>\n\n<script lang="ts">\n import { reactiveOmit } from "@vueuse/core";\n import { useForwardProps } from "radix-vue";\n import type { NuxtLinkProps } from "#app/components";\n</script>\n<script lang="ts" setup>\n const badgeVariants = tv({\n base: "inline-flex items-center rounded-full border font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",\n variants: {\n variant: {\n default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",\n secondary:\n "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",\n destructive:\n "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",\n outline: "text-foreground",\n },\n disabled: {\n true: "cursor-not-allowed opacity-50",\n },\n size: {\n sm: "px-2.5 py-0.5 text-xs font-medium",\n md: "px-2.5 py-1 text-sm font-semibold",\n lg: "px-3 py-1.5 text-sm font-semibold",\n },\n },\n defaultVariants: {\n variant: "default",\n disabled: false,\n size: "sm",\n },\n });\n\n type BadgeProps = VariantProps<typeof badgeVariants>;\n\n const props = defineProps<\n NuxtLinkProps & {\n /** Any additional class that should be added to the badge */\n class?: any;\n /** The variant of the badge */\n variant?: BadgeProps["variant"];\n /** The size of the badge */\n size?: BadgeProps["size"];\n /** The action to perform when the badge is clicked */\n onClick?: () => void;\n /** Should the badge be disabled or not */\n disabled?: boolean;\n /** The element to render the badge as */\n tag?: string;\n }\n >();\n\n const forwarded = useForwardProps(reactiveOmit(props, "class", "variant", "onClick", "disabled"));\n\n const elementType = computed(() => {\n if (props.tag) return props.tag;\n if (props.href || props.to) return resolveComponent("NuxtLink");\n if (props.onClick) return "button";\n return props.tag || "div";\n });\n</script>\n', }, ], utils: [], composables: [], plugins: [], }, { name: "Breadcrumbs", value: "breadcrumbs", files: [ { fileName: "Breadcrumbs.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <div :class="styles({ class: props.class })">\n <template v-for="(item, i) in items" :key="i">\n <slot :name="item.slot || \'default\'">\n <div class="flex items-center gap-3">\n <div class="group flex items-center gap-2">\n <slot name="crumbIcon" :item="item" :index="i">\n <Icon\n v-if="item.icon"\n :name="item.icon"\n :class="[\n isNotLastItem(i)\n ? \'text-muted-foreground group-hover:text-foreground\'\n : \'text-primary\',\n ]"\n />\n </slot>\n <slot :item="item" :is-not-last-item="isNotLastItem" :index="i" name="link">\n <NuxtLink\n v-if="item.label"\n :to="!item?.disabled ? item.link : \'\'"\n :class="[\n item.link && !item.disabled && \'underline-offset-2 group-hover:underline\',\n isNotLastItem(i)\n ? \'text-muted-foreground group-hover:text-foreground\'\n : \'font-semibold text-primary\',\n ]"\n class="text-sm text-foreground transition-colors"\n @click="item?.click?.()"\n >{{ item.label }}</NuxtLink\n >\n </slot>\n </div>\n </div>\n </slot>\n <slot name="separator" :item="item" :index="i">\n <Icon v-if="isNotLastItem(i)" :name="separator" class="h-3 w-3 text-muted-foreground" />\n </slot>\n </template>\n </div>\n</template>\n\n<script setup lang="ts">\n export interface Crumbs {\n label?: string;\n icon?: string;\n link?: string;\n disabled?: boolean;\n slot?: string;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n click?: Function;\n }\n const props = withDefaults(\n defineProps<{\n /**\n * The items to display in the breadcrumbs.\n */\n items?: Crumbs[];\n /**\n * The separator to use between each breadcrumb.\n */\n separator?: string;\n class?: any;\n }>(),\n {\n separator: "heroicons:chevron-right",\n items: () => [],\n class: undefined,\n }\n );\n\n const isNotLastItem = (index: number) => {\n return index !== props?.items?.length - 1;\n };\n\n const styles = tv({\n base: "flex w-full items-center gap-4",\n });\n</script>\n', }, ], utils: [], composables: [], plugins: [], }, { name: "Button", value: "button", utils: [ { fileName: "shared.styles.ts", dirPath: "utils", fileContent: '// Add here because button styles are used in several components\nexport const buttonStyles = tv({\n base: "group inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",\n variants: {\n variant: {\n default: "bg-primary text-primary-foreground hover:bg-primary/90",\n destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",\n outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",\n secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",\n ghost: "hover:bg-accent hover:text-accent-foreground",\n link: "text-primary underline-offset-4 hover:underline",\n expandIcon: "group relative bg-primary text-primary-foreground hover:bg-primary/90",\n ringHover:\n "bg-primary text-primary-foreground transition-all duration-300 hover:bg-primary/90 hover:ring-2 hover:ring-primary/90 hover:ring-offset-2",\n shine:\n "animate-shine bg-gradient-to-r from-primary via-primary/75 to-primary bg-[length:400%_100%] text-primary-foreground",\n gooeyRight:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 before:absolute before:inset-0 before:-z-10 before:translate-x-[150%] before:translate-y-[150%] before:scale-[2.5] before:rounded-[100%] before:bg-gradient-to-r before:transition-transform before:duration-1000 hover:before:translate-x-[0%] hover:before:translate-y-[0%]",\n gooeyLeft:\n "relative z-0 overflow-hidden bg-primary from-primary-foreground/40 text-primary-foreground transition-all duration-500 after:absolute after:inset-0 after:-z-10 after:translate-x-[-150%] after:translate-y-[150%] after:scale-[2.5] after:rounded-[100%] after:bg-gradient-to-l after:transition-transform after:duration-1000 hover:after:translate-x-[0%] hover:after:translate-y-[0%]",\n linkHover1:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-left after:scale-x-100 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-right hover:after:scale-x-0",\n linkHover2:\n "relative after:absolute after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-right after:scale-x-0 after:bg-primary after:transition-transform after:duration-300 after:ease-in-out hover:after:origin-bottom-left hover:after:scale-x-100",\n },\n size: {\n xs: "h-8 px-2",\n sm: "h-9 px-3",\n default: "h-10 px-4 py-2",\n lg: "h-11 px-8",\n "icon-xs": "h-8 w-8",\n "icon-sm": "h-9 w-9",\n icon: "h-10 w-10",\n },\n disabled: {\n true: "pointer-events-none opacity-50",\n },\n hasIcon: {\n false: "gap-2",\n },\n },\n defaultVariants: {\n variant: "default",\n size: "default",\n },\n});\n', }, ], files: [ { fileName: "Button.vue", dirPath: "app/components/Ui", fileContent: '<template>\n <component\n :is="elementType"\n :class="\n buttonStyles({\n hasIcon: !!icon,\n disabled: disabled || loading,\n variant: variant,\n size: size,\n class: props.class,\n })\n "\n :disabled="disabled || loading"\n v-bind="forwarded"\n >\n <slot name="iconLeft">\n <div\n v-if="icon && iconPlacement == \'left\'"\n class="group-hover:translate-x-100 flex w-0 shrink-0 translate-x-[0%] items-center justify-center pr-0 opacity-0 transition-all duration-200 group-hover:w-6 group-hover:pr-2 group-hover:opacity-100"\n >\n <Icon :name="icon" class="size-5" />\n </div>\n </slot>\n <slot name="loading">\n <Icon v-if="loading" class="size-4 shrink-0" :name="loadingIcon" />\n </slot>\n <slot>\n <span v-if="text">{{ text }}</span>\n </slot>\n <slot name="iconRight">\n <div\n v-if="icon && iconPlacement == \'right\'"\n class="flex w-0 shrink-0 translate-x-[100%] items-center justify-center pl-0 opacity-0 transition-all duration-200 group-hover:w-6 group-hover:translate-x-0 group-hover:pl-2 group-hover:opacity-100"\n >\n <Icon :name="icon" class="size-5" />\n </div>\n </slot>\n </component>\n</template>\n\n<script setup lang="ts">\n import { reactiveOmit } from "@vueuse/core";\n import { useForwardProps }