refactor: poc using radix-vue
This commit is contained in:
parent
f70bef32b2
commit
f540d332fb
13
.eslintrc.cjs
Normal file
13
.eslintrc.cjs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
const process = require('node:process')
|
||||||
|
|
||||||
|
process.env.ESLINT_TSCONFIG = 'tsconfig.json'
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
extends: '@antfu',
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
'symbol-description': 'off',
|
||||||
|
'no-console': 'warn',
|
||||||
|
'no-tabs': 'off',
|
||||||
|
},
|
||||||
|
}
|
||||||
37
package.json
Normal file
37
package.json
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"name": "shadcn-vue",
|
||||||
|
"private": true,
|
||||||
|
"packageManager": "pnpm@8.6.3",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "radix-vue/shadcn-vue",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev": "pnpm --filter shadcn-vue dev",
|
||||||
|
"prepare": "pnpm simple-git-hooks",
|
||||||
|
"lint": "eslint . --ignore-path .gitignore",
|
||||||
|
"lint:fix": "eslint . --fix --ignore-path .gitignore"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@antfu/eslint-config": "^0.39.7",
|
||||||
|
"@commitlint/cli": "^17.7.1",
|
||||||
|
"@commitlint/config-conventional": "^17.7.0",
|
||||||
|
"eslint": "^8.43.0",
|
||||||
|
"lint-staged": "^14.0.0",
|
||||||
|
"pnpm": "^8.6.12",
|
||||||
|
"simple-git-hooks": "^2.9.0"
|
||||||
|
},
|
||||||
|
"commitlint": {
|
||||||
|
"extends": [
|
||||||
|
"@commitlint/config-conventional"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"simple-git-hooks": {
|
||||||
|
"pre-commit": "pnpm lint-staged",
|
||||||
|
"commit-msg": "pnpm commitlint --edit ${1}"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*": "eslint --fix"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,32 +1,31 @@
|
||||||
{
|
{
|
||||||
"name": "radix-vue",
|
"name": "shadcn-vue",
|
||||||
|
"type": "module",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"files": [
|
|
||||||
"dist"
|
|
||||||
],
|
|
||||||
"main": "./dist/radix-vue.umd.js",
|
|
||||||
"module": "./dist/radix-vue.es.js",
|
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"import": "./dist/radix-vue.es.js",
|
"require": "./dist/radix-vue.umd.js",
|
||||||
"require": "./dist/radix-vue.umd.js"
|
"import": "./dist/radix-vue.es.js"
|
||||||
},
|
},
|
||||||
"./dist/style.css": "./dist/style.css"
|
"./dist/style.css": "./dist/style.css"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"main": "./dist/radix-vue.umd.js",
|
||||||
|
"module": "./dist/radix-vue.es.js",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc && vite build",
|
"build": "vue-tsc && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui-float/vue": "^0.11.2",
|
|
||||||
"@headlessui/vue": "^1.7.14",
|
|
||||||
"@morev/vue-transitions": "^2.3.6",
|
"@morev/vue-transitions": "^2.3.6",
|
||||||
"@vueuse/core": "^10.2.1",
|
"@vueuse/core": "^10.2.1",
|
||||||
"class-variance-authority": "^0.6.1",
|
"class-variance-authority": "^0.6.1",
|
||||||
"radix-vue": "^0.1.6",
|
"clsx": "^2.0.0",
|
||||||
"vue": "^3.2.47"
|
"radix-vue": "file:../../../radix-vue/packages/radix-vue",
|
||||||
|
"vue": "^3.3.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify/vue": "^4.1.1",
|
"@iconify/vue": "^4.1.1",
|
||||||
|
|
|
||||||
|
|
@ -1,394 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import AccordionDemo from './components/ui/AccordionDemo.vue'
|
||||||
import {
|
|
||||||
Accordion,
|
|
||||||
AccordionTrigger,
|
|
||||||
AccordionItem,
|
|
||||||
AccordionContent,
|
|
||||||
} from "./components/ui/Accordion";
|
|
||||||
import { Alert, AlertDescription, AlertTitle } from "./components/ui/Alert";
|
|
||||||
import { Card as InternalCard } from "./components/Internal/Docs/Card";
|
|
||||||
import { TransitionExpand } from "@morev/vue-transitions";
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
import { Button } from "./components/ui/Button";
|
|
||||||
import {
|
|
||||||
AlertDialog,
|
|
||||||
AlertDialogTitle,
|
|
||||||
AlertDialogHeader,
|
|
||||||
AlertDialogDescription,
|
|
||||||
AlertDialogFooter,
|
|
||||||
} from "./components/ui/AlertDialog";
|
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogTitle,
|
|
||||||
DialogHeader,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
} from "./components/ui/Dialog";
|
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from "./components/ui/Avatar";
|
|
||||||
import { Badge } from "./components/ui/Badge";
|
|
||||||
import { Checkbox } from "./components/ui/Checkbox";
|
|
||||||
import { Label } from "./components/ui/Label";
|
|
||||||
import { Input } from "./components/ui/Input";
|
|
||||||
import { Textarea } from "./components/ui/Textarea";
|
|
||||||
import { Switch } from "./components/ui/Switch";
|
|
||||||
import { Toggle } from "./components/ui/Toggle";
|
|
||||||
import { Card } from "./components/ui/Demos";
|
|
||||||
import { AspectRatio, Image } from "./components/ui/AspectRatio";
|
|
||||||
import {
|
|
||||||
Collapsible,
|
|
||||||
CollapsibleTrigger,
|
|
||||||
CollapsibleContent,
|
|
||||||
} from "./components/ui/Collapsible";
|
|
||||||
import { Select, SelectContent, SelectItem, SelectLabel, SelectTrigger } from "./components/ui/Select";
|
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "./components/ui/Popover";
|
|
||||||
import { Separator } from "./components/ui/Separator";
|
|
||||||
import { Tooltip, TooltipTrigger } from "./components/ui/Tooltip";
|
|
||||||
import { RadioGroup, RadioGroupItem } from "./components/ui/RadioGroup";
|
|
||||||
import AccordionDemo2 from "./components/uiv2/AccordionDemo.vue"
|
|
||||||
import SwitchDemo2 from "./components/uiv2/SwitchDemo.vue"
|
|
||||||
|
|
||||||
const alertDialogIsOpen = ref(false);
|
|
||||||
const dialogIsOpen = ref(false);
|
|
||||||
const enabled = ref(false);
|
|
||||||
const checkboxEnabled = ref(false);
|
|
||||||
const checkboxEnabled2 = ref(false);
|
|
||||||
const toggleEnabled = ref(false);
|
|
||||||
|
|
||||||
const people = [
|
|
||||||
{ id: 1, name: "Durward Reynolds", unavailable: false },
|
|
||||||
{ id: 2, name: "Kenton Towne", unavailable: false },
|
|
||||||
{ id: 3, name: "Therese Wunsch", unavailable: false },
|
|
||||||
{ id: 4, name: "Benedict Kessler", unavailable: true },
|
|
||||||
{ id: 5, name: "Katelyn Rohan", unavailable: false },
|
|
||||||
];
|
|
||||||
const selectedPerson = ref(people[0]);
|
|
||||||
|
|
||||||
const radioOptions = [
|
|
||||||
"Default",
|
|
||||||
"Comfortable",
|
|
||||||
"Compact",
|
|
||||||
];
|
|
||||||
|
|
||||||
const radioValue = ref(radioOptions[0]);
|
|
||||||
|
|
||||||
const components = [
|
|
||||||
"Accordion",
|
|
||||||
"Alert",
|
|
||||||
"Alert Dialog",
|
|
||||||
"Aspect Ratio",
|
|
||||||
"Avatar",
|
|
||||||
"Badge",
|
|
||||||
"Button",
|
|
||||||
"Calendar",
|
|
||||||
"Card",
|
|
||||||
"Checkbox",
|
|
||||||
"Collapsible",
|
|
||||||
"Combobox",
|
|
||||||
"Command",
|
|
||||||
"Context Menu",
|
|
||||||
"Data Table",
|
|
||||||
"Date Picker",
|
|
||||||
"Dialog",
|
|
||||||
"Dropdown Menu",
|
|
||||||
"Form",
|
|
||||||
"Hover Card",
|
|
||||||
"Input",
|
|
||||||
"Label",
|
|
||||||
"Menubar",
|
|
||||||
"Navigation Menu",
|
|
||||||
"Popover",
|
|
||||||
"Progress",
|
|
||||||
"Radio Group",
|
|
||||||
"Scroll Area",
|
|
||||||
"Select",
|
|
||||||
"Separator",
|
|
||||||
"Sheet",
|
|
||||||
"Skeleton",
|
|
||||||
"Slider",
|
|
||||||
"Switch",
|
|
||||||
"Table",
|
|
||||||
"Tabs",
|
|
||||||
"Textarea",
|
|
||||||
"Toast",
|
|
||||||
"Toggle",
|
|
||||||
"Tooltip",
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col items-center px-6 pb-6">
|
<div class="p-8">
|
||||||
<div class="mt-32 mb-16 w-full max-w-6xl flex flex-col items-center">
|
<AccordionDemo class="max-w-[20rem]" />
|
||||||
<h1 class="text-7xl font-bold mb-2">shadcn vue</h1>
|
|
||||||
<p class="text-md text-neutral-700">
|
|
||||||
This is a description of easy UI that has been remade over 10000 times.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex max-w-6xl">
|
|
||||||
<div class="w-[200px] pr-4">
|
|
||||||
<nav class="gap-0.5 flex flex-col text-sm sticky top-0 max-h-screen overflow-scroll">
|
|
||||||
<button v-for="(link, index) of components" :key="index"
|
|
||||||
:class="` group relative flex items-center gap-2.5 px-3 py-1.5 rounded-md text-gray-600 hover:text-black hover:bg-gray-200`">
|
|
||||||
<span :class="`truncate relative`">{{ link }}</span>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
||||||
<InternalCard title="Accordion">
|
|
||||||
<div class="w-full max-w-[400px]">
|
|
||||||
<Accordion>
|
|
||||||
<AccordionItem>
|
|
||||||
<AccordionTrigger> Is it accessible? </AccordionTrigger>
|
|
||||||
<transition-expand>
|
|
||||||
<AccordionContent>
|
|
||||||
Yes. It adheres to the WAI-ARIA design pattern.
|
|
||||||
</AccordionContent>
|
|
||||||
</transition-expand>
|
|
||||||
</AccordionItem>
|
|
||||||
<AccordionItem>
|
|
||||||
<AccordionTrigger> Is it styled? </AccordionTrigger>
|
|
||||||
<transition-expand>
|
|
||||||
<AccordionContent>
|
|
||||||
Yes. It comes with default styles that matches the other components'
|
|
||||||
aesthetic.
|
|
||||||
</AccordionContent>
|
|
||||||
</transition-expand>
|
|
||||||
</AccordionItem>
|
|
||||||
<AccordionItem>
|
|
||||||
<AccordionTrigger> Is it animated? </AccordionTrigger>
|
|
||||||
<transition-expand>
|
|
||||||
<AccordionContent>
|
|
||||||
Yes. It's animated by default, but you can disable it if you prefer.
|
|
||||||
</AccordionContent>
|
|
||||||
</transition-expand>
|
|
||||||
</AccordionItem>
|
|
||||||
</Accordion>
|
|
||||||
</div>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Accordionv22">
|
|
||||||
<AccordionDemo2 />
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Switchv2">
|
|
||||||
<SwitchDemo2 />
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Alert">
|
|
||||||
<div class="max-w-[400px]">
|
|
||||||
<Alert>
|
|
||||||
<Icon icon="lucide:terminal" class="h-4 w-4" />
|
|
||||||
<AlertTitle>Heads up!</AlertTitle>
|
|
||||||
<AlertDescription>
|
|
||||||
You can add components to your app using the cli.
|
|
||||||
</AlertDescription>
|
|
||||||
</Alert>
|
|
||||||
</div>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Alert Dialog">
|
|
||||||
<Button label="Open" @click="alertDialogIsOpen = true">Show Dialog</Button>
|
|
||||||
<AlertDialog v-model="alertDialogIsOpen">
|
|
||||||
<AlertDialogHeader>
|
|
||||||
<AlertDialogTitle>Title</AlertDialogTitle>
|
|
||||||
<AlertDialogDescription>
|
|
||||||
This action cannot be undone. This will permanently delete your account
|
|
||||||
and remove your data from our servers.
|
|
||||||
</AlertDialogDescription>
|
|
||||||
</AlertDialogHeader>
|
|
||||||
<AlertDialogFooter><Button variant="outline" @click="alertDialogIsOpen = false">Cancel</Button><Button>CTA
|
|
||||||
Button</Button>
|
|
||||||
</AlertDialogFooter>
|
|
||||||
</AlertDialog>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Aspect Ratio">
|
|
||||||
<AspectRatio :ratio="16 / 9" class="bg-muted">
|
|
||||||
<Image src="https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80"
|
|
||||||
alt="Photo by Drew Beamer" fill class="rounded-md object-cover" />
|
|
||||||
</AspectRatio>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Avatar">
|
|
||||||
<Avatar>
|
|
||||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
||||||
<AvatarFallback>CN</AvatarFallback>
|
|
||||||
</Avatar>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Badge">
|
|
||||||
<Badge>Badge</Badge>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Button">
|
|
||||||
<Button>Button</Button>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Calendar"></InternalCard>
|
|
||||||
<InternalCard title="Card">
|
|
||||||
<Card />
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Checkbox">
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<Checkbox id="terms" v-model="checkboxEnabled" />
|
|
||||||
<label htmlFor="terms"
|
|
||||||
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
|
||||||
Accept terms and conditions
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Collapsible">
|
|
||||||
<Collapsible class="w-[350px] space-y-2" v-slot="{ open }">
|
|
||||||
<div class="flex items-center justify-between space-x-4 px-4">
|
|
||||||
<h4 class="text-sm font-semibold">@peduarte starred 3 repositories</h4>
|
|
||||||
<CollapsibleTrigger>
|
|
||||||
<Button variant="outline" class="w-9 p-0 aspect-square">
|
|
||||||
<span>
|
|
||||||
<Icon v-show="!open" icon="lucide:chevrons-up-down" class="h-4 w-4 text-black" />
|
|
||||||
<Icon v-show="open" icon="lucide:x" class="h-4 w-4 text-black" />
|
|
||||||
</span>
|
|
||||||
</Button>
|
|
||||||
</CollapsibleTrigger>
|
|
||||||
</div>
|
|
||||||
<div class="rounded-md border px-4 py-3 font-mono text-sm">
|
|
||||||
@radix-ui/primitives
|
|
||||||
</div>
|
|
||||||
<CollapsibleContent class="space-y-2">
|
|
||||||
<div class="rounded-md border px-4 py-3 font-mono text-sm">
|
|
||||||
@radix-ui/colors
|
|
||||||
</div>
|
|
||||||
<div class="rounded-md border px-4 py-3 font-mono text-sm">
|
|
||||||
@stitches/react
|
|
||||||
</div>
|
|
||||||
</CollapsibleContent>
|
|
||||||
</Collapsible>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Combobox"></InternalCard>
|
|
||||||
<InternalCard title="Command"></InternalCard>
|
|
||||||
<InternalCard title="Context Menu"></InternalCard>
|
|
||||||
<InternalCard title="Data Table"></InternalCard>
|
|
||||||
<InternalCard title="Date Picker"></InternalCard>
|
|
||||||
<InternalCard title="Dialog">
|
|
||||||
<Button label="Open" @click="dialogIsOpen = true">Show Dialog</Button>
|
|
||||||
<Dialog v-model="dialogIsOpen">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Title</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
This action cannot be undone. This will permanently delete your account
|
|
||||||
and remove your data from our servers.
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
<DialogFooter><Button variant="outline" @click="dialogIsOpen = false">Cancel</Button><Button>CTA
|
|
||||||
Button</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</Dialog>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Dropdown Menu"></InternalCard>
|
|
||||||
<InternalCard title="Hover Card"></InternalCard>
|
|
||||||
<InternalCard title="Input">
|
|
||||||
<Input type="email" placeholder="Email" />
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Label">
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<Checkbox id="terms2" v-model="checkboxEnabled2" />
|
|
||||||
<Label htmlFor="terms2">Accept terms and conditions</Label>
|
|
||||||
</div>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Menubar"></InternalCard>
|
|
||||||
<InternalCard title="Navigation Menu"></InternalCard>
|
|
||||||
<InternalCard title="Popover">
|
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger><Button variant="outline">Open popover</Button></PopoverTrigger>
|
|
||||||
<PopoverContent class="w-80">
|
|
||||||
<div class="grid gap-4">
|
|
||||||
<div class="space-y-2">
|
|
||||||
<h4 class="font-medium leading-none">Dimensions</h4>
|
|
||||||
<p class="text-sm text-muted-foreground">
|
|
||||||
Set the dimensions for the layer.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="grid gap-2">
|
|
||||||
<div class="grid grid-cols-3 items-center gap-4">
|
|
||||||
<Label htmlFor="width">Width</Label>
|
|
||||||
<Input id="width" defaultValue="100%" class="col-span-2 h-8" />
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-3 items-center gap-4">
|
|
||||||
<Label htmlFor="maxWidth">Max. width</Label>
|
|
||||||
<Input id="maxWidth" defaultValue="300px" class="col-span-2 h-8" />
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-3 items-center gap-4">
|
|
||||||
<Label htmlFor="height">Height</Label>
|
|
||||||
<Input id="height" defaultValue="25px" class="col-span-2 h-8" />
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-3 items-center gap-4">
|
|
||||||
<Label htmlFor="maxHeight">Max. height</Label>
|
|
||||||
<Input id="maxHeight" defaultValue="none" class="col-span-2 h-8" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Progress"></InternalCard>
|
|
||||||
<InternalCard title="Radio Group">
|
|
||||||
<RadioGroup v-model="radioValue">
|
|
||||||
<RadioGroupItem v-for="option in radioOptions" :value="option" :id="option">
|
|
||||||
<Label :for="option">{{ option }}</Label>
|
|
||||||
</RadioGroupItem>
|
|
||||||
</RadioGroup>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Scroll Area"></InternalCard>
|
|
||||||
<InternalCard title="Select">
|
|
||||||
<Select v-model="selectedPerson.id">
|
|
||||||
<SelectTrigger class="w-[210px]">
|
|
||||||
{{ selectedPerson.name }}
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectLabel>Fruits</SelectLabel>
|
|
||||||
<SelectItem v-for="person in people" :key="person.id" :value="person.id" :disabled="person.unavailable">{{
|
|
||||||
person.name }}</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Separator">
|
|
||||||
<div>
|
|
||||||
<div className="space-y-1">
|
|
||||||
<h4 className="text-sm font-medium leading-none">Radix Primitives</h4>
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
An open-source UI component library.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Separator class="my-4" />
|
|
||||||
<div className="flex h-5 items-center space-x-4 text-sm">
|
|
||||||
<div>Blog</div>
|
|
||||||
<Separator orientation="vertical" />
|
|
||||||
<div>Docs</div>
|
|
||||||
<Separator orientation="vertical" />
|
|
||||||
<div>Source</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Sheet"></InternalCard>
|
|
||||||
<InternalCard title="Skeleton"></InternalCard>
|
|
||||||
<InternalCard title="Slider"></InternalCard>
|
|
||||||
<InternalCard title="Switch">
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<Switch id="airplane-mode" v-model="enabled" />
|
|
||||||
<Label htmlFor="airplane-mode">Airplane Mode</Label>
|
|
||||||
</div>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Table"></InternalCard>
|
|
||||||
<InternalCard title="Tabs"></InternalCard>
|
|
||||||
<InternalCard title="Textarea"><Textarea placeholder="Type your message here." /></InternalCard>
|
|
||||||
<InternalCard title="Toast"></InternalCard>
|
|
||||||
<InternalCard title="Toggle">
|
|
||||||
<Toggle aria-label="Toggle italic" v-model="toggleEnabled">
|
|
||||||
<Icon icon="lucide:bold" class="h-4 w-4" />
|
|
||||||
</Toggle>
|
|
||||||
</InternalCard>
|
|
||||||
<InternalCard title="Tooltip">
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger>Hover</TooltipTrigger>
|
|
||||||
</Tooltip>
|
|
||||||
</InternalCard>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
@apply bg-neutral-100;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
44
packages/shadcn-vue/src/components/ui/Accordion.ts
Normal file
44
packages/shadcn-vue/src/components/ui/Accordion.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { defineComponent, h } from 'vue'
|
||||||
|
import {
|
||||||
|
AccordionContent as AccordionContentPrimitive,
|
||||||
|
type AccordionContentProps, AccordionHeader as AccordionHeaderPrimitive,
|
||||||
|
type AccordionHeaderProps, AccordionItem as AccordionItemPrimitive,
|
||||||
|
type AccordionItemProps, AccordionRoot as AccordionRootPrimitive,
|
||||||
|
AccordionTrigger as AccordionTriggerPrimitive, type AccordionTriggerProps,
|
||||||
|
} from 'radix-vue'
|
||||||
|
import { cn } from '@/utils'
|
||||||
|
|
||||||
|
export const Accordion = AccordionRootPrimitive
|
||||||
|
|
||||||
|
export const AccordionContent = defineComponent<AccordionContentProps>(
|
||||||
|
(props, { attrs, slots }) => {
|
||||||
|
return () => h(AccordionContentPrimitive,
|
||||||
|
{ class: cn('overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down', attrs.class), ...props },
|
||||||
|
() => h('div', { class: 'pb-4 pt-0' }, slots),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export const AccordionTrigger = defineComponent<AccordionTriggerProps>(
|
||||||
|
(props, { attrs, slots }) => {
|
||||||
|
return () => h(AccordionHeaderPrimitive, { class: 'flex' },
|
||||||
|
() => h(AccordionTriggerPrimitive,
|
||||||
|
{ class: cn('flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180', attrs.class) },
|
||||||
|
slots,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export const AccordionItem = defineComponent<AccordionItemProps>(
|
||||||
|
(props, { attrs, slots }) => {
|
||||||
|
return () => h(AccordionItemPrimitive,
|
||||||
|
{ class: cn('border-b', attrs.class), ...props }, slots)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export const AccordionHeader = defineComponent<AccordionHeaderProps>(
|
||||||
|
(props, { attrs, slots }) => {
|
||||||
|
return () => h(AccordionHeaderPrimitive, { class: cn('flex', attrs.class), ...props }, slots)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<DisclosurePanel class="overflow-hidden text-sm">
|
|
||||||
<div class="pb-4 pt-0"><slot /></div>
|
|
||||||
</DisclosurePanel>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
DisclosurePanel,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="border-b w-full">
|
|
||||||
<Disclosure>
|
|
||||||
<slot />
|
|
||||||
</Disclosure>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { Disclosure } from "@headlessui/vue"
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex">
|
|
||||||
<DisclosureButton class="flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-headlessui-state=open]>svg]:rotate-180">
|
|
||||||
<slot />
|
|
||||||
<Icon icon="heroicons:chevron-down" class="text-[16px] transition-transform duration-200" />
|
|
||||||
</DisclosureButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { DisclosureButton } from "@headlessui/vue";
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
/*
|
|
||||||
import MorphConfig from "@/morph.config.js";
|
|
||||||
import { computed } from "vue";
|
|
||||||
|
|
||||||
|
|
||||||
const triggerClass = computed(() => {
|
|
||||||
if (MorphConfig.ui.accordion.trigger) return MorphConfig.ui.accordion.trigger;
|
|
||||||
return "flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-headlessui-state=open]>svg]:rotate-180";
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
export { default as Accordion } from "./Accordion.vue";
|
|
||||||
export { default as AccordionContent } from "./AccordionContent.vue";
|
|
||||||
export { default as AccordionItem } from "./AccordionItem.vue";
|
|
||||||
export { default as AccordionTrigger } from "./AccordionTrigger.vue";
|
|
||||||
34
packages/shadcn-vue/src/components/ui/AccordionDemo.vue
Normal file
34
packages/shadcn-vue/src/components/ui/AccordionDemo.vue
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<script setup>
|
||||||
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './Accordion'
|
||||||
|
|
||||||
|
const defaultValue = 'item-1'
|
||||||
|
|
||||||
|
const accordionItems = [
|
||||||
|
{
|
||||||
|
value: 'item-1',
|
||||||
|
title: 'Is it accessible?',
|
||||||
|
content: 'Yes. It adheres to the WAI-ARIA design pattern.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'item-2',
|
||||||
|
title: 'Is it unstyled?',
|
||||||
|
content: 'Yes. It\'s unstyled by default, giving you freedom over the look and feel.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'item-3',
|
||||||
|
title: 'Can it be animated?',
|
||||||
|
content: 'Yes! You can use the transition prop to configure the animation.',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Accordion type="single" collapsible :default-value="defaultValue">
|
||||||
|
<AccordionItem v-for="item in accordionItems" :key="item.value" :value="item.value">
|
||||||
|
<AccordionTrigger>{{ item.title }}</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
{{ item.content }}
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
</template>
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
title: String
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="text-sm [&_p]:leading-relaxed"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<h5 class="mb-1 font-medium leading-none tracking-tight"><slot/></h5>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export { default as Alert } from "./Alert.vue";
|
|
||||||
export { default as AlertTitle } from "./AlertTitle.vue";
|
|
||||||
export { default as AlertDescription } from "./AlertDescription.vue";
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
<template>
|
|
||||||
<TransitionRoot :appear="appear" :show="isOpen" as="template">
|
|
||||||
<Dialog class="relative z-50" @close="close">
|
|
||||||
<TransitionChild v-if="overlay" as="template" :appear="appear" enter='ease-out duration-300'
|
|
||||||
enterFrom='opacity-0' enterTo='opacity-100' leave='ease-in duration-200' leaveFrom='opacity-100'
|
|
||||||
leaveTo='opacity-0'>
|
|
||||||
<div class="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-opacity animate-in fade-in" />
|
|
||||||
</TransitionChild>
|
|
||||||
|
|
||||||
<div class="fixed inset-0 z-50 flex items-end justify-center sm:items-center">
|
|
||||||
<TransitionChild as="template" :appear="appear" enter='ease-out duration-300'
|
|
||||||
enterFrom='opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95'
|
|
||||||
enterTo='opacity-100 translate-y-0 sm:scale-100' leave='ease-in duration-200'
|
|
||||||
leaveFrom='opacity-100 translate-y-0 sm:scale-100'
|
|
||||||
leaveTo='opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95'>
|
|
||||||
<DialogPanel
|
|
||||||
class="fixed z-50 grid w-full max-w-lg scale-100 gap-4 border bg-white p-6 opacity-100 shadow-lg animate-in fade-in-90 slide-in-from-bottom-10 sm:rounded-lg sm:zoom-in-90 sm:slide-in-from-bottom-0 md:w-full">
|
|
||||||
<slot />
|
|
||||||
</DialogPanel>
|
|
||||||
</TransitionChild>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
|
||||||
</TransitionRoot>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue'
|
|
||||||
import { Dialog, DialogPanel, TransitionRoot, TransitionChild } from '@headlessui/vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
appear: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
overlay: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
transition: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'close'])
|
|
||||||
|
|
||||||
const isOpen = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit('update:modelValue', value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function close(value: boolean) {
|
|
||||||
isOpen.value = value
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<p class="text-sm text-black/60"><slot/></p>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col space-y-2 text-center sm:text-left"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<template>
|
|
||||||
<h5 class="text-lg font-semibold">
|
|
||||||
<slot />
|
|
||||||
</h5>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex items-center justify-center border-2 border-neutral-300 rounded-xl min-h-[300px] relative">
|
|
||||||
<p class="text-2xl font-semibold absolute left-5 top-3">{{ props.title }}</p>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
title: String
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
export { default as AlertDialog } from "./AlertDialog.vue";
|
|
||||||
export { default as AlertDialogTitle } from "./AlertDialogTitle.vue";
|
|
||||||
export { default as AlertDialogHeader } from "./AlertDialogHeader.vue";
|
|
||||||
export { default as AlertDialogFooter } from "./AlertDialogFooter.vue";
|
|
||||||
export { default as AlertDialogDescription } from "./AlertDialogDescription.vue";
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="`relative w-full`" :style="`padding-bottom: ${aspect}%`">
|
|
||||||
<div class="absolute inset-0">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { computed } from "vue";
|
|
||||||
const props = defineProps({
|
|
||||||
ratio: Number,
|
|
||||||
});
|
|
||||||
|
|
||||||
const aspect = computed(() => {
|
|
||||||
return 1/props.ratio*100;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<img style="position: absolute; height: 100%; width: 100%; inset: 0px; color: transparent;" />
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
export { default as AspectRatio } from "./AspectRatio.vue";
|
|
||||||
export { default as Image } from "./Image.vue";
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full">
|
|
||||||
<slot />
|
|
||||||
</div></template>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
<template><div class="flex h-full w-full items-center justify-center rounded-full bg-muted"><slot /></div></template>
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<template>
|
|
||||||
<img :src="props.src" :alt="props.alt">
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
src: String,
|
|
||||||
alt: String
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export { default as Avatar } from "./Avatar.vue";
|
|
||||||
export { default as AvatarFallback } from "./AvatarFallback.vue";
|
|
||||||
export { default as AvatarImage } from "./AvatarImage.vue";
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="inline-flex items-center border rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 bg-black hover:bg-black/80 border-transparent text-white">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
</script>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Badge } from "./Badge.vue";
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<template>
|
|
||||||
<button
|
|
||||||
:class="`inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background h-10 py-2 px-4
|
|
||||||
${props.variant==='outline' ? 'border border-neutral-200 hover:bg-neutral-100' : 'bg-black text-white hover:bg-black/80' }`">
|
|
||||||
<slot />
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
label: String,
|
|
||||||
variant: String,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Button } from "./Button.vue";
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="rounded-lg border bg-card text-card-foreground shadow-sm">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="p-6 pt-0"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<p class="text-sm text-muted-foreground"><slot/></p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex items-center p-6 pt-0"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col space-y-1.5 p-6"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<h3 class="text-lg font-semibold leading-none tracking-tight"><slot/></h3>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
export { default as Card } from "./Card.vue";
|
|
||||||
export { default as CardContent } from "./CardContent.vue";
|
|
||||||
export { default as CardDescription } from "./CardDescription.vue";
|
|
||||||
export { default as CardFooter } from "./CardFooter.vue";
|
|
||||||
export { default as CardHeader } from "./CardHeader.vue";
|
|
||||||
export { default as CardTitle } from "./CardTitle.vue";
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<template>
|
|
||||||
<Switch v-model="isOpen" :class="isOpen ? 'text-primary-foreground bg-primary' : ''"
|
|
||||||
class="peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground">
|
|
||||||
<span class="flex items-center justify-center text-current" v-if="isOpen"><Icon icon="lucide:check"/></span>
|
|
||||||
</Switch>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { Switch } from '@headlessui/vue'
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: Boolean
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'close'])
|
|
||||||
|
|
||||||
const isOpen = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit('update:modelValue', value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Checkbox } from "./Checkbox.vue";
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Disclosure as="div" v-slot="{ open }">
|
|
||||||
<slot :open="open"></slot>
|
|
||||||
</Disclosure>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { Disclosure } from "@headlessui/vue"
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<DisclosurePanel class="overflow-hidden text-sm">
|
|
||||||
<slot />
|
|
||||||
</DisclosurePanel>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
DisclosurePanel,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<DisclosureButton as="template">
|
|
||||||
<slot />
|
|
||||||
</DisclosureButton>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { DisclosureButton } from "@headlessui/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export { default as Collapsible } from "./Collapsible.vue";
|
|
||||||
export { default as CollapsibleContent } from "./CollapsibleContent.vue";
|
|
||||||
export { default as CollapsibleTrigger } from "./CollapsibleTrigger.vue";
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
<template>
|
|
||||||
<Listbox v-model="isOpen" v-slot="{ open }">
|
|
||||||
<Float
|
|
||||||
portal
|
|
||||||
placement="bottom"
|
|
||||||
flip
|
|
||||||
strategy="fixed"
|
|
||||||
adaptive-width
|
|
||||||
enter="transition duration-200 ease-out"
|
|
||||||
enter-from="scale-95 opacity-0"
|
|
||||||
enter-to="scale-100 opacity-100"
|
|
||||||
leave="transition duration-150 ease-in"
|
|
||||||
leave-from="scale-100 opacity-100"
|
|
||||||
leave-to="scale-95 opacity-0"
|
|
||||||
tailwindcss-origin-class
|
|
||||||
:offset="4"
|
|
||||||
as="div"
|
|
||||||
class="relative mt-1"
|
|
||||||
>
|
|
||||||
<slot :open="open"></slot>
|
|
||||||
</Float>
|
|
||||||
</Listbox>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from "vue";
|
|
||||||
import { Listbox } from "@headlessui/vue";
|
|
||||||
import { Float } from "@headlessui-float/vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: Boolean,
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(["update:modelValue", "close"]);
|
|
||||||
|
|
||||||
const isOpen = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit("update:modelValue", value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<template>
|
|
||||||
<ListboxButton v-slot="{ open }"
|
|
||||||
class="flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50">
|
|
||||||
<span>
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
<Icon icon="lucide:chevron-down" :class="`h-4 w-4 opacity-50 transition-all ${open ? 'rotate-180' : ''}`" />
|
|
||||||
</ListboxButton>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ListboxButton,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
<template>
|
|
||||||
<ListboxOption v-slot="{ active, selected, disabled }" as="template">
|
|
||||||
<li :class="[
|
|
||||||
active ? 'bg-accent text-accent-foreground' : 'text-gray-900',
|
|
||||||
disabled ? 'opacity-50 pointer-events-none' : 'text-gray-900',
|
|
||||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none',
|
|
||||||
]">
|
|
||||||
<span v-if="selected" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
||||||
<Icon icon="lucide:check" class="h-[14px] w-[14px]" aria-hidden="true" />
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
</ListboxOption>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ListboxOption,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<template>
|
|
||||||
<ListboxOptions
|
|
||||||
class="w-full min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md p-1 focus:outline-none">
|
|
||||||
<slot />
|
|
||||||
</ListboxOptions>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ListboxOptions,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
export { default as Combobox } from "./Combobox.vue";
|
|
||||||
export { default as ComboboxInput } from "./ComboboxInput.vue";
|
|
||||||
export { default as ComboboxOptions } from "./ComboboxOptions.vue";
|
|
||||||
export { default as ComboboxOption } from "./ComboboxOption.vue";
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
import { Button } from "@/src/components/ui/Button"
|
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
CardDescription,
|
|
||||||
CardFooter,
|
|
||||||
CardHeader,
|
|
||||||
CardTitle,
|
|
||||||
} from "@/src/components/ui/Card"
|
|
||||||
|
|
||||||
const notifications = [
|
|
||||||
{
|
|
||||||
title: "Your call has been confirmed.",
|
|
||||||
description: "1 hour ago",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "You have a new message!",
|
|
||||||
description: "1 hour ago",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Your subscription is expiring soon!",
|
|
||||||
description: "2 hours ago",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<Card class="w-[380px]">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Notifications</CardTitle>
|
|
||||||
<CardDescription>You have 3 unread messages.</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent class="grid gap-4">
|
|
||||||
<div class=" flex items-center space-x-4 rounded-md border p-4">
|
|
||||||
<Icon icon="lucide:bell-ring" />
|
|
||||||
<div class="flex-1 space-y-1">
|
|
||||||
<p class="text-sm font-medium leading-none">
|
|
||||||
Push Notifications
|
|
||||||
</p>
|
|
||||||
<p class="text-sm text-muted-foreground">
|
|
||||||
Send notifications to device.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="mb-4 grid grid-cols-[25px_1fr] items-start pb-4 last:mb-0 last:pb-0"
|
|
||||||
v-for="notification, index in notifications" :key="index">
|
|
||||||
<span class="flex h-2 w-2 translate-y-1 rounded-full bg-sky-500" />
|
|
||||||
<div class="space-y-1">
|
|
||||||
<p class="text-sm font-medium leading-none">
|
|
||||||
{{ notification.title }}
|
|
||||||
</p>
|
|
||||||
<p class="text-sm text-muted-foreground">
|
|
||||||
{{ notification.description }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
<CardFooter>
|
|
||||||
<Button class="w-full">
|
|
||||||
<Icon icon="lucide:check" class="mr-2 h-4 w-4" /> Mark all as read
|
|
||||||
</Button>
|
|
||||||
</CardFooter>
|
|
||||||
</Card>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Card } from "./Card.vue";
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
<template>
|
|
||||||
<TransitionRoot :appear="appear" :show="isOpen" as="template">
|
|
||||||
<Dialog class="relative z-50" @close="close">
|
|
||||||
<TransitionChild v-if="overlay" as="template" :appear="appear" enter='ease-out duration-300'
|
|
||||||
enterFrom='opacity-0' enterTo='opacity-100' leave='ease-in duration-200' leaveFrom='opacity-100'
|
|
||||||
leaveTo='opacity-0'>
|
|
||||||
<div class="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-opacity animate-in fade-in" />
|
|
||||||
</TransitionChild>
|
|
||||||
|
|
||||||
<div class="fixed inset-0 z-50 flex items-end justify-center sm:items-center">
|
|
||||||
<TransitionChild as="template" :appear="appear" enter='ease-out duration-300'
|
|
||||||
enterFrom='opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95'
|
|
||||||
enterTo='opacity-100 translate-y-0 sm:scale-100' leave='ease-in duration-200'
|
|
||||||
leaveFrom='opacity-100 translate-y-0 sm:scale-100'
|
|
||||||
leaveTo='opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95'>
|
|
||||||
<DialogPanel
|
|
||||||
class="fixed z-50 grid w-full max-w-lg scale-100 gap-4 border bg-white p-6 opacity-100 shadow-lg animate-in fade-in-90 slide-in-from-bottom-10 sm:rounded-lg sm:zoom-in-90 sm:slide-in-from-bottom-0 md:w-full">
|
|
||||||
<slot />
|
|
||||||
</DialogPanel>
|
|
||||||
</TransitionChild>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
|
||||||
</TransitionRoot>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue'
|
|
||||||
import { Dialog, DialogPanel, TransitionRoot, TransitionChild } from '@headlessui/vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
appear: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
overlay: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
transition: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'close'])
|
|
||||||
|
|
||||||
const isOpen = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit('update:modelValue', value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function close(value: boolean) {
|
|
||||||
isOpen.value = value
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<p class="text-sm text-black/60"><slot/></p>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex flex-col space-y-2 text-center sm:text-left"><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<template>
|
|
||||||
<h5 class="text-lg font-semibold">
|
|
||||||
<slot />
|
|
||||||
</h5>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="flex items-center justify-center border-2 border-neutral-300 rounded-xl min-h-[300px] relative">
|
|
||||||
<p class="text-2xl font-semibold absolute left-5 top-3">{{ props.title }}</p>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
title: String
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
export { default as Dialog } from "./Dialog.vue";
|
|
||||||
export { default as DialogTitle } from "./DialogTitle.vue";
|
|
||||||
export { default as DialogHeader } from "./DialogHeader.vue";
|
|
||||||
export { default as DialogFooter } from "./DialogFooter.vue";
|
|
||||||
export { default as DialogDescription } from "./DialogDescription.vue";
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<input
|
|
||||||
:class="props.class"
|
|
||||||
class="flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
class: String,
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Input } from "./Input.vue";
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<template>
|
|
||||||
<label :for="props.htmlFor" :class="`text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 ${props.class}`"><slot/></label>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
class: String,
|
|
||||||
id: String,
|
|
||||||
htmlFor: String
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Label } from "./Label.vue";
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<template>
|
|
||||||
<Popover v-slot="{ open }">
|
|
||||||
<Float portal composable placement="bottom" flip strategy="fixed" enter="transition duration-200 ease-out"
|
|
||||||
enter-from="scale-95 opacity-0" enter-to="scale-100 opacity-100" leave="transition duration-150 ease-in"
|
|
||||||
leave-from="scale-100 opacity-100" leave-to="scale-95 opacity-0" tailwindcss-origin-class :offset="6" as="div"
|
|
||||||
class="relative">
|
|
||||||
<slot :open="open"/>
|
|
||||||
</Float>
|
|
||||||
</Popover>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { Popover } from "@headlessui/vue";
|
|
||||||
import { Float } from "@headlessui-float/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<template>
|
|
||||||
<FloatContent>
|
|
||||||
<PopoverPanel
|
|
||||||
class="z-50 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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 w-80">
|
|
||||||
<slot />
|
|
||||||
</PopoverPanel>
|
|
||||||
</FloatContent>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { PopoverPanel } from "@headlessui/vue";
|
|
||||||
import { FloatContent } from "@headlessui-float/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<template>
|
|
||||||
<FloatReference>
|
|
||||||
<PopoverButton><slot /></PopoverButton>
|
|
||||||
</FloatReference>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { PopoverButton } from "@headlessui/vue";
|
|
||||||
import { FloatReference } from "@headlessui-float/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export { default as Popover } from "./Popover.vue";
|
|
||||||
export { default as PopoverContent } from "./PopoverContent.vue";
|
|
||||||
export { default as PopoverTrigger } from "./PopoverTrigger.vue";
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<template>
|
|
||||||
<RadioGroup v-model="isOpen" class="flex flex-col gap-2">
|
|
||||||
<slot />
|
|
||||||
</RadioGroup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { RadioGroup } from '@headlessui/vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: String
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'close'])
|
|
||||||
|
|
||||||
const isOpen = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit('update:modelValue', value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<template>
|
|
||||||
<RadioGroupOption v-slot="{ active, checked }" class="list-none focus:outline-none flex items-center space-x-2 [&>[role='indicator']]:focus:outline-none [&>[role='indicator']]:focus-visible:ring-2 [&>[role='indicator']]:focus-visible:ring-ring [&>[role='indicator']]:focus-visible:ring-offset-2">
|
|
||||||
<button role="indicator"
|
|
||||||
class="aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 flex items-center justify-center">
|
|
||||||
<span v-show="checked" class="bg-black h-2.5 w-2.5 rounded-full"></span>
|
|
||||||
</button>
|
|
||||||
<slot />
|
|
||||||
</RadioGroupOption>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { RadioGroupOption } from '@headlessui/vue';
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
export { default as RadioGroup } from "./RadioGroup.vue";
|
|
||||||
export { default as RadioGroupItem } from "./RadioGroupItem.vue";
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
<template>
|
|
||||||
<Listbox v-model="isOpen" v-slot="{ open }">
|
|
||||||
<Float
|
|
||||||
portal
|
|
||||||
placement="bottom"
|
|
||||||
flip
|
|
||||||
strategy="fixed"
|
|
||||||
adaptive-width
|
|
||||||
enter="transition duration-200 ease-out"
|
|
||||||
enter-from="scale-95 opacity-0"
|
|
||||||
enter-to="scale-100 opacity-100"
|
|
||||||
leave="transition duration-150 ease-in"
|
|
||||||
leave-from="scale-100 opacity-100"
|
|
||||||
leave-to="scale-95 opacity-0"
|
|
||||||
tailwindcss-origin-class
|
|
||||||
:offset="4"
|
|
||||||
as="div"
|
|
||||||
class="relative mt-1"
|
|
||||||
>
|
|
||||||
<slot :open="open"></slot>
|
|
||||||
</Float>
|
|
||||||
</Listbox>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from "vue";
|
|
||||||
import { Listbox } from "@headlessui/vue";
|
|
||||||
import { Float } from "@headlessui-float/vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: Number,
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(["update:modelValue", "close"]);
|
|
||||||
|
|
||||||
const isOpen = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit("update:modelValue", value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<template>
|
|
||||||
<ListboxOptions
|
|
||||||
class="w-full min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md p-1 focus:outline-none">
|
|
||||||
<slot />
|
|
||||||
</ListboxOptions>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ListboxOptions,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
<template>
|
|
||||||
<ListboxOption v-slot="{ active, selected, disabled }" as="template">
|
|
||||||
<li :class="[
|
|
||||||
active ? 'bg-accent text-accent-foreground' : 'text-gray-900',
|
|
||||||
disabled ? 'opacity-50 pointer-events-none' : 'text-gray-900',
|
|
||||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none',
|
|
||||||
]">
|
|
||||||
<span v-if="selected" class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
||||||
<Icon icon="lucide:check" class="h-[14px] w-[14px]" aria-hidden="true" />
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
</ListboxOption>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ListboxOption,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="py-1.5 pl-8 pr-2 text-sm font-semibold">
|
|
||||||
|
|
||||||
|
|
||||||
<ListboxLabel>
|
|
||||||
<slot />
|
|
||||||
</ListboxLabel>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ListboxLabel,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<template>
|
|
||||||
<ListboxButton v-slot="{ open }"
|
|
||||||
class="flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50">
|
|
||||||
<span>
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
<Icon icon="lucide:chevron-down" :class="`h-4 w-4 opacity-50 transition-all ${open ? 'rotate-180' : ''}`" />
|
|
||||||
</ListboxButton>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import {
|
|
||||||
ListboxButton,
|
|
||||||
} from '@headlessui/vue'
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
export { default as Select } from "./Select.vue";
|
|
||||||
export { default as SelectContent } from "./SelectContent.vue";
|
|
||||||
export { default as SelectTrigger } from "./SelectTrigger.vue";
|
|
||||||
export { default as SelectItem } from "./SelectItem.vue";
|
|
||||||
export { default as SelectLabel } from "./SelectLabel.vue";
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="`shrink-0 bg-border ${props.orientation == 'vertical' ? 'w-[1px] h-full' : 'w-full h-[1px]'}`"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
const props = defineProps({
|
|
||||||
orientation: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: "horizontal"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export {default as Separator} from './Separator.vue'
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<template>
|
|
||||||
<Switch v-model="isOpen" :class="isOpen ? 'bg-black' : 'bg-neutral-300'"
|
|
||||||
class="peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50">
|
|
||||||
<span :class="isOpen ? 'translate-x-5' : 'translate-x-0'"
|
|
||||||
class="pointer-events-none block h-5 w-5 rounded-full bg-white shadow-lg ring-0 transition-transform" />
|
|
||||||
</Switch>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { Switch } from '@headlessui/vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: Boolean
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'close'])
|
|
||||||
|
|
||||||
const isOpen = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit('update:modelValue', value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Switch } from "./Switch.vue";
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<TabGroup>
|
|
||||||
<slot />
|
|
||||||
</TabGroup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { TabGroup, TabList, Tab, TabPanels, TabPanel } from '@headlessui/vue'
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<div><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { TabGroup, TabList, Tab, TabPanels, TabPanel } from '@headlessui/vue'
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<div><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<div><slot/></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
export { default as Tabs } from "./Tabs.vue";
|
|
||||||
export { default as TabsContent } from "./TabsContent.vue";
|
|
||||||
export { default as TabsList } from "./TabsList.vue";
|
|
||||||
export { default as TabsTrigger } from "./TabsTrigger.vue";
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<textarea
|
|
||||||
class="flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
</script>
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Textarea } from "./Textarea.vue";
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<template>
|
|
||||||
<Switch v-model="isChecked" :class="isChecked ? 'text-accent-foreground bg-neutral-300' : 'bg-neutral-100'"
|
|
||||||
class="inline-flex items-center justify-center rounded-md text-sm font-medium 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 ring-offset-background hover:bg-neutral-200/80 hover:text-black-40 h-10 px-3">
|
|
||||||
<span>
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
</Switch>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { Switch } from '@headlessui/vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: Boolean
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'close'])
|
|
||||||
|
|
||||||
const isChecked = computed({
|
|
||||||
get() {
|
|
||||||
return props.modelValue
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
emit('update:modelValue', value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as Toggle } from "./Toggle.vue";
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<template>
|
|
||||||
<Float :show="show">
|
|
||||||
<slot :enter="handleMouseEnter" :leave="handleMouseLeave"/>
|
|
||||||
<div static>
|
|
||||||
Help me fund my Open Source work!
|
|
||||||
</div>
|
|
||||||
</Float>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { Float } from '@headlessui-float/vue'
|
|
||||||
|
|
||||||
const show = ref(false)
|
|
||||||
const handleMouseEnter = () => {
|
|
||||||
show.value = true
|
|
||||||
}
|
|
||||||
const handleMouseLeave = () => {
|
|
||||||
show.value = false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<template>
|
|
||||||
<FloatContent static>
|
|
||||||
<div
|
|
||||||
class="z-50 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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 w-80">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</FloatContent>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { FloatContent } from "@headlessui-float/vue";
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<template>
|
|
||||||
<button @mouseenter="emit('enter')" @mouseleave="emit('leave')">Sponsor me</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { Float } from '@headlessui-float/vue'
|
|
||||||
|
|
||||||
const show = ref(false)
|
|
||||||
const toggle = () => {
|
|
||||||
show.value = !show.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits(['enter', 'leave'])
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export { default as Tooltip } from "./Tooltip.vue";
|
|
||||||
export { default as TooltipContent } from "./TooltipContent.vue";
|
|
||||||
export { default as TooltipTrigger } from "./TooltipTrigger.vue";
|
|
||||||
82
packages/shadcn-vue/src/components/ui/cva.ts
Normal file
82
packages/shadcn-vue/src/components/ui/cva.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { type VariantProps, cva } from 'class-variance-authority'
|
||||||
|
|
||||||
|
export const AccordionClass = cva('', {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
root: '',
|
||||||
|
item: '',
|
||||||
|
header: '',
|
||||||
|
trigger: '',
|
||||||
|
content: '',
|
||||||
|
contentWrapper: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
compoundVariants: [
|
||||||
|
{ variant: 'default', component: 'root', class: 'w-[300px]' },
|
||||||
|
{ variant: 'default', component: 'item', class: 'border-b w-full' },
|
||||||
|
{
|
||||||
|
variant: 'default',
|
||||||
|
component: 'trigger',
|
||||||
|
class:
|
||||||
|
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variant: 'default',
|
||||||
|
component: 'content',
|
||||||
|
class:
|
||||||
|
'overflow-hidden text-sm data-[state=open]:animate-accordion-down data-[state=closed]:animate-accordion-up',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variant: 'default',
|
||||||
|
component: 'contentWrapper',
|
||||||
|
class: 'overflow-hidden text-sm',
|
||||||
|
},
|
||||||
|
{ variant: 'default', component: 'header', class: 'flex' },
|
||||||
|
],
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AccordionClassProps = VariantProps<typeof AccordionClass>
|
||||||
|
|
||||||
|
export const SwitchClass = cva('', {
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
1: '',
|
||||||
|
2: '',
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
root: 'unset box-border select-none [&::before]:box-border [&::after]:box-border inline-flex items-center justify-center leading-none m-0 outline-none bg-[#e6e8eb] rounded-full relative focus-within:shadow-[0_0_0_2px_#c1c8cd] data-[state=checked]:bg-[#0091ff] data-[state=checked]:focus-within:shadow-[0_0_0_2px_#5eb0ef]',
|
||||||
|
thumb:
|
||||||
|
'absolute left-0 bg-white rounded-full shadow-switch transition-transform duration-100 ease-[cubic-bezier(0.22,_1,_0.36,_1)]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
compoundVariants: [
|
||||||
|
{ size: 1, component: 'root', class: 'w-[25px] h-[15px]' },
|
||||||
|
{ size: 2, component: 'root', class: 'w-[45px] h-[25px]' },
|
||||||
|
{
|
||||||
|
size: 1,
|
||||||
|
component: 'thumb',
|
||||||
|
class:
|
||||||
|
'w-[13px] h-[13px] translate-x-[1px] data-[state=checked]:translate-x-[11px]',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 2,
|
||||||
|
component: 'thumb',
|
||||||
|
class:
|
||||||
|
'w-[21px] h-[21px] translate-x-0.5 data-[state=checked]:translate-x-[22px]',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default',
|
||||||
|
size: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export type SwitchClassProps = VariantProps<typeof SwitchClass>
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import {
|
|
||||||
AccordionContent,
|
|
||||||
AccordionHeader,
|
|
||||||
AccordionItem,
|
|
||||||
AccordionRoot,
|
|
||||||
AccordionTrigger,
|
|
||||||
} from "radix-vue";
|
|
||||||
import { Icon } from "@iconify/vue";
|
|
||||||
import { AccordionClass, type AccordionClassProps } from "./cva"
|
|
||||||
|
|
||||||
interface AccordionProps {
|
|
||||||
variant: AccordionClassProps["variant"];
|
|
||||||
data: {
|
|
||||||
value: string,
|
|
||||||
title: string,
|
|
||||||
content: string,
|
|
||||||
}[],
|
|
||||||
defaultValue: string,
|
|
||||||
type: string,
|
|
||||||
collapsible: boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
withDefaults(defineProps<AccordionProps>(), {
|
|
||||||
variant: 'default',
|
|
||||||
type: 'single',
|
|
||||||
collapsible: true,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<AccordionRoot
|
|
||||||
:class="AccordionClass({ variant, component: 'root' })"
|
|
||||||
:default-value="defaultValue"
|
|
||||||
:type="type"
|
|
||||||
:collapsible="collapsible"
|
|
||||||
>
|
|
||||||
<template v-for="item in data" :key="item.value">
|
|
||||||
<AccordionItem
|
|
||||||
:class="AccordionClass({ variant, component: 'item' })"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
<AccordionHeader :class="AccordionClass({ variant, component: 'header' })">
|
|
||||||
<AccordionTrigger :class="AccordionClass({ variant, component: 'trigger' })"
|
|
||||||
><span>{{ item.title }}</span>
|
|
||||||
<Icon
|
|
||||||
icon="radix-icons:chevron-down"
|
|
||||||
class="text-green10 ease-[cubic-bezier(0.87,_0,_0.13,_1)] transition-transform duration-300 group-data-[state=open]:rotate-180"
|
|
||||||
aria-hidden
|
|
||||||
/>
|
|
||||||
</AccordionTrigger>
|
|
||||||
</AccordionHeader>
|
|
||||||
<AccordionContent :class="AccordionClass({ variant, component: 'content' })">
|
|
||||||
<div :class="AccordionClass({ variant, component: 'contentWrapper' })">
|
|
||||||
{{ item.content }}
|
|
||||||
</div>
|
|
||||||
</AccordionContent>
|
|
||||||
</AccordionItem>
|
|
||||||
</template>
|
|
||||||
</AccordionRoot>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import Accordion from "./Accordion.vue"
|
|
||||||
|
|
||||||
const defaultValue = 'item-1'
|
|
||||||
|
|
||||||
const accordionItems = [
|
|
||||||
{
|
|
||||||
value: "item-1",
|
|
||||||
title: "Is it accessible?",
|
|
||||||
content: "Yes. It adheres to the WAI-ARIA design pattern."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "item-2",
|
|
||||||
title: "Is it unstyled?",
|
|
||||||
content: "Yes. It's unstyled by default, giving you freedom over the look and feel."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: "item-3",
|
|
||||||
title: "Can it be animated?",
|
|
||||||
content: "Yes! You can use the transition prop to configure the animation."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Accordion :data="accordionItems" :default-value="defaultValue"/>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { SwitchRoot, SwitchThumb } from 'radix-vue'
|
|
||||||
import { SwitchClass, type SwitchClassProps } from "./cva"
|
|
||||||
import { useVModel } from "@vueuse/core";
|
|
||||||
|
|
||||||
interface SwitchProps {
|
|
||||||
variant?: SwitchClassProps["variant"];
|
|
||||||
size?: SwitchClassProps["size"];
|
|
||||||
defaultOpen?: string;
|
|
||||||
open: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<SwitchProps>(), {
|
|
||||||
variant: 'default',
|
|
||||||
size: 1,
|
|
||||||
open: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(["update:open"]);
|
|
||||||
|
|
||||||
const open = useVModel(props, "open", emit, {
|
|
||||||
defaultValue: props.defaultOpen,
|
|
||||||
passive: true,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<SwitchRoot
|
|
||||||
v-model:open="open"
|
|
||||||
:class="SwitchClass({ variant, size, component: 'root' })"
|
|
||||||
>
|
|
||||||
<SwitchThumb :class="SwitchClass({ variant, size, component: 'thumb' })" />
|
|
||||||
</SwitchRoot>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import Switch from './Switch.vue';
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
const switchState = ref(false)
|
|
||||||
const switchState2 = ref(false)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Switch v-model:open="switchState">
|
|
||||||
</Switch>
|
|
||||||
|
|
||||||
<Switch v-model:open="switchState2" :size="2" class="ml-5">
|
|
||||||
</Switch>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
|
||||||
|
|
||||||
export const AccordionClass = cva("", {
|
|
||||||
variants: {
|
|
||||||
variant: {
|
|
||||||
default: "",
|
|
||||||
},
|
|
||||||
component: {
|
|
||||||
root: "",
|
|
||||||
item: "",
|
|
||||||
header: "",
|
|
||||||
trigger: "",
|
|
||||||
content: "",
|
|
||||||
contentWrapper: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
compoundVariants: [
|
|
||||||
{ variant: "default", component: "root", class: "w-[300px]" },
|
|
||||||
{ variant: "default", component: "item", class: "border-b w-full" },
|
|
||||||
{
|
|
||||||
variant: "default",
|
|
||||||
component: "trigger",
|
|
||||||
class:
|
|
||||||
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
variant: "default",
|
|
||||||
component: "content",
|
|
||||||
class:
|
|
||||||
"overflow-hidden text-sm data-[state=open]:animate-accordion-down data-[state=closed]:animate-accordion-up",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
variant: "default",
|
|
||||||
component: "contentWrapper",
|
|
||||||
class: "overflow-hidden text-sm",
|
|
||||||
},
|
|
||||||
{ variant: "default", component: "header", class: "flex" },
|
|
||||||
],
|
|
||||||
defaultVariants: {
|
|
||||||
variant: "default",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export type AccordionClassProps = VariantProps<typeof AccordionClass>;
|
|
||||||
|
|
||||||
export const SwitchClass = cva("", {
|
|
||||||
variants: {
|
|
||||||
variant: {
|
|
||||||
default: "",
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
1: "",
|
|
||||||
2: "",
|
|
||||||
},
|
|
||||||
component: {
|
|
||||||
root: "unset box-border select-none [&::before]:box-border [&::after]:box-border inline-flex items-center justify-center leading-none m-0 outline-none bg-[#e6e8eb] rounded-full relative focus-within:shadow-[0_0_0_2px_#c1c8cd] data-[state=checked]:bg-[#0091ff] data-[state=checked]:focus-within:shadow-[0_0_0_2px_#5eb0ef]",
|
|
||||||
thumb:
|
|
||||||
"absolute left-0 bg-white rounded-full shadow-switch transition-transform duration-100 ease-[cubic-bezier(0.22,_1,_0.36,_1)]",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
compoundVariants: [
|
|
||||||
{ size: 1, component: "root", class: "w-[25px] h-[15px]" },
|
|
||||||
{ size: 2, component: "root", class: "w-[45px] h-[25px]" },
|
|
||||||
{
|
|
||||||
size: 1,
|
|
||||||
component: "thumb",
|
|
||||||
class:
|
|
||||||
"w-[13px] h-[13px] translate-x-[1px] data-[state=checked]:translate-x-[11px]",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
size: 2,
|
|
||||||
component: "thumb",
|
|
||||||
class:
|
|
||||||
"w-[21px] h-[21px] translate-x-0.5 data-[state=checked]:translate-x-[22px]",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
defaultVariants: {
|
|
||||||
variant: "default",
|
|
||||||
size: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
export type SwitchClassProps = VariantProps<typeof SwitchClass>;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user