-
-
Notifications
You must be signed in to change notification settings - Fork 88
/
metadata.json
655 lines (655 loc) · 139 KB
/
metadata.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
[
{
"name": "accordion",
"description": "A vertically stacked set of interactive headings that each reveal a section of content.",
"usage": "<script setup lang=\"ts\">\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'\n</script>\n\n<template>\n <Accordion type=\"single\" collapsible>\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>Is it accessible?</AccordionTrigger>\n <AccordionContent>\n Yes. It adheres to the WAI-ARIA design pattern.\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n</template>\n",
"examples": [
{
"source": "AccordionDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'\n\nconst defaultValue = 'item-1'\n\nconst accordionItems = [\n { value: 'item-1', title: 'Is it accessible?', content: 'Yes. It adheres to the WAI-ARIA design pattern.' },\n { value: 'item-2', title: 'Is it unstyled?', content: 'Yes. It\\'s unstyled by default, giving you freedom over the look and feel.' },\n { value: 'item-3', title: 'Can it be animated?', content: 'Yes! You can use the transition prop to configure the animation.' },\n]\n</script>\n\n<template>\n <Accordion type=\"single\" class=\"w-full\" collapsible :default-value=\"defaultValue\">\n <AccordionItem v-for=\"item in accordionItems\" :key=\"item.value\" :value=\"item.value\">\n <AccordionTrigger>{{ item.title }}</AccordionTrigger>\n <AccordionContent>\n {{ item.content }}\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n</template>"
}
]
},
{
"name": "alert-dialog",
"description": "A modal dialog that interrupts the user with important content and expects a response.",
"usage": "<script setup lang=\"ts\">\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@/components/ui/alert-dialog'\n</script>\n\n<template>\n <AlertDialog>\n <AlertDialogTrigger>Open</AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your account\n and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction>Continue</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n</template>\n",
"examples": [
{
"source": "AlertDialogDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@/components/ui/alert-dialog'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <AlertDialog>\n <AlertDialogTrigger as-child>\n <Button variant=\"outline\">\n Show Dialog\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction>Continue</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n</template>"
}
]
},
{
"name": "alert",
"description": "Displays a callout for user attention.",
"usage": "<script setup lang=\"ts\">\nimport { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'\n</script>\n\n<template>\n <Alert>\n <AlertTitle>Heads up!</AlertTitle>\n <AlertDescription>\n You can add components to your app using the cli.\n </AlertDescription>\n </Alert>\n</template>\n",
"examples": [
{
"source": "AlertDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Terminal } from 'lucide-vue-next'\nimport { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'\n</script>\n\n<template>\n <Alert>\n <Terminal class=\"h-4 w-4\" />\n <AlertTitle>Heads up!</AlertTitle>\n <AlertDescription>\n You can add components to your app using the cli.\n </AlertDescription>\n </Alert>\n</template>"
},
{
"source": "AlertDestructiveDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { AlertCircle } from 'lucide-vue-next'\nimport { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'\n</script>\n\n<template>\n <Alert variant=\"destructive\">\n <AlertCircle class=\"w-4 h-4\" />\n <AlertTitle>Error</AlertTitle>\n <AlertDescription>\n Your session has expired. Please log in again.\n </AlertDescription>\n </Alert>\n</template>"
},
{
"source": "AlertDialogDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from '@/components/ui/alert-dialog'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <AlertDialog>\n <AlertDialogTrigger as-child>\n <Button variant=\"outline\">\n Show Dialog\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction>Continue</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n</template>"
}
]
},
{
"name": "aspect-ratio",
"description": "Displays content within a desired ratio.",
"usage": "<script setup lang=\"ts\">\nimport { AspectRatio } from '@/components/ui/aspect-ratio'\n</script>\n\n<template>\n <div class=\"w-[450px]\">\n <AspectRatio :ratio=\"16 / 9\">\n <img src=\"...\" alt=\"Image\" class=\"rounded-md object-cover\">\n </AspectRatio>\n </div>\n</template>\n",
"examples": [
{
"source": "AspectRatioDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { AspectRatio } from '@/components/ui/aspect-ratio'\n</script>\n\n<template>\n <AspectRatio :ratio=\"16 / 9\" class=\"bg-muted\">\n <img\n src=\"https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80\"\n alt=\"Photo by Drew Beamer\"\n class=\"rounded-md object-cover w-full h-full\"\n >\n </AspectRatio>\n</template>"
}
]
},
{
"name": "avatar",
"description": "An image element with a fallback for representing the user.",
"usage": "<script setup lang=\"ts\">\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'\n</script>\n\n<template>\n <Avatar>\n <AvatarImage src=\"https://github.com/radix-vue.png\" alt=\"@radix-vue\" />\n <AvatarFallback>CN</AvatarFallback>\n </Avatar>\n</template>\n",
"examples": [
{
"source": "AvatarDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'\n</script>\n\n<template>\n <Avatar>\n <AvatarImage src=\"https://github.com/radix-vue.png\" alt=\"@radix-vue\" />\n <AvatarFallback>CN</AvatarFallback>\n </Avatar>\n</template>"
}
]
},
{
"name": "badge",
"description": "Displays a badge or a component that looks like a badge.",
"usage": "<script setup lang=\"ts\">\nimport { Badge } from '@/components/ui/badge'\n</script>\n\n<template>\n <Badge>Badge</Badge>\n</template>\n",
"examples": [
{
"source": "BadgeDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Badge } from '@/components/ui/badge'\n</script>\n\n<template>\n <Badge>Badge</Badge>\n</template>"
},
{
"source": "BadgeDestructiveDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Badge } from '@/components/ui/badge'\n</script>\n\n<template>\n <Badge variant=\"destructive\">\n Destructive\n </Badge>\n</template>"
},
{
"source": "BadgeOutlineDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Badge } from '@/components/ui/badge'\n</script>\n\n<template>\n <Badge variant=\"outline\">\n Outline\n </Badge>\n</template>"
},
{
"source": "BadgeSecondaryDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Badge } from '@/components/ui/badge'\n</script>\n\n<template>\n <Badge variant=\"secondary\">\n Secondary\n </Badge>\n</template>"
}
]
},
{
"name": "button",
"description": "Displays a button or a component that looks like a button. Variant 'default' is the primary variant",
"usage": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button>Button</Button>\n</template>\n",
"examples": [
{
"source": "ButtonAsChildDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button as-child>\n <a href=\"/login\">\n Login\n </a>\n </Button>\n</template>"
},
{
"source": "ButtonDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button>Button</Button>\n</template>"
},
{
"source": "ButtonDestructiveDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button variant=\"destructive\">\n Destructive\n </Button>\n</template>"
},
{
"source": "ButtonGhostDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button variant=\"ghost\">\n Ghost\n </Button>\n</template>"
},
{
"source": "ButtonIconDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ChevronRight } from 'lucide-vue-next'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button variant=\"outline\" size=\"icon\">\n <ChevronRight class=\"w-4 h-4\" />\n </Button>\n</template>"
},
{
"source": "ButtonLinkDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button variant=\"link\">\n Link\n </Button>\n</template>"
},
{
"source": "ButtonLoadingDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Loader2 } from 'lucide-vue-next'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button disabled>\n <Loader2 class=\"w-4 h-4 mr-2 animate-spin\" />\n Please wait\n </Button>\n</template>"
},
{
"source": "ButtonOutlineDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button variant=\"outline\">\n Outline\n </Button>\n</template>"
},
{
"source": "ButtonSecondaryDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button variant=\"secondary\">\n Secondary\n </Button>\n</template>"
},
{
"source": "ButtonWithIconDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Mail } from 'lucide-vue-next'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Button>\n <Mail class=\"w-4 h-4 mr-2\" /> Login with Email\n </Button>\n</template>"
}
]
},
{
"name": "calendar",
"description": "A date field component that allows users to enter and edit date.",
"usage": "<script setup lang=\"ts\">\nimport { Calendar } from '@/components/ui/calendar'\n</script>\n\n<template>\n <Calendar />\n</template>\n\n\nSee the [VCalendar](https://vcalendar.io/getting-started/installation.html) documentation for more information.",
"examples": [
{
"source": "CalendarDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { Calendar } from '@/components/ui/calendar'\n\nconst date = ref(new Date())\n</script>\n\n<template>\n <Calendar v-model=\"date\" class=\"rounded-md border\" />\n</template>"
}
]
},
{
"name": "card",
"description": "Displays a card with header, content, and footer.",
"usage": "<script setup lang=\"ts\">\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from '@/components/ui/card'\n</script>\n\n<template>\n <Card>\n <CardHeader>\n <CardTitle>Card Title</CardTitle>\n <CardDescription>Card Description</CardDescription>\n </CardHeader>\n <CardContent>\n Card Content\n </CardContent>\n <CardFooter>\n Card Footer\n </CardFooter>\n </Card>\n</template>\n",
"examples": [
{
"source": "CardChat.vue",
"code": "<script setup lang=\"ts\">\nimport { Check, Plus, Send } from 'lucide-vue-next'\nimport { computed, ref } from 'vue'\nimport {\n Card,\n CardContent,\n CardFooter,\n CardHeader,\n} from '@/components/ui/card'\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'\nimport { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '@/components/ui/command'\n\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '@/components/ui/tooltip'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { cn } from '@/lib/utils'\n\nconst input = ref('')\nconst inputLength = computed(() => input.value.trim().length)\nconst users = ref([\n {\n name: 'Olivia Martin',\n email: 'm@example.com',\n avatar: '/avatars/01.png',\n },\n {\n name: 'Isabella Nguyen',\n email: 'isabella.nguyen@email.com',\n avatar: '/avatars/03.png',\n },\n {\n name: 'Emma Wilson',\n email: 'emma@example.com',\n avatar: '/avatars/05.png',\n },\n {\n name: 'Jackson Lee',\n email: 'lee@example.com',\n avatar: '/avatars/02.png',\n },\n {\n name: 'William Kim',\n email: 'will@email.com',\n avatar: '/avatars/04.png',\n },\n])\n\ntype User = (typeof users.value)[number]\n\nconst messages = ref([\n { role: 'agent', content: 'Hi, how can I help you today?' },\n { role: 'user', content: 'Hey, I\\'m having trouble with my account.' },\n { role: 'agent', content: 'What seems to be the problem?' },\n { role: 'user', content: 'I can\\'t log in.' },\n])\n\nconst open = ref(false)\nconst selectedUsers = ref<User[]>([])\n</script>\n\n<template>\n <Card>\n <CardHeader class=\"flex flex-row items-center justify-between\">\n <div class=\"flex items-center space-x-4\">\n <Avatar>\n <AvatarImage src=\"/avatars/01.png\" alt=\"Image\" />\n <AvatarFallback>OM</AvatarFallback>\n </Avatar>\n <div>\n <p class=\"text-sm font-medium leading-none\">\n Sofia Davis\n </p>\n <p class=\"text-sm text-muted-foreground\">\n m@example.com\n </p>\n </div>\n </div>\n <TooltipProvider>\n <Tooltip :delay-duration=\"200\">\n <TooltipTrigger as-child>\n <Button\n variant=\"outline\"\n class=\"rounded-full p-2.5 flex items-center justify-center\"\n @click=\"open = true\"\n >\n <Plus class=\"w-4 h-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent :side-offset=\"10\">\n New message\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </CardHeader>\n <CardContent>\n <div class=\"space-y-4\">\n <div\n v-for=\"(message, index) in messages\"\n :key=\"index\"\n :class=\"cn(\n 'flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm',\n message.role === 'user' ? 'ml-auto bg-primary text-primary-foreground' : 'bg-muted',\n )\"\n >\n {{ message.content }}\n </div>\n </div>\n </CardContent>\n <CardFooter>\n <form\n class=\"flex w-full items-center space-x-2\"\n @submit.prevent=\"() => {\n if (inputLength === 0) return\n messages.push({\n role: 'user',\n content: input,\n })\n }\"\n >\n <Input v-model=\"input\" placeholder=\"Type a message...\" class=\"flex-1\" />\n <Button class=\"p-2.5 flex items-center justify-center\" :disabled=\"inputLength === 0\">\n <Send class=\"w-4 h-4\" />\n <span class=\"sr-only\">Send</span>\n </Button>\n </form>\n </CardFooter>\n </Card>\n\n <Dialog v-model:open=\"open\">\n <DialogContent class=\"gap-0 p-0 outline-none\">\n <DialogHeader class=\"px-4 pb-4 pt-5\">\n <DialogTitle>New message</DialogTitle>\n <DialogDescription>\n Invite a user to this thread. This will create a new group\n message.\n </DialogDescription>\n </DialogHeader>\n <Command\n class=\"overflow-hidden rounded-t-none border-t\"\n :filter-function=\"(list: User[], search) => list.filter(l => l.name.toLowerCase().includes(search.toLowerCase()))\"\n >\n <CommandInput placeholder=\"Search user...\" />\n <CommandList>\n <CommandEmpty>No users found.</CommandEmpty>\n <CommandGroup class=\"p-2\">\n <CommandItem\n v-for=\"user in users\"\n :key=\"user.email\"\n :value=\"user\"\n class=\"flex items-center px-2\"\n @select=\"() => {\n const index = selectedUsers.findIndex(u => u === user)\n if (index !== -1) {\n selectedUsers.splice(index, 1)\n }\n else {\n selectedUsers.push(user)\n }\n }\"\n >\n <Avatar>\n <AvatarImage :src=\"user.avatar\" alt=\"Image\" />\n <AvatarFallback>{{ user.name[0] }}</AvatarFallback>\n </Avatar>\n <div class=\"ml-2\">\n <p class=\"text-sm font-medium leading-none\">\n {{ user.name }}\n </p>\n <p class=\"text-sm text-muted-foreground\">\n {{ user.email }}\n </p>\n </div>\n <Check v-if=\"selectedUsers.includes(user)\" class=\"ml-auto flex h-5 w-5 text-primary\" />\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n <DialogFooter class=\"flex items-center border-t p-4 sm:justify-between\">\n <div v-if=\"selectedUsers.length > 0\" class=\"flex -space-x-2 overflow-hidden\">\n <Avatar\n v-for=\"user in selectedUsers\"\n :key=\"user.email\"\n class=\"inline-block border-2 border-background\"\n >\n <AvatarImage :src=\"user.avatar\" />\n <AvatarFallback>{{ user.name[0] }}</AvatarFallback>\n </Avatar>\n </div>\n\n <p v-else class=\"text-sm text-muted-foreground\">\n Select users to add to this thread.\n </p>\n\n <Button\n :disabled=\"selectedUsers.length < 2\"\n @click=\"open = false\"\n >\n Continue\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n</template>"
},
{
"source": "CardDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { BellRing, Check } from 'lucide-vue-next'\n\nimport { Button } from '@/components/ui/button'\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from '@/components/ui/card'\nimport { Switch } from '@/components/ui/switch'\nimport { cn } from '@/lib/utils'\n\nconst notifications = [\n {\n title: 'Your call has been confirmed.',\n description: '1 hour ago',\n },\n {\n title: 'You have a new message!',\n description: '1 hour ago',\n },\n {\n title: 'Your subscription is expiring soon!',\n description: '2 hours ago',\n },\n]\n</script>\n\n<template>\n <Card :class=\"cn('w-[380px]', $attrs.class ?? '')\">\n <CardHeader>\n <CardTitle>Notifications</CardTitle>\n <CardDescription>You have 3 unread messages.</CardDescription>\n </CardHeader>\n <CardContent class=\"grid gap-4\">\n <div class=\" flex items-center space-x-4 rounded-md border p-4\">\n <BellRing />\n <div class=\"flex-1 space-y-1\">\n <p class=\"text-sm font-medium leading-none\">\n Push Notifications\n </p>\n <p class=\"text-sm text-muted-foreground\">\n Send notifications to device.\n </p>\n </div>\n <Switch />\n </div>\n <div>\n <div\n v-for=\"(notification, index) in notifications\" :key=\"index\"\n class=\"mb-4 grid grid-cols-[25px_1fr] items-start pb-4 last:mb-0 last:pb-0\"\n >\n <span class=\"flex h-2 w-2 translate-y-1 rounded-full bg-sky-500\" />\n <div class=\"space-y-1\">\n <p class=\"text-sm font-medium leading-none\">\n {{ notification.title }}\n </p>\n <p class=\"text-sm text-muted-foreground\">\n {{ notification.description }}\n </p>\n </div>\n </div>\n </div>\n </CardContent>\n <CardFooter>\n <Button class=\"w-full\">\n <Check class=\"mr-2 h-4 w-4\" /> Mark all as read\n </Button>\n </CardFooter>\n </Card>\n</template>"
},
{
"source": "CardFormDemo.vue",
"code": "<script setup lang='ts'>\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <Card class=\"w-[350px]\">\n <CardHeader>\n <CardTitle>Create project</CardTitle>\n <CardDescription>Deploy your new project in one-click.</CardDescription>\n </CardHeader>\n <CardContent>\n <form>\n <div class=\"grid items-center w-full gap-4\">\n <div class=\"flex flex-col space-y-1.5\">\n <Label for=\"name\">Name</Label>\n <Input id=\"name\" placeholder=\"Name of your project\" />\n </div>\n <div class=\"flex flex-col space-y-1.5\">\n <Label for=\"framework\">Framework</Label>\n <Select>\n <SelectTrigger id=\"framework\">\n <SelectValue placeholder=\"Select\" />\n </SelectTrigger>\n <SelectContent position=\"popper\">\n <SelectItem value=\"nuxt\">\n Nuxt.js\n </SelectItem>\n <SelectItem value=\"next\">\n Next.js\n </SelectItem>\n <SelectItem value=\"sveltekit\">\n SvelteKit\n </SelectItem>\n <SelectItem value=\"astro\">\n Astro\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n </div>\n </form>\n </CardContent>\n <CardFooter class=\"flex justify-between px-6 pb-6\">\n <Button variant=\"outline\">\n Cancel\n </Button>\n <Button>Deploy</Button>\n </CardFooter>\n </Card>\n</template>"
},
{
"source": "CardStats.vue",
"code": "<script setup lang=\"ts\">\nimport { VisLine, VisScatter, VisStackedBar, VisXYContainer } from '@unovis/vue'\nimport { computed } from 'vue'\nimport { useData } from 'vitepress'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { useConfigStore } from '@/stores/config'\nimport { themes } from '@/lib/registry/themes'\n\ntype Data = typeof data[number]\nconst data = [\n { revenue: 10400, subscription: 240 },\n { revenue: 14405, subscription: 300 },\n { revenue: 9400, subscription: 200 },\n { revenue: 8200, subscription: 278 },\n { revenue: 7000, subscription: 189 },\n { revenue: 9600, subscription: 239 },\n { revenue: 11244, subscription: 278 },\n { revenue: 26475, subscription: 189 },\n]\n\nconst cfg = useConfigStore()\n\nconst { isDark } = useData()\nconst theme = computed(() => themes.find(theme => theme.name === cfg.config.value.theme))\n\nconst lineX = (d: Data, i: number) => i\nconst lineY = (d: Data) => d.revenue\n</script>\n\n<template>\n <div class=\"grid gap-4 sm:grid-cols-2 xl:grid-cols-2\">\n <Card>\n <CardHeader class=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle class=\"text-sm font-normal\">\n Total Revenue\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div class=\"text-2xl font-bold\">\n $15,231.89\n </div>\n <p class=\"text-xs text-muted-foreground\">\n +20.1% from last month\n </p>\n\n <div class=\"h-[80px]\">\n <VisXYContainer\n height=\"80px\"\n :data=\"data\" :margin=\"{\n top: 5,\n right: 10,\n left: 10,\n bottom: 0,\n }\"\n :style=\"{\n '--theme-primary': `hsl(${\n theme?.cssVars[isDark ? 'dark' : 'light'].primary\n })`,\n }\"\n >\n <VisLine :x=\"lineX\" :y=\"lineY\" color=\"var(--theme-primary)\" />\n <VisScatter :x=\"lineX\" :y=\"lineY\" :size=\"6\" stroke-color=\"var(--theme-primary)\" :stroke-width=\"2\" color=\"white\" />\n </VisXYContainer>\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader class=\"pb-2\">\n <CardTitle class=\"text-lg\">\n Subscriptions\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div class=\"text-2xl font-bold\">\n +2,350\n </div>\n <p class=\"text-xs text-muted-foreground\">\n +54.8% from last month\n </p>\n\n <div class=\"mt-4 h-[80px]\">\n <VisXYContainer\n height=\"80px\" :data=\"data\" :style=\"{\n '--theme-primary': `hsl(${\n theme?.cssVars[isDark ? 'dark' : 'light'].primary\n })`,\n }\"\n >\n <VisStackedBar\n :x=\"lineX\"\n :y=\"(d: Data) => d.subscription\"\n :bar-padding=\"0.1\"\n :rounded-corners=\"0\" color=\"var(--theme-primary)\"\n />\n </VisXYContainer>\n </div>\n </CardContent>\n </Card>\n </div>\n</template>"
},
{
"source": "CardWithForm.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\n</script>\n\n<template>\n <Card class=\"w-[350px]\">\n <CardHeader>\n <CardTitle>Create project</CardTitle>\n <CardDescription>Deploy your new project in one-click.</CardDescription>\n </CardHeader>\n <CardContent>\n <form>\n <div class=\"grid w-full items-center gap-4\">\n <div class=\"flex flex-col space-y-1.5\">\n <Label for=\"name\">Name</Label>\n <Input id=\"name\" placeholder=\"Name of your project\" />\n </div>\n <div class=\"flex flex-col space-y-1.5\">\n <Label for=\"framework\">Framework</Label>\n <Select>\n <SelectTrigger id=\"framework\">\n <SelectValue placeholder=\"Select\" />\n </SelectTrigger>\n <SelectContent position=\"popper\">\n <SelectItem value=\"next\">\n Next.js\n </SelectItem>\n <SelectItem value=\"sveltekit\">\n SvelteKit\n </SelectItem>\n <SelectItem value=\"astro\">\n Astro\n </SelectItem>\n <SelectItem value=\"nuxt\">\n Nuxt.js\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n </div>\n </form>\n </CardContent>\n <CardFooter class=\"flex justify-between\">\n <Button variant=\"outline\">\n Cancel\n </Button>\n <Button>Deploy</Button>\n </CardFooter>\n </Card>\n</template>"
}
]
},
{
"name": "checkbox",
"description": "A control that allows the user to toggle between checked and not checked.",
"usage": "<script setup lang=\"ts\">\nimport { Checkbox } from '@/components/ui/checkbox'\n</script>\n\n<template>\n <Checkbox id=\"terms\" />\n</template>\n",
"examples": [
{
"source": "CheckboxDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Checkbox } from '@/components/ui/checkbox'\n</script>\n\n<template>\n <div class=\"flex items-center space-x-2\">\n <Checkbox id=\"terms\" />\n <label\n for=\"terms\"\n class=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n Accept terms and conditions\n </label>\n </div>\n</template>"
},
{
"source": "CheckboxDisabled.vue",
"code": "<script setup lang=\"ts\">\nimport { Checkbox } from '@/components/ui/checkbox'\n</script>\n\n<template>\n <div class=\"items-top flex space-x-2\">\n <Checkbox id=\"terms1\" disabled />\n <label\n for=\"terms2\"\n class=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n Accept terms and conditions\n </label>\n </div>\n</template>"
},
{
"source": "CheckboxFormMultiple.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport { toast } from '@/components/ui/toast'\n\nconst items = [\n {\n id: 'recents',\n label: 'Recents',\n },\n {\n id: 'home',\n label: 'Home',\n },\n {\n id: 'applications',\n label: 'Applications',\n },\n {\n id: 'desktop',\n label: 'Desktop',\n },\n {\n id: 'downloads',\n label: 'Downloads',\n },\n {\n id: 'documents',\n label: 'Documents',\n },\n] as const\n\nconst formSchema = toTypedSchema(z.object({\n items: z.array(z.string()).refine(value => value.some(item => item), {\n message: 'You have to select at least one item.',\n }),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n initialValues: {\n items: ['recents', 'home'],\n },\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form @submit=\"onSubmit\">\n <FormField name=\"items\">\n <FormItem>\n <div class=\"mb-4\">\n <FormLabel class=\"text-base\">\n Sidebar\n </FormLabel>\n <FormDescription>\n Select the items you want to display in the sidebar.\n </FormDescription>\n </div>\n\n <FormField v-for=\"item in items\" v-slot=\"{ value, handleChange }\" :key=\"item.id\" type=\"checkbox\" :value=\"item.id\" :unchecked-value=\"false\" name=\"items\">\n <FormItem class=\"flex flex-row items-start space-x-3 space-y-0\">\n <FormControl>\n <Checkbox\n :checked=\"value.includes(item.id)\"\n @update:checked=\"handleChange\"\n />\n </FormControl>\n <FormLabel class=\"font-normal\">\n {{ item.label }}\n </FormLabel>\n </FormItem>\n </FormField>\n <FormMessage />\n </FormItem>\n </FormField>\n\n <div class=\"flex justify-start mt-4\">\n <Button type=\"submit\">\n Submit\n </Button>\n </div>\n </form>\n</template>"
},
{
"source": "CheckboxFormSingle.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n mobile: z.boolean().default(false).optional(),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n initialValues: {\n mobile: true,\n },\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-6\" @submit=\"onSubmit\">\n <FormField v-slot=\"{ value, handleChange }\" type=\"checkbox\" name=\"mobile\">\n <FormItem class=\"flex flex-row items-start gap-x-3 space-y-0 rounded-md border p-4\">\n <FormControl>\n <Checkbox :checked=\"value\" @update:checked=\"handleChange\" />\n </FormControl>\n <div class=\"space-y-1 leading-none\">\n <FormLabel>Use different settings for my mobile devices</FormLabel>\n <FormDescription>\n You can manage your mobile notifications in the\n <a href=\"/examples/forms\">mobile settings</a> page.\n </FormDescription>\n <FormMessage />\n </div>\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>"
},
{
"source": "CheckboxWithText.vue",
"code": "<script setup lang=\"ts\">\nimport { Checkbox } from '@/components/ui/checkbox'\n</script>\n\n<template>\n <div class=\"items-top flex gap-x-2\">\n <Checkbox id=\"terms1\" />\n <div class=\"grid gap-1.5 leading-none\">\n <label\n for=\"terms1\"\n class=\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n Accept terms and conditions\n </label>\n <p class=\"text-sm text-muted-foreground\">\n You agree to our Terms of Service and Privacy Policy.\n </p>\n </div>\n </div>\n</template>"
}
]
},
{
"name": "collapsible",
"description": "An interactive component which expands/collapses a panel.",
"usage": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '@/components/ui/collapsible'\n\nconst isOpen = ref(false)\n</script>\n\n<template>\n <Collapsible v-model:open=\"isOpen\">\n <CollapsibleTrigger>Can I use this in my project?</CollapsibleTrigger>\n <CollapsibleContent>\n Yes. Free to use for personal and commercial projects. No attribution\n required.\n </CollapsibleContent>\n </Collapsible>\n</template>\n",
"examples": [
{
"source": "CollapsibleDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ChevronsUpDown } from 'lucide-vue-next'\n\nimport { ref } from 'vue'\nimport { Button } from '@/components/ui/button'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '@/components/ui/collapsible'\n\nconst isOpen = ref(false)\n</script>\n\n<template>\n <Collapsible\n v-model:open=\"isOpen\"\n class=\"w-[350px] space-y-2\"\n >\n <div class=\"flex items-center justify-between space-x-4 px-4\">\n <h4 class=\"text-sm font-semibold\">\n @peduarte starred 3 repositories\n </h4>\n <CollapsibleTrigger as-child>\n <Button variant=\"ghost\" size=\"sm\" class=\"w-9 p-0\">\n <ChevronsUpDown class=\"h-4 w-4\" />\n <span class=\"sr-only\">Toggle</span>\n </Button>\n </CollapsibleTrigger>\n </div>\n <div class=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @radix-ui/primitives\n </div>\n <CollapsibleContent class=\"space-y-2\">\n <div class=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @radix-ui/colors\n </div>\n <div class=\"rounded-md border px-4 py-3 font-mono text-sm\">\n @stitches/react\n </div>\n </CollapsibleContent>\n </Collapsible>\n</template>"
}
]
},
{
"name": "combobox",
"description": "Autocomplete input and command palette with a list of suggestions.",
"usage": "<script setup lang=\"ts\">\nimport { Check, ChevronsUpDown } from 'lucide-vue-next'\n\nimport { ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from '@/components/ui/command'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\n\nconst frameworks = [\n { value: 'next.js', label: 'Next.js' },\n { value: 'sveltekit', label: 'SvelteKit' },\n { value: 'nuxt.js', label: 'Nuxt.js' },\n { value: 'remix', label: 'Remix' },\n { value: 'astro', label: 'Astro' },\n]\n\nconst open = ref(false)\nconst value = ref({})\n</script>\n\n<template>\n <Popover v-model:open=\"open\">\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n class=\"w-[200px] justify-between\"\n >\n {{ value ? frameworks.find((framework) => framework.value === value)?.label : 'Select framework...' }}\n\n <ChevronsUpDown class=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-[200px] p-0\">\n <Command v-model=\"value\">\n <CommandInput placeholder=\"Search framework...\" />\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n <CommandItem\n v-for=\"framework in frameworks\"\n :key=\"framework.value\"\n :value=\"framework\"\n @select=\"open = false\"\n >\n <Check\n :class=\"cn(\n 'mr-2 h-4 w-4',\n value === framework.value ? 'opacity-100' : 'opacity-0',\n )\"\n />\n {{ framework.label }}\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n</template>\n",
"examples": [
{
"source": "ComboboxDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Check, ChevronsUpDown } from 'lucide-vue-next'\n\nimport { ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/components/ui/command'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\n\nconst frameworks = [\n { value: 'next.js', label: 'Next.js' },\n { value: 'sveltekit', label: 'SvelteKit' },\n { value: 'nuxt.js', label: 'Nuxt.js' },\n { value: 'remix', label: 'Remix' },\n { value: 'astro', label: 'Astro' },\n]\n\nconst open = ref(false)\nconst value = ref<typeof frameworks[number]>()\n\nconst filterFunction = (list: typeof frameworks, search: string) => list.filter(i => i.value.toLowerCase().includes(search.toLowerCase()))\n</script>\n\n<template>\n <Popover v-model:open=\"open\">\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n :aria-expanded=\"open\"\n class=\"w-[200px] justify-between\"\n >\n {{ value ? value.label : 'Select framework...' }}\n <ChevronsUpDown class=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-[200px] p-0\">\n <Command :filter-function=\"filterFunction\">\n <CommandInput placeholder=\"Search framework...\" />\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n <CommandItem\n v-for=\"framework in frameworks\"\n :key=\"framework.value\"\n :value=\"framework\"\n @select=\"(ev) => {\n value = ev.detail.value\n console.log(ev)\n open = false\n }\"\n >\n <Check\n :class=\"cn(\n 'mr-2 h-4 w-4',\n value?.value === framework.value ? 'opacity-100' : 'opacity-0',\n )\"\n />\n {{ framework.label }}\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n</template>"
},
{
"source": "ComboboxDropdownMenu.vue",
"code": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { Calendar, MoreHorizontal, Tags, Trash, User } from 'lucide-vue-next'\n\nimport { Button } from '@/components/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/components/ui/command'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\n\nconst labels = [\n 'feature',\n 'bug',\n 'enhancement',\n 'documentation',\n 'design',\n 'question',\n 'maintenance',\n]\n\nconst labelRef = ref('feature')\nconst open = ref(false)\n</script>\n\n<template>\n <div class=\"flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center\">\n <p class=\"text-sm font-medium leading-none\">\n <span class=\"mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground\">\n {{ labelRef }}\n </span>\n <span class=\"text-muted-foreground\">Create a new project</span>\n </p>\n <DropdownMenu v-model:open=\"open\">\n <DropdownMenuTrigger as-child>\n <Button variant=\"ghost\" size=\"sm\">\n <MoreHorizontal />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" class=\"w-[200px]\">\n <DropdownMenuLabel>Actions</DropdownMenuLabel>\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <User class=\"mr-2 h-4 w-4\" />\n Assign to...\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Calendar class=\"mr-2 h-4 w-4\" />\n Set due date...\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n <Tags class=\"mr-2 h-4 w-4\" />\n Apply label\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent class=\"p-0\">\n <Command>\n <CommandInput\n placeholder=\"Filter label...\"\n auto-focus\n />\n <CommandList>\n <CommandEmpty>No label found.</CommandEmpty>\n <CommandGroup>\n <CommandItem\n v-for=\"label in labels\"\n :key=\"label\"\n :value=\"label\"\n @select=\"(ev) => {\n labelRef = ev.detail.value as string\n open = false\n }\"\n >\n {{ label }}\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n <DropdownMenuSeparator />\n <DropdownMenuItem class=\"text-red-600\">\n <Trash class=\"mr-2 h-4 w-4\" />\n Delete\n <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n</template>"
},
{
"source": "ComboboxForm.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Check, ChevronsUpDown } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/components/ui/command'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\nimport { toast } from '@/components/ui/toast'\n\nconst languages = [\n { label: 'English', value: 'en' },\n { label: 'French', value: 'fr' },\n { label: 'German', value: 'de' },\n { label: 'Spanish', value: 'es' },\n { label: 'Portuguese', value: 'pt' },\n { label: 'Russian', value: 'ru' },\n { label: 'Japanese', value: 'ja' },\n { label: 'Korean', value: 'ko' },\n { label: 'Chinese', value: 'zh' },\n]\n\nconst formSchema = toTypedSchema(z.object({\n language: z.string({\n required_error: 'Please select a language.',\n }),\n}))\n\nconst { handleSubmit, setValues, values } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-6\" @submit=\"onSubmit\">\n <FormField name=\"language\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Language</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n :class=\"cn('w-[200px] justify-between', !values.language && 'text-muted-foreground')\"\n >\n {{ values.language ? languages.find(\n (language) => language.value === values.language,\n )?.label : 'Select language...' }}\n <ChevronsUpDown class=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search language...\" />\n <CommandEmpty>Nothing found.</CommandEmpty>\n <CommandList>\n <CommandGroup>\n <CommandItem\n v-for=\"language in languages\"\n :key=\"language.value\"\n :value=\"language.label\"\n @select=\"() => {\n setValues({\n language: language.value,\n })\n }\"\n >\n <Check\n :class=\"cn('mr-2 h-4 w-4', language.value === values.language ? 'opacity-100' : 'opacity-0')\"\n />\n {{ language.label }}\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <FormDescription>\n This is the language that will be used in the dashboard.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n\n <Button type=\"submit\">\n Submit\n </Button>\n </form>\n</template>"
},
{
"source": "ComboboxPopover.vue",
"code": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport {\n ArrowUpCircle,\n CheckCircle2,\n Circle,\n HelpCircle,\n XCircle,\n} from 'lucide-vue-next'\nimport type { Icon } from 'lucide-vue-next'\n\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from '@/components/ui/command'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\n\ninterface Status {\n value: string\n label: string\n icon: Icon\n}\n\nconst statuses: Status[] = [\n {\n value: 'backlog',\n label: 'Backlog',\n icon: HelpCircle,\n },\n {\n value: 'todo',\n label: 'Todo',\n icon: Circle,\n },\n {\n value: 'in progress',\n label: 'In Progress',\n icon: ArrowUpCircle,\n },\n {\n value: 'done',\n label: 'Done',\n icon: CheckCircle2,\n },\n {\n value: 'canceled',\n label: 'Canceled',\n icon: XCircle,\n },\n]\n\nconst open = ref(false)\nconst value = ref<typeof statuses[number]>()\n\nconst selectedStatus = ref<Status>()\n</script>\n\n<template>\n <div class=\"flex items-center space-x-4\">\n <p class=\"text-sm text-muted-foreground\">\n Status\n </p>\n <Popover v-model:open=\"open\">\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n size=\"sm\"\n class=\"w-[150px] justify-start\"\n >\n <template v-if=\"selectedStatus\">\n <component :is=\"selectedStatus?.icon\" class=\"mr-2 h-4 w-4 shrink-0\" />\n {{ selectedStatus?.label }}\n </template>\n <template v-else>\n + Set status\n </template>\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"p-0\" side=\"right\" align=\"start\">\n <Command>\n <CommandInput placeholder=\"Change status...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup>\n <CommandItem\n v-for=\"status in statuses\"\n :key=\"status.value\"\n :value=\"status.value\"\n @select=\"(value) => {\n selectedStatus = status\n open = false\n }\"\n >\n <component\n :is=\"status.icon\"\n :key=\"status.value\"\n :class=\"cn('mr-2 h-4 w-4', status.value === selectedStatus?.value ? 'opacity-100' : 'opacity-40',\n )\"\n />\n <span>{{ status.label }}</span>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n</template>"
}
]
},
{
"name": "command",
"description": "Fast, composable, unstyled command menu.",
"usage": "<script setup lang=\"ts\">\nimport {\n Command,\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from '@/components/ui/command'\n</script>\n\n<template>\n <Command>\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem value=\"calendar\">\n Calendar\n </CommandItem>\n <CommandItem value=\"search-emoji\">\n Search Emoji\n </CommandItem>\n <CommandItem value=\"calculator\">\n Calculator\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem value=\"profile\">\n Profile\n </CommandItem>\n <CommandItem value=\"billing\">\n Billing\n </CommandItem>\n <CommandItem value=\"settings\">\n Settings\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n</template>\n",
"examples": [
{
"source": "CommandDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from 'lucide-vue-next'\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from '@/components/ui/command'\n</script>\n\n<template>\n <Command class=\"rounded-lg border shadow-md max-w-[450px]\">\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem value=\"Calendar\">\n <Calendar class=\"mr-2 h-4 w-4\" />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem value=\"Search Emoji\">\n <Smile class=\"mr-2 h-4 w-4\" />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem value=\"Calculator\">\n <Calculator class=\"mr-2 h-4 w-4\" />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem value=\"Profile\">\n <User class=\"mr-2 h-4 w-4\" />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem value=\"Billing\">\n <CreditCard class=\"mr-2 h-4 w-4\" />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem value=\"Settings\">\n <Settings class=\"mr-2 h-4 w-4\" />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n</template>"
},
{
"source": "CommandDialogDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { useMagicKeys } from '@vueuse/core'\n\nimport { ref, watch } from 'vue'\nimport {\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '@/components/ui/command'\n\nconst open = ref(false)\n\nconst keys = useMagicKeys()\nconst CmdJ = keys['Cmd+J']\n\nfunction handleOpenChange() {\n open.value = !open.value\n}\n\nwatch(CmdJ, (v) => {\n if (v)\n handleOpenChange()\n})\n</script>\n\n<template>\n <div>\n <p class=\"text-sm text-muted-foreground\">\n Press\n <kbd\n class=\"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100\"\n >\n <span class=\"text-xs\">⌘</span>J\n </kbd>\n </p>\n <CommandDialog :open=\"open\" :on-open-change=\"handleOpenChange\">\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem value=\"calendar\">\n Calendar\n </CommandItem>\n <CommandItem value=\"search-emoji\">\n Search Emoji\n </CommandItem>\n <CommandItem value=\"calculator\">\n Calculator\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem value=\"profile\">\n Profile\n </CommandItem>\n <CommandItem value=\"billing\">\n Billing\n </CommandItem>\n <CommandItem value=\"settings\">\n Settings\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </CommandDialog>\n </div>\n</template>"
}
]
},
{
"name": "context-menu",
"description": "Displays a menu to the user — such as a set of actions or functions — triggered by a button.",
"usage": "<script setup lang=\"ts\">\nimport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from '@/components/ui/context-menu'\n</script>\n\n<template>\n <ContextMenu>\n <ContextMenuTrigger>Right click</ContextMenuTrigger>\n <ContextMenuContent>\n <ContextMenuItem>Profile</ContextMenuItem>\n <ContextMenuItem>Billing</ContextMenuItem>\n <ContextMenuItem>Team</ContextMenuItem>\n <ContextMenuItem>Subscription</ContextMenuItem>\n </ContextMenuContent>\n </ContextMenu>\n</template>\n",
"examples": [
{
"source": "ContextMenuDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from '@/components/ui/context-menu'\n</script>\n\n<template>\n <ContextMenu>\n <ContextMenuTrigger class=\"flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm\">\n Right click here\n </ContextMenuTrigger>\n <ContextMenuContent class=\"w-64\">\n <ContextMenuItem inset>\n Back\n <ContextMenuShortcut>⌘[</ContextMenuShortcut>\n </ContextMenuItem>\n <ContextMenuItem inset disabled>\n Forward\n <ContextMenuShortcut>⌘]</ContextMenuShortcut>\n </ContextMenuItem>\n <ContextMenuItem inset>\n Reload\n <ContextMenuShortcut>⌘R</ContextMenuShortcut>\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger inset>\n More Tools\n </ContextMenuSubTrigger>\n <ContextMenuSubContent class=\"w-48\">\n <ContextMenuItem>\n Save Page As...\n <ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>\n </ContextMenuItem>\n <ContextMenuItem>Create Shortcut...</ContextMenuItem>\n <ContextMenuItem>Name Window...</ContextMenuItem>\n <ContextMenuSeparator />\n <ContextMenuItem>Developer Tools</ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n <ContextMenuSeparator />\n <ContextMenuCheckboxItem checked>\n Show Bookmarks Bar\n <ContextMenuShortcut>⌘⇧B</ContextMenuShortcut>\n </ContextMenuCheckboxItem>\n <ContextMenuCheckboxItem>Show Full URLs</ContextMenuCheckboxItem>\n <ContextMenuSeparator />\n <ContextMenuRadioGroup model-value=\"pedro\">\n <ContextMenuLabel inset>\n People\n </ContextMenuLabel>\n <ContextMenuSeparator />\n <ContextMenuRadioItem value=\"pedro\">\n Pedro Duarte\n </ContextMenuRadioItem>\n <ContextMenuRadioItem value=\"colm\">\n Colm Tuite\n </ContextMenuRadioItem>\n </ContextMenuRadioGroup>\n </ContextMenuContent>\n </ContextMenu>\n</template>"
}
]
},
{
"name": "date-picker",
"description": "A date picker component with range and presets.",
"usage": "<script setup lang=\"ts\">\nimport { format } from 'date-fns'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\n\nimport { ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Calendar } from '@/components/ui/calendar'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\n\nconst date = ref<Date>()\n</script>\n\n<template>\n <Popover>\n <PopoverTrigger as-child>\n <Button\n :variant=\"'outline'\"\n :class=\"cn(\n 'w-[280px] justify-start text-left font-normal',\n !date && 'text-muted-foreground',\n )\"\n >\n <CalendarIcon class=\"mr-2 h-4 w-4\" />\n <span>{{ date ? format(date, \"PPP\") : \"Pick a date\" }}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar v-model=\"date\" />\n </PopoverContent>\n </Popover>\n</template>\n",
"examples": [
{
"source": "DatePickerDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { format } from 'date-fns'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\n\nimport { ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Calendar } from '@/components/ui/calendar'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\n\nconst date = ref<Date>()\n</script>\n\n<template>\n <Popover>\n <PopoverTrigger as-child>\n <Button\n :variant=\"'outline'\"\n :class=\"cn(\n 'w-[280px] justify-start text-left font-normal',\n !date && 'text-muted-foreground',\n )\"\n >\n <CalendarIcon class=\"mr-2 h-4 w-4\" />\n <span>{{ date ? format(date, \"PPP\") : \"Pick a date\" }}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\">\n <Calendar v-model=\"date\" />\n </PopoverContent>\n </Popover>\n</template>"
},
{
"source": "DatePickerForm.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { format } from 'date-fns'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Calendar } from '@/components/ui/calendar'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\n\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n dob: z.date({\n required_error: 'A date of birth is required.',\n }),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"space-y-8\" @submit=\"onSubmit\">\n <FormField v-slot=\"{ componentField, value }\" name=\"dob\">\n <FormItem class=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger as-child>\n <FormControl>\n <Button\n variant=\"outline\" :class=\"cn(\n 'w-[240px] ps-3 text-start font-normal',\n !value && 'text-muted-foreground',\n )\"\n >\n <span>{{ value ? format(value, \"PPP\") : \"Pick a date\" }}</span>\n <CalendarIcon class=\"ms-auto h-4 w-4 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent class=\"p-0\">\n <Calendar v-bind=\"componentField\" />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>"
},
{
"source": "DatePickerWithPresets.vue",
"code": "<script setup lang=\"ts\">\nimport { addDays, format } from 'date-fns'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\n\nimport { ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Calendar } from '@/components/ui/calendar'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\n\nconst date = ref<Date>()\n</script>\n\n<template>\n <Popover>\n <PopoverTrigger as-child>\n <Button\n variant=\"outline\"\n :class=\"cn(\n 'w-[280px] justify-start text-left font-normal',\n !date && 'text-muted-foreground',\n )\"\n >\n <CalendarIcon class=\"mr-2 h-4 w-4\" />\n <template v-if=\"date\">\n {{ format(date, \"PPP\") }}\n </template>\n <template v-else>\n <span>Pick a date</span>\n </template>\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"flex w-auto flex-col space-y-2 p-2\">\n <Select\n @update:model-value=\"(value) => {\n date = addDays(new Date(), parseInt(value))\n }\"\n >\n <SelectTrigger>\n <SelectValue placeholder=\"Select\" />\n </SelectTrigger>\n <SelectContent position=\"popper\">\n <SelectItem value=\"0\">\n Today\n </SelectItem>\n <SelectItem value=\"1\">\n Tomorrow\n </SelectItem>\n <SelectItem value=\"3\">\n In 3 days\n </SelectItem>\n <SelectItem value=\"7\">\n In a week\n </SelectItem>\n </SelectContent>\n </Select>\n <div class=\"rounded-md border\">\n <Calendar v-model=\"date\" mode=\"single\" />\n </div>\n </PopoverContent>\n </Popover>\n</template>"
},
{
"source": "DatePickerWithRange.vue",
"code": "<script setup lang=\"ts\">\nimport { addDays, format } from 'date-fns'\nimport { Calendar as CalendarIcon } from 'lucide-vue-next'\n\nimport { ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Calendar } from '@/components/ui/calendar'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\n\nconst date = ref({\n start: new Date(2022, 0, 20),\n end: addDays(new Date(2022, 0, 20), 20),\n})\n</script>\n\n<template>\n <div :class=\"cn('grid gap-2', $attrs.class ?? '')\">\n <Popover>\n <PopoverTrigger as-child>\n <Button\n id=\"date\"\n :variant=\"'outline'\"\n :class=\"cn(\n 'w-[300px] justify-start text-left font-normal',\n !date && 'text-muted-foreground',\n )\"\n >\n <CalendarIcon class=\"mr-2 h-4 w-4\" />\n\n <span>\n {{ date.start ? (\n date.end ? `${format(date.start, 'LLL dd, y')} - ${format(date.end, 'LLL dd, y')}`\n : format(date.start, 'LLL dd, y')\n ) : 'Pick a date' }}\n </span>\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-auto p-0\" align=\"start\" :avoid-collisions=\"true\">\n <Calendar\n v-model.range=\"date\"\n :columns=\"2\"\n />\n </PopoverContent>\n </Popover>\n </div>\n</template>"
}
]
},
{
"name": "dialog",
"description": "A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.",
"usage": "<script setup lang=\"ts\">\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/components/ui/dialog'\n</script>\n\n<template>\n <Dialog>\n <DialogTrigger>\n Edit Profile\n </DialogTrigger>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you're done.\n </DialogDescription>\n </DialogHeader>\n\n <DialogFooter>\n Save changes\n </DialogFooter>\n </DialogContent>\n </Dialog>\n</template>\n",
"examples": [
{
"source": "DialogCustomCloseButton.vue",
"code": "<script setup lang=\"ts\">\nimport { Copy } from 'lucide-vue-next'\nimport { Button } from '@/components/ui/button'\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/components/ui/dialog'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <Dialog>\n <DialogTrigger as-child>\n <Button variant=\"outline\">\n Share\n </Button>\n </DialogTrigger>\n <DialogContent class=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>Share link</DialogTitle>\n <DialogDescription>\n Anyone who has this link will be able to view this.\n </DialogDescription>\n </DialogHeader>\n <div class=\"flex items-center space-x-2\">\n <div class=\"grid flex-1 gap-2\">\n <Label for=\"link\" class=\"sr-only\">\n Link\n </Label>\n <Input\n id=\"link\"\n default-value=\"https://shadcn-vue.com/docs/installation\"\n read-only\n />\n </div>\n <Button type=\"submit\" size=\"sm\" class=\"px-3\">\n <span class=\"sr-only\">Copy</span>\n <Copy class=\"w-4 h-4\" />\n </Button>\n </div>\n <DialogFooter class=\"sm:justify-start\">\n <DialogClose as-child>\n <Button type=\"button\" variant=\"secondary\">\n Close\n </Button>\n </DialogClose>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n</template>"
},
{
"source": "DialogDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/components/ui/dialog'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <Dialog>\n <DialogTrigger as-child>\n <Button variant=\"outline\">\n Edit Profile\n </Button>\n </DialogTrigger>\n <DialogContent class=\"sm:max-w-[425px]\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you're done.\n </DialogDescription>\n </DialogHeader>\n <div class=\"grid gap-4 py-4\">\n <div class=\"grid grid-cols-4 items-center gap-4\">\n <Label for=\"name\" class=\"text-right\">\n Name\n </Label>\n <Input id=\"name\" value=\"Pedro Duarte\" class=\"col-span-3\" />\n </div>\n <div class=\"grid grid-cols-4 items-center gap-4\">\n <Label for=\"username\" class=\"text-right\">\n Username\n </Label>\n <Input id=\"username\" value=\"@peduarte\" class=\"col-span-3\" />\n </div>\n </div>\n <DialogFooter>\n <Button type=\"submit\">\n Save changes\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n</template>"
}
]
},
{
"name": "dropdown-menu",
"description": "Displays a menu to the user — such as a set of actions or functions — triggered by a button.",
"usage": "<script setup lang=\"ts\">\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\n</script>\n\n<template>\n <DropdownMenu>\n <DropdownMenuTrigger>Open</DropdownMenuTrigger>\n <DropdownMenuContent>\n <DropdownMenuLabel>My Account</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuItem>Profile</DropdownMenuItem>\n <DropdownMenuItem>Billing</DropdownMenuItem>\n <DropdownMenuItem>Team</DropdownMenuItem>\n <DropdownMenuItem>Subscription</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n</template>\n",
"examples": [
{
"source": "DropdownMenuDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n Cloud,\n CreditCard,\n Github,\n Keyboard,\n LifeBuoy,\n LogOut,\n Mail,\n MessageSquare,\n Plus,\n PlusCircle,\n Settings,\n User,\n UserPlus,\n Users,\n} from 'lucide-vue-next'\n\nimport { Button } from '@/components/ui/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\n</script>\n\n<template>\n <DropdownMenu>\n <DropdownMenuTrigger as-child>\n <Button variant=\"outline\">\n Open\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent class=\"w-56\">\n <DropdownMenuLabel>My Account</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <User class=\"mr-2 h-4 w-4\" />\n <span>Profile</span>\n <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <CreditCard class=\"mr-2 h-4 w-4\" />\n <span>Billing</span>\n <DropdownMenuShortcut>⌘B</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Settings class=\"mr-2 h-4 w-4\" />\n <span>Settings</span>\n <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <Keyboard class=\"mr-2 h-4 w-4\" />\n <span>Keyboard shortcuts</span>\n <DropdownMenuShortcut>⌘K</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <Users class=\"mr-2 h-4 w-4\" />\n <span>Team</span>\n </DropdownMenuItem>\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n <UserPlus class=\"mr-2 h-4 w-4\" />\n <span>Invite users</span>\n </DropdownMenuSubTrigger>\n <DropdownMenuPortal>\n <DropdownMenuSubContent>\n <DropdownMenuItem>\n <Mail class=\"mr-2 h-4 w-4\" />\n <span>Email</span>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <MessageSquare class=\"mr-2 h-4 w-4\" />\n <span>Message</span>\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n <PlusCircle class=\"mr-2 h-4 w-4\" />\n <span>More...</span>\n </DropdownMenuItem>\n </DropdownMenuSubContent>\n </DropdownMenuPortal>\n </DropdownMenuSub>\n <DropdownMenuItem>\n <Plus class=\"mr-2 h-4 w-4\" />\n <span>New Team</span>\n <DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n <Github class=\"mr-2 h-4 w-4\" />\n <span>GitHub</span>\n </DropdownMenuItem>\n <DropdownMenuItem>\n <LifeBuoy class=\"mr-2 h-4 w-4\" />\n <span>Support</span>\n </DropdownMenuItem>\n <DropdownMenuItem disabled>\n <Cloud class=\"mr-2 h-4 w-4\" />\n <span>API</span>\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n <LogOut class=\"mr-2 h-4 w-4\" />\n <span>Log out</span>\n <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n</template>"
}
]
},
{
"name": "hover-card",
"description": "For sighted users to preview content available behind a link.",
"usage": "<script setup lang=\"ts\">\nimport {\n HoverCard,\n HoverCardContent,\n HoverCardTrigger,\n} from '@/components/ui/hover-card'\n</script>\n\n<template>\n <HoverCard>\n <HoverCardTrigger>Hover</HoverCardTrigger>\n <HoverCardContent>\n The Vue Framework – created and maintained by @vuejs.\n </HoverCardContent>\n </HoverCard>\n</template>\n",
"examples": [
{
"source": "HoverCardDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { CalendarDays } from 'lucide-vue-next'\n\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n} from '@/components/ui/avatar'\nimport { Button } from '@/components/ui/button'\nimport {\n HoverCard,\n HoverCardContent,\n HoverCardTrigger,\n} from '@/components/ui/hover-card'\n</script>\n\n<template>\n <HoverCard>\n <HoverCardTrigger as-child>\n <Button variant=\"link\">\n @vuejs\n </Button>\n </HoverCardTrigger>\n <HoverCardContent class=\"w-80\">\n <div class=\"flex justify-between space-x-4\">\n <Avatar>\n <AvatarImage src=\"https://github.com/vuejs.png\" />\n <AvatarFallback>VC</AvatarFallback>\n </Avatar>\n <div class=\"space-y-1\">\n <h4 class=\"text-sm font-semibold\">\n @vuejs\n </h4>\n <p class=\"text-sm\">\n Progressive JavaScript framework for building modern web interfaces.\n </p>\n <div class=\"flex items-center pt-2\">\n <CalendarDays class=\"mr-2 h-4 w-4 opacity-70\" />\n <span class=\"text-xs text-muted-foreground\">\n Joined January 2014\n </span>\n </div>\n </div>\n </div>\n </HoverCardContent>\n </HoverCard>\n</template>"
}
]
},
{
"name": "input",
"description": "Displays a form input field or a component that looks like an input field.",
"usage": "<script setup lang=\"ts\">\nimport { Input } from '@/components/ui/input'\n</script>\n\n<template>\n <Input />\n</template>\n",
"examples": [
{
"source": "InputDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Input } from '@/components/ui/input'\n</script>\n\n<template>\n <Input type=\"email\" placeholder=\"Email\" />\n</template>"
},
{
"source": "InputDisabled.vue",
"code": "<script setup lang=\"ts\">\nimport { Input } from '@/components/ui/input'\n</script>\n\n<template>\n <Input disabled type=\"email\" placeholder=\"Email\" />\n</template>"
},
{
"source": "InputFile.vue",
"code": "<script setup lang=\"ts\">\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <div class=\"grid w-full max-w-sm items-center gap-1.5\">\n <Label for=\"picture\">Picture</Label>\n <Input id=\"picture\" type=\"file\" />\n </div>\n</template>"
},
{
"source": "InputForm.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport { Input } from '@/components/ui/input'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n username: z.string().min(2).max(50),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"w-2/3 space-y-6\" @submit=\"onSubmit\">\n <FormField v-slot=\"{ componentField }\" name=\"username\">\n <FormItem>\n <FormLabel>Username</FormLabel>\n <FormControl>\n <Input type=\"text\" placeholder=\"shadcn\" v-bind=\"componentField\" />\n </FormControl>\n <FormDescription>\n This is your public display name.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>"
},
{
"source": "InputFormAutoAnimate.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\nimport { vAutoAnimate } from '@formkit/auto-animate/vue'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport { Input } from '@/components/ui/input'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n username: z.string().min(2).max(50),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"w-2/3 space-y-6\" @submit=\"onSubmit\">\n <FormField v-slot=\"{ componentField }\" name=\"username\">\n <FormItem v-auto-animate>\n <FormLabel>Username</FormLabel>\n <FormControl>\n <Input type=\"text\" placeholder=\"shadcn\" v-bind=\"componentField\" />\n </FormControl>\n <FormDescription>\n This is your public display name.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </Form>\n</template>"
},
{
"source": "InputWithButton.vue",
"code": "<script setup lang=\"ts\">\nimport { Input } from '@/components/ui/input'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <div class=\"flex w-full max-w-sm items-center gap-1.5\">\n <Input id=\"email\" type=\"email\" placeholder=\"Email\" />\n <Button type=\"submit\">\n Subscribe\n </Button>\n </div>\n</template>"
},
{
"source": "InputWithLabel.vue",
"code": "<script setup lang=\"ts\">\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <div class=\"grid w-full max-w-sm items-center gap-1.5\">\n <Label for=\"email\">Email</Label>\n <Input id=\"email\" type=\"email\" placeholder=\"Email\" />\n </div>\n</template>"
}
]
},
{
"name": "label",
"description": "Renders an accessible label associated with controls.",
"usage": "<script setup lang=\"ts\">\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <Label for=\"email\">Your email address</Label>\n</template>\n",
"examples": [
{
"source": "LabelDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Checkbox } from '@/components/ui/checkbox'\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <div>\n <div class=\"flex items-center space-x-2\">\n <Checkbox id=\"terms\" />\n <Label for=\"terms\">Accept terms and conditions</Label>\n </div>\n </div>\n</template>"
}
]
},
{
"name": "menubar",
"description": "A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.",
"usage": "<script setup lang=\"ts\">\nimport {\n Menubar,\n MenubarContent,\n MenubarItem,\n MenubarMenu,\n MenubarSeparator,\n MenubarShortcut,\n MenubarTrigger,\n} from '@/components/ui/menubar'\n</script>\n\n<template>\n <Menubar>\n <MenubarMenu>\n <MenubarTrigger>File</MenubarTrigger>\n <MenubarContent>\n <MenubarItem>\n New Tab <MenubarShortcut>⌘T</MenubarShortcut>\n </MenubarItem>\n <MenubarItem>New Window</MenubarItem>\n <MenubarSeparator />\n <MenubarItem>Share</MenubarItem>\n <MenubarSeparator />\n <MenubarItem>Print</MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n </Menubar>\n</template>\n",
"examples": [
{
"source": "MenubarDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n Menubar,\n MenubarCheckboxItem,\n MenubarContent,\n MenubarItem,\n MenubarMenu,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSeparator,\n MenubarShortcut,\n MenubarSub,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarTrigger,\n} from '@/components/ui/menubar'\n</script>\n\n<template>\n <Menubar>\n <MenubarMenu>\n <MenubarTrigger>File</MenubarTrigger>\n <MenubarContent>\n <MenubarItem>\n New Tab <MenubarShortcut>⌘T</MenubarShortcut>\n </MenubarItem>\n <MenubarItem>\n New Window <MenubarShortcut>⌘N</MenubarShortcut>\n </MenubarItem>\n <MenubarItem disabled>\n New Incognito Window\n </MenubarItem>\n <MenubarSeparator />\n <MenubarSub>\n <MenubarSubTrigger>Share</MenubarSubTrigger>\n <MenubarSubContent>\n <MenubarItem>Email link</MenubarItem>\n <MenubarItem>Messages</MenubarItem>\n <MenubarItem>Notes</MenubarItem>\n </MenubarSubContent>\n </MenubarSub>\n <MenubarSeparator />\n <MenubarItem>\n Print... <MenubarShortcut>⌘P</MenubarShortcut>\n </MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n <MenubarMenu>\n <MenubarTrigger>Edit</MenubarTrigger>\n <MenubarContent>\n <MenubarItem>\n Undo <MenubarShortcut>⌘Z</MenubarShortcut>\n </MenubarItem>\n <MenubarItem>\n Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>\n </MenubarItem>\n <MenubarSeparator />\n <MenubarSub>\n <MenubarSubTrigger>Find</MenubarSubTrigger>\n <MenubarSubContent>\n <MenubarItem>Search the web</MenubarItem>\n <MenubarSeparator />\n <MenubarItem>Find...</MenubarItem>\n <MenubarItem>Find Next</MenubarItem>\n <MenubarItem>Find Previous</MenubarItem>\n </MenubarSubContent>\n </MenubarSub>\n <MenubarSeparator />\n <MenubarItem>Cut</MenubarItem>\n <MenubarItem>Copy</MenubarItem>\n <MenubarItem>Paste</MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n <MenubarMenu>\n <MenubarTrigger>View</MenubarTrigger>\n <MenubarContent>\n <MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>\n <MenubarCheckboxItem checked>\n Always Show Full URLs\n </MenubarCheckboxItem>\n <MenubarSeparator />\n <MenubarItem inset>\n Reload <MenubarShortcut>⌘R</MenubarShortcut>\n </MenubarItem>\n <MenubarItem disabled inset>\n Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut>\n </MenubarItem>\n <MenubarSeparator />\n <MenubarItem inset>\n Toggle Fullscreen\n </MenubarItem>\n <MenubarSeparator />\n <MenubarItem inset>\n Hide Sidebar\n </MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n <MenubarMenu>\n <MenubarTrigger>Profiles</MenubarTrigger>\n <MenubarContent>\n <MenubarRadioGroup value=\"benoit\">\n <MenubarRadioItem value=\"andy\">\n Andy\n </MenubarRadioItem>\n <MenubarRadioItem value=\"benoit\">\n Benoit\n </MenubarRadioItem>\n <MenubarRadioItem value=\"Luis\">\n Luis\n </MenubarRadioItem>\n </MenubarRadioGroup>\n <MenubarSeparator />\n <MenubarItem inset>\n Edit...\n </MenubarItem>\n <MenubarSeparator />\n <MenubarItem inset>\n Add Profile...\n </MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n </Menubar>\n</template>"
}
]
},
{
"name": "navigation-menu",
"description": "A collection of links for navigating websites.",
"usage": "<script setup lang=\"ts\">\nimport {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuIndicator,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n NavigationMenuViewport,\n} from '@/components/ui/navigation-menu'\n</script>\n\n<template>\n <NavigationMenu>\n <NavigationMenuList>\n <NavigationMenuItem>\n <NavigationMenuTrigger>Item One</NavigationMenuTrigger>\n <NavigationMenuContent>\n <NavigationMenuLink>Link</NavigationMenuLink>\n </NavigationMenuContent>\n </NavigationMenuItem>\n </NavigationMenuList>\n </NavigationMenu>\n</template>\n",
"examples": [
{
"source": "NavigationMenuDemo.vue",
"code": "<script setup lang=\"ts\">\nimport ListItem from './NavigationMenuDemoItem.vue'\nimport {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n navigationMenuTriggerStyle,\n} from '@/components/ui/navigation-menu'\n\nconst components: { title: string; href: string; description: string }[] = [\n {\n title: 'Alert Dialog',\n href: '/docs/primitives/alert-dialog',\n description:\n 'A modal dialog that interrupts the user with important content and expects a response.',\n },\n {\n title: 'Hover Card',\n href: '/docs/primitives/hover-card',\n description:\n 'For sighted users to preview content available behind a link.',\n },\n {\n title: 'Progress',\n href: '/docs/primitives/progress',\n description:\n 'Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.',\n },\n {\n title: 'Scroll-area',\n href: '/docs/primitives/scroll-area',\n description: 'Visually or semantically separates content.',\n },\n {\n title: 'Tabs',\n href: '/docs/primitives/tabs',\n description:\n 'A set of layered sections of content—known as tab panels—that are displayed one at a time.',\n },\n {\n title: 'Tooltip',\n href: '/docs/primitives/tooltip',\n description:\n 'A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.',\n },\n]\n</script>\n\n<template>\n <NavigationMenu>\n <NavigationMenuList>\n <NavigationMenuItem>\n <NavigationMenuTrigger>Getting started</NavigationMenuTrigger>\n <NavigationMenuContent>\n <ul class=\"grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]\">\n <li class=\"row-span-3\">\n <NavigationMenuLink as-child>\n <a\n class=\"flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md\"\n href=\"/\"\n >\n <img src=\"https://www.radix-vue.com/logo.svg\" class=\"h-6 w-6\">\n <div class=\"mb-2 mt-4 text-lg font-medium\">\n shadcn/ui\n </div>\n <p class=\"text-sm leading-tight text-muted-foreground\">\n Beautifully designed components built with Radix UI and\n Tailwind CSS.\n </p>\n </a>\n </NavigationMenuLink>\n </li>\n <ListItem href=\"/docs\" title=\"Introduction\">\n Re-usable components built using Radix UI and Tailwind CSS.\n </ListItem>\n <ListItem href=\"/docs/installation\" title=\"Installation\">\n How to install dependencies and structure your app.\n </ListItem>\n <ListItem href=\"/docs/primitives/typography\" title=\"Typography\">\n Styles for headings, paragraphs, lists...etc\n </ListItem>\n </ul>\n </NavigationMenuContent>\n </NavigationMenuItem>\n <NavigationMenuItem>\n <NavigationMenuTrigger>Components</NavigationMenuTrigger>\n <NavigationMenuContent>\n <ul class=\"grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] \">\n <ListItem\n v-for=\"component in components\"\n :key=\"component.title\"\n :title=\"component.title\"\n :href=\"component.href\"\n >\n {{ component.description }}\n </ListItem>\n </ul>\n </NavigationMenuContent>\n </NavigationMenuItem>\n <NavigationMenuItem>\n <NavigationMenuLink href=\"/docs\" :class=\"navigationMenuTriggerStyle()\">\n Documentation\n </NavigationMenuLink>\n </NavigationMenuItem>\n </NavigationMenuList>\n </NavigationMenu>\n</template>"
},
{
"source": "NavigationMenuDemoItem.vue",
"code": "<script setup lang=\"ts\">\nimport { cn } from '@/lib/utils'\nimport {\n NavigationMenuLink,\n} from '@/components/ui/navigation-menu'\n\ndefineProps<{ title?: string; href?: string }>()\n</script>\n\n<template>\n <li>\n <NavigationMenuLink as-child>\n <a\n :href=\"href\"\n :class=\"cn(\n 'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground',\n $attrs.class ?? '',\n )\"\n >\n <div class=\"text-sm font-medium leading-none\">{{ title }}</div>\n <p class=\"line-clamp-2 text-sm leading-snug text-muted-foreground\">\n <slot />\n </p>\n </a>\n </NavigationMenuLink>\n </li>\n</template>"
}
]
},
{
"name": "pagination",
"description": "Displays data in paged format and provides navigation between pages.",
"usage": "<script setup lang=\"ts\">\nimport {\n Pagination,\n PaginationEllipsis,\n PaginationFirst,\n PaginationLast,\n PaginationList,\n PaginationListItem,\n PaginationNext,\n PaginationPrev,\n} from '@/components/ui/pagination'\n\nimport {\n Button,\n} from '@/components/ui/button'\n</script>\n\n<template>\n <Pagination v-slot=\"{ page }\" :total=\"100\" :sibling-count=\"1\" show-edges :default-page=\"2\">\n <PaginationList v-slot=\"{ items }\" class=\"flex items-center gap-1\">\n <PaginationFirst />\n <PaginationPrev />\n\n <template v-for=\"(item, index) in items\">\n <PaginationListItem v-if=\"item.type === 'page'\" :key=\"index\" :value=\"item.value\" as-child>\n <Button class=\"w-10 h-10 p-0\" :variant=\"item.value === page ? 'default' : 'outline'\">\n {{ item.value }}\n </Button>\n </PaginationListItem>\n <PaginationEllipsis v-else :key=\"item.type\" :index=\"index\" />\n </template>\n\n <PaginationNext />\n <PaginationLast />\n </PaginationList>\n </Pagination>\n</template>\n",
"examples": [
{
"source": "PaginationDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n Pagination,\n PaginationEllipsis,\n PaginationFirst,\n PaginationLast,\n PaginationList,\n PaginationListItem,\n PaginationNext,\n PaginationPrev,\n} from '@/components/ui/pagination'\n\nimport {\n Button,\n} from '@/components/ui/button'\n</script>\n\n<template>\n <Pagination v-slot=\"{ page }\" :total=\"100\" :sibling-count=\"1\" show-edges :default-page=\"2\">\n <PaginationList v-slot=\"{ items }\" class=\"flex items-center gap-1\">\n <PaginationFirst />\n <PaginationPrev />\n\n <template v-for=\"(item, index) in items\">\n <PaginationListItem v-if=\"item.type === 'page'\" :key=\"index\" :value=\"item.value\" as-child>\n <Button class=\"w-10 h-10 p-0\" :variant=\"item.value === page ? 'default' : 'outline'\">\n {{ item.value }}\n </Button>\n </PaginationListItem>\n <PaginationEllipsis v-else :key=\"item.type\" :index=\"index\" />\n </template>\n\n <PaginationNext />\n <PaginationLast />\n </PaginationList>\n </Pagination>\n</template>"
}
]
},
{
"name": "popover",
"description": "Displays rich content in a portal, triggered by a button.",
"usage": "<script setup lang=\"ts\">\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\n</script>\n\n<template>\n <Popover>\n <PopoverTrigger>\n Open popover\n </PopoverTrigger>\n <PopoverContent />\n </Popover>\n</template>\n",
"examples": [
{
"source": "PopoverDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '@/components/ui/popover'\nimport { Button } from '@/components/ui/button'\nimport { Label } from '@/components/ui/label'\nimport { Input } from '@/components/ui/input'\n</script>\n\n<template>\n <Popover>\n <PopoverTrigger as-child>\n <Button variant=\"outline\">\n Open popover\n </Button>\n </PopoverTrigger>\n <PopoverContent class=\"w-80\">\n <div class=\"grid gap-4\">\n <div class=\"space-y-2\">\n <h4 class=\"font-medium leading-none\">\n Dimensions\n </h4>\n <p class=\"text-sm text-muted-foreground\">\n Set the dimensions for the layer.\n </p>\n </div>\n <div class=\"grid gap-2\">\n <div class=\"grid grid-cols-3 items-center gap-4\">\n <Label for=\"width\">Width</Label>\n <Input\n id=\"width\"\n type=\"text\"\n default-value=\"100%\"\n class=\"col-span-2 h-8\"\n />\n </div>\n <div class=\"grid grid-cols-3 items-center gap-4\">\n <Label for=\"maxWidth\">Max. width</Label>\n <Input\n id=\"maxWidth\"\n type=\"text\"\n default-value=\"300px\"\n class=\"col-span-2 h-8\"\n />\n </div>\n <div class=\"grid grid-cols-3 items-center gap-4\">\n <Label for=\"height\">Height</Label>\n <Input\n id=\"height\"\n type=\"text\"\n default-value=\"25px\"\n class=\"col-span-2 h-8\"\n />\n </div>\n <div class=\"grid grid-cols-3 items-center gap-4\">\n <Label for=\"maxHeight\">Max. height</Label>\n <Input\n id=\"maxHeight\"\n type=\"text\"\n default-value=\"none\"\n class=\"col-span-2 h-8\"\n />\n </div>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n</template>"
}
]
},
{
"name": "progress",
"description": "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.",
"usage": "<script setup lang=\"ts\">\nimport { Progress } from '@/components/ui/progress'\n</script>\n\n<template>\n <Progress :model-value=\"33\" />\n</template>\n",
"examples": [
{
"source": "ProgressDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ref, watchEffect } from 'vue'\nimport { Progress } from '@/components/ui/progress'\n\nconst progress = ref(13)\n\nwatchEffect((cleanupFn) => {\n const timer = setTimeout(() => progress.value = 66, 500)\n cleanupFn(() => clearTimeout(timer))\n})\n</script>\n\n<template>\n <Progress v-model=\"progress\" class=\"w-[60%]\" />\n</template>"
}
]
},
{
"name": "radio-group",
"description": "A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.",
"usage": "<script setup lang=\"ts\">\nimport { Label } from '@/components/ui/label'\nimport { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'\n</script>\n\n<template>\n <RadioGroup default-value=\"option-one\">\n <div class=\"flex items-center space-x-2\">\n <RadioGroupItem id=\"option-one\" value=\"option-one\" />\n <Label for=\"option-one\">Option One</Label>\n </div>\n <div class=\"flex items-center space-x-2\">\n <RadioGroupItem id=\"option-two\" value=\"option-two\" />\n <Label for=\"option-two\">Option Two</Label>\n </div>\n </RadioGroup>\n</template>\n",
"examples": [
{
"source": "RadioGroupDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Label } from '@/components/ui/label'\nimport { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'\n</script>\n\n<template>\n <RadioGroup default-value=\"comfortable\">\n <div class=\"flex items-center space-x-2\">\n <RadioGroupItem id=\"r1\" value=\"default\" />\n <Label for=\"r1\">Default</Label>\n </div>\n <div class=\"flex items-center space-x-2\">\n <RadioGroupItem id=\"r2\" value=\"comfortable\" />\n <Label for=\"r2\">Comfortable</Label>\n </div>\n <div class=\"flex items-center space-x-2\">\n <RadioGroupItem id=\"r3\" value=\"compact\" />\n <Label for=\"r3\">Compact</Label>\n </div>\n </RadioGroup>\n</template>"
},
{
"source": "RadioGroupForm.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n type: z.enum(['all', 'mentions', 'none'], {\n required_error: 'You need to select a notification type.',\n }),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"w-2/3 space-y-6\" @submit=\"onSubmit\">\n <FormField v-slot=\"{ componentField }\" type=\"radio\" name=\"type\">\n <FormItem class=\"space-y-3\">\n <FormLabel>Notify me about...</FormLabel>\n\n <FormControl>\n <RadioGroup\n class=\"flex flex-col space-y-1\"\n v-bind=\"componentField\"\n >\n <FormItem class=\"flex items-center space-y-0 gap-x-3\">\n <FormControl>\n <RadioGroupItem value=\"all\" />\n </FormControl>\n <FormLabel class=\"font-normal\">\n All new messages\n </FormLabel>\n </FormItem>\n <FormItem class=\"flex items-center space-y-0 gap-x-3\">\n <FormControl>\n <RadioGroupItem value=\"mentions\" />\n </FormControl>\n <FormLabel class=\"font-normal\">\n Direct messages and mentions\n </FormLabel>\n </FormItem>\n <FormItem class=\"flex items-center space-y-0 gap-x-3\">\n <FormControl>\n <RadioGroupItem value=\"none\" />\n </FormControl>\n <FormLabel class=\"font-normal\">\n Nothing\n </FormLabel>\n </FormItem>\n </RadioGroup>\n </FormControl>\n <FormMessage />\n </FormItem>\n </FormField>\n\n <Button type=\"submit\">\n Submit\n </Button>\n </form>\n</template>"
}
]
},
{
"name": "scroll-area",
"description": "Augments native scroll functionality for custom, cross-browser styling.",
"usage": "<script setup lang=\"ts\">\nimport { ScrollArea } from '@/components/ui/scroll-area'\n</script>\n\n<template>\n <ScrollArea class=\"h-[200px] w-[350px] rounded-md border p-4\">\n Jokester began sneaking into the castle in the middle of the night and leaving\n jokes all over the place: under the king's pillow, in his soup, even in the\n royal toilet. The king was furious, but he couldn't seem to stop Jokester. And\n then, one day, the people of the kingdom discovered that the jokes left by\n Jokester were so funny that they couldn't help but laugh. And once they\n started laughing, they couldn't stop.\n </ScrollArea>\n</template>\n",
"examples": [
{
"source": "ScrollAreaDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ScrollArea } from '@/components/ui/scroll-area'\nimport { Separator } from '@/components/ui/separator'\n\nconst tags = Array.from({ length: 50 }).map(\n (_, i, a) => `v1.2.0-beta.${a.length - i}`,\n)\n</script>\n\n<template>\n <ScrollArea class=\"h-72 w-48 rounded-md border\">\n <div class=\"p-4\">\n <h4 class=\"mb-4 text-sm font-medium leading-none\">\n Tags\n </h4>\n\n <div v-for=\"tag in tags\" :key=\"tag\">\n <div class=\"text-sm\">\n {{ tag }}\n </div>\n <Separator class=\"my-2\" />\n </div>\n </div>\n </ScrollArea>\n</template>"
},
{
"source": "ScrollAreaHorizontalDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ScrollArea, ScrollBar } from '@/components/ui/scroll-area'\n\ninterface Artwork {\n id: string\n artist: string\n art: string\n}\n\nconst works: Artwork[] = [\n {\n id: '1',\n artist: 'Ornella Binni',\n art: 'https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80',\n },\n {\n id: '2',\n artist: 'Tom Byrom',\n art: 'https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80',\n },\n {\n id: '3',\n artist: 'Vladimir Malyavko',\n art: 'https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80',\n },\n]\n</script>\n\n<template>\n <ScrollArea class=\"border rounded-md w-96 whitespace-nowrap\">\n <div class=\"flex p-4 space-x-4 w-max\">\n <div v-for=\"artwork in works\" :key=\"artwork.id\">\n <figure class=\"shrink-0\">\n <div class=\"overflow-hidden rounded-md\">\n <img\n :src=\"artwork.art\"\n :alt=\"`Photo by ${artwork.artist}`\"\n class=\"aspect-[3/4] w-36 h-56 object-cover\"\n >\n </div>\n <figcaption class=\"pt-2 text-xs text-muted-foreground\">\n Photo by\n <span class=\"font-semibold text-foreground\">\n {{ artwork.artist }}\n </span>\n </figcaption>\n </figure>\n </div>\n </div>\n <ScrollBar orientation=\"horizontal\" />\n </ScrollArea>\n</template>"
}
]
},
{
"name": "select",
"description": "Displays a list of options for the user to pick from—triggered by a button.",
"usage": "<script setup lang=\"ts\">\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\n</script>\n\n<template>\n <Select>\n <SelectTrigger>\n <SelectValue placeholder=\"Select a fruit\" />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n <SelectLabel>Fruits</SelectLabel>\n <SelectItem value=\"apple\">\n Apple\n </SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n</template>\n",
"examples": [
{
"source": "SelectDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\n</script>\n\n<template>\n <Select>\n <SelectTrigger class=\"w-[180px]\">\n <SelectValue placeholder=\"Select a fruit\" />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n <SelectLabel>Fruits</SelectLabel>\n <SelectItem value=\"apple\">\n Apple\n </SelectItem>\n <SelectItem value=\"banana\">\n Banana\n </SelectItem>\n <SelectItem value=\"blueberry\">\n Blueberry\n </SelectItem>\n <SelectItem value=\"grapes\">\n Grapes\n </SelectItem>\n <SelectItem value=\"pineapple\">\n Pineapple\n </SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n</template>"
},
{
"source": "SelectForm.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n email: z\n .string({\n required_error: 'Please select an email to display.',\n })\n .email(),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"w-2/3 space-y-6\" @submit=\"onSubmit\">\n <FormField v-slot=\"{ componentField }\" name=\"email\">\n <FormItem>\n <FormLabel>Email</FormLabel>\n\n <Select v-bind=\"componentField\">\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder=\"Select a verified email to display\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n <SelectGroup>\n <SelectItem value=\"m@example.com\">\n m@example.com\n </SelectItem>\n <SelectItem value=\"m@google.com\">\n m@google.com\n </SelectItem>\n <SelectItem value=\"m@support.com\">\n m@support.com\n </SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n <FormDescription>\n You can manage email addresses in your\n <a href=\"/examples/forms\">email settings</a>.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n\n <Button type=\"submit\">\n Submit\n </Button>\n </form>\n</template>"
}
]
},
{
"name": "separator",
"description": "Visually or semantically separates content.",
"usage": "<script setup lang=\"ts\">\nimport { Separator } from '@/components/ui/separator'\n</script>\n\n<template>\n <Separator />\n</template>\n",
"examples": [
{
"source": "SeparatorDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Separator } from '@/components/ui/separator'\n</script>\n\n<template>\n <div>\n <div class=\"space-y-1\">\n <h4 class=\"text-sm font-medium leading-none\">\n Radix Primitives\n </h4>\n <p class=\"text-sm text-muted-foreground\">\n An open-source UI component library.\n </p>\n </div>\n <Separator class=\"my-4\" />\n <div class=\"flex h-5 items-center space-x-4 text-sm\">\n <div>Blog</div>\n <Separator orientation=\"vertical\" />\n <div>Docs</div>\n <Separator orientation=\"vertical\" />\n <div>Source</div>\n </div>\n </div>\n</template>"
}
]
},
{
"name": "sheet",
"description": "Extends the Dialog component to display content that complements the main content of the screen.",
"usage": "<script setup lang=\"ts\">\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from '@/components/ui/sheet'\n</script>\n\n<template>\n <Sheet>\n <SheetTrigger>Open</SheetTrigger>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>Are you sure absolutely sure?</SheetTitle>\n <SheetDescription>\n This action cannot be undone. This will permanently delete your account\n and remove your data from our servers.\n </SheetDescription>\n </SheetHeader>\n </SheetContent>\n </Sheet>\n</template>\n",
"examples": [
{
"source": "SheetDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from '@/components/ui/sheet'\n</script>\n\n<template>\n <Sheet>\n <SheetTrigger as-child>\n <Button variant=\"outline\">\n Open\n </Button>\n </SheetTrigger>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>Edit profile</SheetTitle>\n <SheetDescription>\n Make changes to your profile here. Click save when you're done.\n </SheetDescription>\n </SheetHeader>\n <div class=\"grid gap-4 py-4\">\n <div class=\"grid grid-cols-4 items-center gap-4\">\n <Label for=\"name\" class=\"text-right\">\n Name\n </Label>\n <Input id=\"name\" value=\"Pedro Duarte\" class=\"col-span-3\" />\n </div>\n <div class=\"grid grid-cols-4 items-center gap-4\">\n <Label for=\"username\" class=\"text-right\">\n Username\n </Label>\n <Input id=\"username\" value=\"@peduarte\" class=\"col-span-3\" />\n </div>\n </div>\n <SheetFooter>\n <SheetClose as-child>\n <Button type=\"submit\">\n Save changes\n </Button>\n </SheetClose>\n </SheetFooter>\n </SheetContent>\n </Sheet>\n</template>"
},
{
"source": "SheetSideDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from '@/components/ui/sheet'\n\nconst SHEET_SIDES = ['top', 'right', 'bottom', 'left'] as const\n\nconst username = ref('')\n</script>\n\n<template>\n <div class=\"grid grid-cols-2 gap-2\">\n <Sheet v-for=\"side in SHEET_SIDES\" :key=\"side\">\n <SheetTrigger as-child>\n <Button variant=\"outline\">\n {{ side }}\n </Button>\n </SheetTrigger>\n <SheetContent :side=\"side\">\n <SheetHeader>\n <SheetTitle>Edit profile</SheetTitle>\n <SheetDescription>\n Make changes to your profile here. Click save when you're done.\n </SheetDescription>\n </SheetHeader>\n <div class=\"grid gap-4 py-4\">\n <div class=\"grid items-center grid-cols-4 gap-4\">\n <Label for=\"name\" class=\"text-right\">Name</Label>\n <Input id=\"name\" v-model=\"username\" class=\"col-span-3\" />\n </div>\n <div class=\"grid items-center grid-cols-4 gap-4\">\n <Label for=\"username\" class=\"text-right\">Username</Label>\n <Input id=\"username\" v-model=\"username\" class=\"col-span-3\" />\n </div>\n </div>\n <SheetFooter>\n <SheetClose as-child>\n <Button type=\"submit\">\n Save changes\n </Button>\n </SheetClose>\n </SheetFooter>\n </SheetContent>\n </Sheet>\n </div>\n</template>"
}
]
},
{
"name": "skeleton",
"description": "Use to show a placeholder while content is loading.",
"usage": "<script setup lang=\"ts\">\nimport { Skeleton } from '@/components/ui/skeleton'\n</script>\n\n<template>\n <Skeleton class=\"w-[100px] h-[20px] rounded-full\" />\n</template>\n",
"examples": [
{
"source": "SkeletonDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Skeleton } from '@/components/ui/skeleton'\n</script>\n\n<template>\n <div class=\"flex items-center space-x-4\">\n <Skeleton class=\"h-12 w-12 rounded-full\" />\n <div class=\"space-y-2\">\n <Skeleton class=\"h-4 w-[250px]\" />\n <Skeleton class=\"h-4 w-[200px]\" />\n </div>\n </div>\n</template>"
}
]
},
{
"name": "slider",
"description": "An input where the user selects a value from within a given range.",
"usage": "<script setup lang=\"ts\">\nimport { Slider } from '@/components/ui/slider'\n</script>\n\n<template>\n <Slider\n :default-value=\"[33]\" :max=\"100\" :step=\"1\"\n />\n</template>\n",
"examples": [
{
"source": "SliderDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Slider } from '@/components/ui/slider'\n\nconst modelValue = ref([50])\n</script>\n\n<template>\n <Slider\n v-model=\"modelValue\"\n :max=\"100\"\n :step=\"1\"\n :class=\"cn('w-[60%]', $attrs.class ?? '')\"\n />\n</template>"
}
]
},
{
"name": "switch",
"description": "A control that allows the user to toggle between checked and not checked.",
"usage": "<script setup lang=\"ts\">\nimport { Switch } from '@/components/ui/switch'\n</script>\n\n<template>\n <Switch />\n</template>\n",
"examples": [
{
"source": "SwitchDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Label } from '@/components/ui/label'\nimport { Switch } from '@/components/ui/switch'\n</script>\n\n<template>\n <div class=\"flex items-center space-x-2\">\n <Switch id=\"airplane-mode\" />\n <Label for=\"airplane-mode\">Airplane Mode</Label>\n </div>\n</template>"
},
{
"source": "SwitchForm.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n} from '@/components/ui/form'\nimport { Switch } from '@/components/ui/switch'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n marketing_emails: z.boolean().default(false).optional(),\n security_emails: z.boolean(),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n initialValues: {\n security_emails: true,\n },\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"w-full space-y-6\" @submit=\"onSubmit\">\n <div>\n <h3 class=\"mb-4 text-lg font-medium\">\n Email Notifications\n </h3>\n\n <div class=\"space-y-4\">\n <FormField v-slot=\"{ value, handleChange }\" name=\"marketing_emails\">\n <FormItem class=\"flex flex-row items-center justify-between rounded-lg border p-4\">\n <div class=\"space-y-0.5\">\n <FormLabel class=\"text-base\">\n Marketing emails\n </FormLabel>\n <FormDescription>\n Receive emails about new products, features, and more.\n </FormDescription>\n </div>\n <FormControl>\n <Switch\n :checked=\"value\"\n @update:checked=\"handleChange\"\n />\n </FormControl>\n </FormItem>\n </FormField>\n <FormField v-slot=\"{ value, handleChange }\" name=\"security_emails\">\n <FormItem class=\"flex flex-row items-center justify-between rounded-lg border p-4\">\n <div class=\"space-y-0.5\">\n <FormLabel class=\"text-base\">\n Security emails\n </FormLabel>\n <FormDescription>\n Receive emails about your account security.\n </FormDescription>\n </div>\n <FormControl>\n <Switch\n :checked=\"value\"\n disabled\n aria-readonly\n @update:checked=\"handleChange\"\n />\n </FormControl>\n </FormItem>\n </FormField>\n </div>\n </div>\n <Button type=\"submit\">\n Submit\n </Button>\n </form>\n</template>"
}
]
},
{
"name": "table",
"description": "A responsive table component.",
"usage": "<script setup lang=\"ts\">\nimport {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\n</script>\n\n<template>\n <Table>\n <TableCaption>A list of your recent invoices.</TableCaption>\n <TableHeader>\n <TableRow>\n <TableHead class=\"w-[100px]\">\n Invoice\n </TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Method</TableHead>\n <TableHead class=\"text-right\">\n Amount\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n <TableRow>\n <TableCell class=\"font-medium\">\n INV001\n </TableCell>\n <TableCell>Paid</TableCell>\n <TableCell>Credit Card</TableCell>\n <TableCell class=\"text-right\">\n $250.00\n </TableCell>\n </TableRow>\n </TableBody>\n </Table>\n</template>\n",
"examples": [
{
"source": "TableDemo.vue",
"code": "<script setup lang=\"ts\">\nimport {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@/components/ui/table'\n\nconst invoices = [\n {\n invoice: 'INV001',\n paymentStatus: 'Paid',\n totalAmount: '$250.00',\n paymentMethod: 'Credit Card',\n },\n {\n invoice: 'INV002',\n paymentStatus: 'Pending',\n totalAmount: '$150.00',\n paymentMethod: 'PayPal',\n },\n {\n invoice: 'INV003',\n paymentStatus: 'Unpaid',\n totalAmount: '$350.00',\n paymentMethod: 'Bank Transfer',\n },\n {\n invoice: 'INV004',\n paymentStatus: 'Paid',\n totalAmount: '$450.00',\n paymentMethod: 'Credit Card',\n },\n {\n invoice: 'INV005',\n paymentStatus: 'Paid',\n totalAmount: '$550.00',\n paymentMethod: 'PayPal',\n },\n {\n invoice: 'INV006',\n paymentStatus: 'Pending',\n totalAmount: '$200.00',\n paymentMethod: 'Bank Transfer',\n },\n {\n invoice: 'INV007',\n paymentStatus: 'Unpaid',\n totalAmount: '$300.00',\n paymentMethod: 'Credit Card',\n },\n]\n</script>\n\n<template>\n <Table>\n <TableCaption>A list of your recent invoices.</TableCaption>\n <TableHeader>\n <TableRow>\n <TableHead class=\"w-[100px]\">\n Invoice\n </TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Method</TableHead>\n <TableHead class=\"text-right\">\n Amount\n </TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n <TableRow v-for=\"invoice in invoices\" :key=\"invoice.invoice\">\n <TableCell class=\"font-medium\">\n {{ invoice.invoice }}\n </TableCell>\n <TableCell>{{ invoice.paymentStatus }}</TableCell>\n <TableCell>{{ invoice.paymentMethod }}</TableCell>\n <TableCell class=\"text-right\">\n {{ invoice.totalAmount }}\n </TableCell>\n </TableRow>\n </TableBody>\n </Table>\n</template>"
}
]
},
{
"name": "tabs",
"description": "A set of layered sections of content—known as tab panels—that are displayed one at a time.",
"usage": "<script setup lang=\"ts\">\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'\n</script>\n\n<template>\n <Tabs default-value=\"account\" class=\"w-[400px]\">\n <TabsList>\n <TabsTrigger value=\"account\">\n Account\n </TabsTrigger>\n <TabsTrigger value=\"password\">\n Password\n </TabsTrigger>\n </TabsList>\n <TabsContent value=\"account\">\n Make changes to your account here.\n </TabsContent>\n <TabsContent value=\"password\">\n Change your password here.\n </TabsContent>\n </Tabs>\n</template>\n",
"examples": [
{
"source": "TabsDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@/components/ui/tabs'\n</script>\n\n<template>\n <Tabs default-value=\"account\" class=\"w-[400px]\">\n <TabsList class=\"grid w-full grid-cols-2\">\n <TabsTrigger value=\"account\">\n Account\n </TabsTrigger>\n <TabsTrigger value=\"password\">\n Password\n </TabsTrigger>\n </TabsList>\n <TabsContent value=\"account\">\n <Card>\n <CardHeader>\n <CardTitle>Account</CardTitle>\n <CardDescription>\n Make changes to your account here. Click save when you're done.\n </CardDescription>\n </CardHeader>\n <CardContent class=\"space-y-2\">\n <div class=\"space-y-1\">\n <Label for=\"name\">Name</Label>\n <Input id=\"name\" default-value=\"Pedro Duarte\" />\n </div>\n <div class=\"space-y-1\">\n <Label for=\"username\">Username</Label>\n <Input id=\"username\" default-value=\"@peduarte\" />\n </div>\n </CardContent>\n <CardFooter>\n <Button>Save changes</Button>\n </CardFooter>\n </Card>\n </TabsContent>\n <TabsContent value=\"password\">\n <Card>\n <CardHeader>\n <CardTitle>Password</CardTitle>\n <CardDescription>\n Change your password here. After saving, you'll be logged out.\n </CardDescription>\n </CardHeader>\n <CardContent class=\"space-y-2\">\n <div class=\"space-y-1\">\n <Label for=\"current\">Current password</Label>\n <Input id=\"current\" type=\"password\" />\n </div>\n <div class=\"space-y-1\">\n <Label for=\"new\">New password</Label>\n <Input id=\"new\" type=\"password\" />\n </div>\n </CardContent>\n <CardFooter>\n <Button>Save password</Button>\n </CardFooter>\n </Card>\n </TabsContent>\n </Tabs>\n</template>"
}
]
},
{
"name": "textarea",
"description": "Displays a form textarea or a component that looks like a textarea.",
"usage": "<script setup lang=\"ts\">\nimport { Textarea } from '@/components/ui/textarea'\n</script>\n\n<template>\n <Textarea />\n</template>\n",
"examples": [
{
"source": "TextareaDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Textarea } from '@/components/ui/textarea'\n</script>\n\n<template>\n <Textarea placeholder=\"Type your message here.\" />\n</template>"
},
{
"source": "TextareaDisabled.vue",
"code": "<script setup lang=\"ts\">\nimport { Textarea } from '@/components/ui/textarea'\n</script>\n\n<template>\n <Textarea placeholder=\"Type your message here.\" disabled />\n</template>"
},
{
"source": "TextareaForm.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { useForm } from 'vee-validate'\nimport { toTypedSchema } from '@vee-validate/zod'\nimport * as z from 'zod'\n\nimport { Button } from '@/components/ui/button'\nimport {\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from '@/components/ui/form'\nimport { Textarea } from '@/components/ui/textarea'\nimport { toast } from '@/components/ui/toast'\n\nconst formSchema = toTypedSchema(z.object({\n bio: z\n .string()\n .min(10, {\n message: 'Bio must be at least 10 characters.',\n })\n .max(160, {\n message: 'Bio must not be longer than 30 characters.',\n }),\n}))\n\nconst { handleSubmit } = useForm({\n validationSchema: formSchema,\n})\n\nconst onSubmit = handleSubmit((values) => {\n toast({\n title: 'You submitted the following values:',\n description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),\n })\n})\n</script>\n\n<template>\n <form class=\"w-full space-y-6\" @submit=\"onSubmit\">\n <FormField v-slot=\"{ componentField }\" name=\"bio\">\n <FormItem>\n <FormLabel>Bio</FormLabel>\n <FormControl>\n <Textarea\n placeholder=\"Tell us a little bit about yourself\"\n class=\"resize-none\"\n v-bind=\"componentField\"\n />\n </FormControl>\n <FormDescription>\n You can <span>@mention</span> other users and organizations.\n </FormDescription>\n <FormMessage />\n </FormItem>\n </FormField>\n <Button type=\"submit\">\n Submit\n </Button>\n </form>\n</template>"
},
{
"source": "TextareaWithButton.vue",
"code": "<script setup lang=\"ts\">\nimport { Textarea } from '@/components/ui/textarea'\nimport { Button } from '@/components/ui/button'\n</script>\n\n<template>\n <div class=\"grid w-full gap-2\">\n <Textarea placeholder=\"Type your message here.\" />\n <Button>Send message</Button>\n </div>\n</template>"
},
{
"source": "TextareaWithLabel.vue",
"code": "<script setup lang=\"ts\">\nimport { Textarea } from '@/components/ui/textarea'\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <div class=\"grid w-full gap-1.5\">\n <Label for=\"message\">Your message</Label>\n <Textarea id=\"message\" placeholder=\"Type your message here.\" />\n </div>\n</template>"
},
{
"source": "TextareaWithText.vue",
"code": "<script setup lang=\"ts\">\nimport { Textarea } from '@/components/ui/textarea'\nimport { Label } from '@/components/ui/label'\n</script>\n\n<template>\n <div class=\"grid w-full gap-1.5\">\n <Label for=\"message-2\">Your message</Label>\n <Textarea id=\"message-2\" placeholder=\"Type your message here.\" />\n <p class=\"text-sm text-muted-foreground\">\n Your message will be copied to the support team.\n </p>\n </div>\n</template>"
}
]
},
{
"name": "toast",
"description": "A succinct message that is displayed temporarily.",
"usage": "The `useToast` hook returns a `toast` function that you can use to display a toast.\n\ntsx\nimport { useToast } from '@/components/ui/toast'\n```\n\n<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport { useToast } from '@/components/ui/toast'\n\nconst { toast } = useToast()\n</script>\n\n<template>\n <Button\n @click=\"() => {\n toast({\n title: 'Scheduled: Catch up',\n description: 'Friday, February 10, 2023 at 5:57 PM',\n });\n }\"\n >\n Add to calander\n </Button>\n</template>\n```\n\n<Callout>\n\nTo display multiple toasts at the same time, you can update the `TOAST_LIMIT` in `use-toast.ts`.\n\n</Callout>",
"examples": [
{
"source": "ToastDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport { useToast } from '@/components/ui/toast'\n\nconst { toast } = useToast()\n</script>\n\n<template>\n <Button\n variant=\"outline\" @click=\"() => {\n toast({\n title: 'Scheduled: Catch up',\n description: 'Friday, February 10, 2023 at 5:57 PM',\n });\n }\"\n >\n Add to calander\n </Button>\n</template>"
},
{
"source": "ToastDestructive.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { Button } from '@/components/ui/button'\nimport { useToast } from '@/components/ui/toast'\nimport { ToastAction } from '@/components/ui/toast'\n\nconst { toast } = useToast()\n</script>\n\n<template>\n <Button\n variant=\"outline\" @click=\"() => {\n toast({\n title: 'Uh oh! Something went wrong.',\n description: 'There was a problem with your request.',\n variant: 'destructive',\n action: h(ToastAction, {\n altText: 'Try again',\n }, {\n default: () => 'Try again',\n }),\n });\n }\"\n >\n Show Toast\n </Button>\n</template>"
},
{
"source": "ToastSimple.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport { useToast } from '@/components/ui/toast'\n\nconst { toast } = useToast()\n</script>\n\n<template>\n <Button\n variant=\"outline\" @click=\"() => {\n toast({\n description: 'Your message has been sent.',\n });\n }\"\n >\n Show Toast\n </Button>\n</template>"
},
{
"source": "ToastWithAction.vue",
"code": "<script setup lang=\"ts\">\nimport { h } from 'vue'\nimport { Button } from '@/components/ui/button'\nimport { useToast } from '@/components/ui/toast'\nimport { ToastAction } from '@/components/ui/toast'\n\nconst { toast } = useToast()\n</script>\n\n<template>\n <Button\n variant=\"outline\" @click=\"() => {\n toast({\n title: 'Uh oh! Something went wrong.',\n description: 'There was a problem with your request.',\n action: h(ToastAction, {\n altText: 'Try again',\n }, {\n default: () => 'Try again',\n }),\n });\n }\"\n >\n Show Toast\n </Button>\n</template>"
},
{
"source": "ToastWithTitle.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport { useToast } from '@/components/ui/toast'\n\nconst { toast } = useToast()\n</script>\n\n<template>\n <Button\n variant=\"outline\" @click=\"() => {\n toast({\n title: 'Uh oh! Something went wrong.',\n description: 'There was a problem with your request.',\n });\n }\"\n >\n Show Toast\n </Button>\n</template>"
}
]
},
{
"name": "toggle",
"description": "A two-state button that can be either on or off.",
"usage": "<script setup lang=\"ts\">\nimport { Toggle } from '@/components/ui/toggle'\n</script>\n\n<template>\n <Toggle>Toggle</Toggle>\n</template>\n",
"examples": [
{
"source": "ToggleDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Bold } from 'lucide-vue-next'\n\nimport { Toggle } from '@/components/ui/toggle'\n</script>\n\n<template>\n <Toggle aria-label=\"Toggle italic\">\n <Bold class=\"h-4 w-4\" />\n </Toggle>\n</template>"
},
{
"source": "ToggleDisabledDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Underline } from 'lucide-vue-next'\n\nimport { Toggle } from '@/components/ui/toggle'\n</script>\n\n<template>\n <Toggle aria-label=\"Toggle italic\" disabled>\n <Underline class=\"w-4 h-4\" />\n </Toggle>\n</template>"
},
{
"source": "ToggleItalicDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Italic } from 'lucide-vue-next'\n\nimport { Toggle } from '@/components/ui/toggle'\n</script>\n\n<template>\n <Toggle variant=\"outline\" aria-label=\"Toggle italic\">\n <Italic class=\"w-4 h-4\" />\n </Toggle>\n</template>"
},
{
"source": "ToggleItalicWithTextDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Italic } from 'lucide-vue-next'\n\nimport { Toggle } from '@/components/ui/toggle'\n</script>\n\n<template>\n <Toggle aria-label=\"Toggle italic\">\n <Italic class=\"w-4 h-4 mr-2\" />\n Italic\n </Toggle>\n</template>"
},
{
"source": "ToggleLargeDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Italic } from 'lucide-vue-next'\n\nimport { Toggle } from '@/components/ui/toggle'\n</script>\n\n<template>\n <Toggle size=\"lg\" aria-label=\"Toggle italic\">\n <Italic class=\"w-4 h-4\" />\n </Toggle>\n</template>"
},
{
"source": "ToggleSmallDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Italic } from 'lucide-vue-next'\n\nimport { Toggle } from '@/components/ui/toggle'\n</script>\n\n<template>\n <Toggle size=\"sm\" aria-label=\"Toggle italic\">\n <Italic class=\"w-4 h-4\" />\n </Toggle>\n</template>"
}
]
},
{
"name": "tooltip",
"description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
"usage": "<script setup lang=\"ts\">\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger\n} from '@/components/ui/tooltip'\n</script>\n\n<template>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger>Hover</TooltipTrigger>\n <TooltipContent>\n <p>Add to library</p>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n</template>\n",
"examples": [
{
"source": "TooltipDemo.vue",
"code": "<script setup lang=\"ts\">\nimport { Button } from '@/components/ui/button'\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '@/components/ui/tooltip'\n</script>\n\n<template>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger as-child>\n <Button variant=\"outline\">\n Hover\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>Add to library</p>\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n</template>"
}
]
}
]