create-nala 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/index.js +227 -0
  4. package/package.json +48 -0
  5. package/template/.env.example +45 -0
  6. package/template/_gitignore +33 -0
  7. package/template/components.json +24 -0
  8. package/template/index.html +30 -0
  9. package/template/package.json +51 -0
  10. package/template/public/favicon.svg +15 -0
  11. package/template/public/icons.svg +24 -0
  12. package/template/public/img/avatar.webp +0 -0
  13. package/template/public/screenshot.png +0 -0
  14. package/template/src/App.vue +15 -0
  15. package/template/src/auto-imports.d.ts +691 -0
  16. package/template/src/components/AppLogo.vue +159 -0
  17. package/template/src/components/EmptyState.vue +60 -0
  18. package/template/src/components/PageHeader.vue +60 -0
  19. package/template/src/components/layout/AppNavbar.vue +159 -0
  20. package/template/src/components/layout/AppSidebar.vue +74 -0
  21. package/template/src/components/layout/CommandSearchDialog.vue +120 -0
  22. package/template/src/components/ui/accordion/Accordion.vue +15 -0
  23. package/template/src/components/ui/accordion/AccordionContent.vue +20 -0
  24. package/template/src/components/ui/accordion/AccordionItem.vue +20 -0
  25. package/template/src/components/ui/accordion/AccordionTrigger.vue +34 -0
  26. package/template/src/components/ui/accordion/index.ts +4 -0
  27. package/template/src/components/ui/alert/Alert.vue +21 -0
  28. package/template/src/components/ui/alert/AlertDescription.vue +17 -0
  29. package/template/src/components/ui/alert/AlertTitle.vue +17 -0
  30. package/template/src/components/ui/alert/index.ts +30 -0
  31. package/template/src/components/ui/alert-dialog/AlertDialog.vue +15 -0
  32. package/template/src/components/ui/alert-dialog/AlertDialogAction.vue +18 -0
  33. package/template/src/components/ui/alert-dialog/AlertDialogCancel.vue +25 -0
  34. package/template/src/components/ui/alert-dialog/AlertDialogContent.vue +44 -0
  35. package/template/src/components/ui/alert-dialog/AlertDialogDescription.vue +23 -0
  36. package/template/src/components/ui/alert-dialog/AlertDialogFooter.vue +22 -0
  37. package/template/src/components/ui/alert-dialog/AlertDialogHeader.vue +17 -0
  38. package/template/src/components/ui/alert-dialog/AlertDialogTitle.vue +21 -0
  39. package/template/src/components/ui/alert-dialog/AlertDialogTrigger.vue +12 -0
  40. package/template/src/components/ui/alert-dialog/index.ts +9 -0
  41. package/template/src/components/ui/avatar/Avatar.vue +50 -0
  42. package/template/src/components/ui/avatar/AvatarFallback.vue +21 -0
  43. package/template/src/components/ui/avatar/AvatarGroup.vue +69 -0
  44. package/template/src/components/ui/avatar/AvatarImage.vue +16 -0
  45. package/template/src/components/ui/avatar/index.ts +4 -0
  46. package/template/src/components/ui/badge/Badge.vue +40 -0
  47. package/template/src/components/ui/badge/index.ts +45 -0
  48. package/template/src/components/ui/breadcrumb/Breadcrumb.vue +17 -0
  49. package/template/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +23 -0
  50. package/template/src/components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
  51. package/template/src/components/ui/breadcrumb/BreadcrumbLink.vue +21 -0
  52. package/template/src/components/ui/breadcrumb/BreadcrumbList.vue +17 -0
  53. package/template/src/components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
  54. package/template/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +22 -0
  55. package/template/src/components/ui/breadcrumb/index.ts +7 -0
  56. package/template/src/components/ui/button/Button.spec.ts +46 -0
  57. package/template/src/components/ui/button/Button.vue +31 -0
  58. package/template/src/components/ui/button/index.ts +41 -0
  59. package/template/src/components/ui/calendar/Calendar.vue +106 -0
  60. package/template/src/components/ui/calendar/index.ts +1 -0
  61. package/template/src/components/ui/card/Card.vue +29 -0
  62. package/template/src/components/ui/card/CardAction.vue +17 -0
  63. package/template/src/components/ui/card/CardContent.vue +17 -0
  64. package/template/src/components/ui/card/CardDescription.vue +17 -0
  65. package/template/src/components/ui/card/CardFooter.vue +17 -0
  66. package/template/src/components/ui/card/CardHeader.vue +29 -0
  67. package/template/src/components/ui/card/CardTitle.vue +17 -0
  68. package/template/src/components/ui/card/index.ts +7 -0
  69. package/template/src/components/ui/chart/AreaChart.vue +143 -0
  70. package/template/src/components/ui/chart/BarChart.vue +142 -0
  71. package/template/src/components/ui/chart/DonutChart.vue +75 -0
  72. package/template/src/components/ui/chart/LineChart.vue +132 -0
  73. package/template/src/components/ui/chart/index.ts +4 -0
  74. package/template/src/components/ui/checkbox/Checkbox.vue +57 -0
  75. package/template/src/components/ui/checkbox/index.ts +1 -0
  76. package/template/src/components/ui/collapsible/Collapsible.vue +15 -0
  77. package/template/src/components/ui/collapsible/CollapsibleContent.vue +18 -0
  78. package/template/src/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
  79. package/template/src/components/ui/collapsible/index.ts +3 -0
  80. package/template/src/components/ui/command/Command.vue +88 -0
  81. package/template/src/components/ui/command/CommandDialog.vue +31 -0
  82. package/template/src/components/ui/command/CommandEmpty.vue +27 -0
  83. package/template/src/components/ui/command/CommandGroup.vue +45 -0
  84. package/template/src/components/ui/command/CommandInput.vue +39 -0
  85. package/template/src/components/ui/command/CommandItem.vue +76 -0
  86. package/template/src/components/ui/command/CommandList.vue +25 -0
  87. package/template/src/components/ui/command/CommandSeparator.vue +21 -0
  88. package/template/src/components/ui/command/CommandShortcut.vue +17 -0
  89. package/template/src/components/ui/command/index.ts +25 -0
  90. package/template/src/components/ui/context-menu/ContextMenu.vue +15 -0
  91. package/template/src/components/ui/context-menu/ContextMenuCheckboxItem.vue +36 -0
  92. package/template/src/components/ui/context-menu/ContextMenuContent.vue +33 -0
  93. package/template/src/components/ui/context-menu/ContextMenuGroup.vue +12 -0
  94. package/template/src/components/ui/context-menu/ContextMenuItem.vue +36 -0
  95. package/template/src/components/ui/context-menu/ContextMenuLabel.vue +25 -0
  96. package/template/src/components/ui/context-menu/ContextMenuRadioGroup.vue +18 -0
  97. package/template/src/components/ui/context-menu/ContextMenuRadioItem.vue +36 -0
  98. package/template/src/components/ui/context-menu/ContextMenuSeparator.vue +18 -0
  99. package/template/src/components/ui/context-menu/ContextMenuShortcut.vue +17 -0
  100. package/template/src/components/ui/context-menu/ContextMenuSub.vue +15 -0
  101. package/template/src/components/ui/context-menu/ContextMenuSubContent.vue +36 -0
  102. package/template/src/components/ui/context-menu/ContextMenuSubTrigger.vue +32 -0
  103. package/template/src/components/ui/context-menu/ContextMenuTrigger.vue +13 -0
  104. package/template/src/components/ui/context-menu/index.ts +14 -0
  105. package/template/src/components/ui/date-picker/DatePicker.vue +233 -0
  106. package/template/src/components/ui/date-picker/index.ts +1 -0
  107. package/template/src/components/ui/dialog/Dialog.vue +19 -0
  108. package/template/src/components/ui/dialog/DialogClose.vue +15 -0
  109. package/template/src/components/ui/dialog/DialogContent.vue +53 -0
  110. package/template/src/components/ui/dialog/DialogDescription.vue +23 -0
  111. package/template/src/components/ui/dialog/DialogFooter.vue +27 -0
  112. package/template/src/components/ui/dialog/DialogHeader.vue +17 -0
  113. package/template/src/components/ui/dialog/DialogOverlay.vue +21 -0
  114. package/template/src/components/ui/dialog/DialogScrollContent.vue +59 -0
  115. package/template/src/components/ui/dialog/DialogTitle.vue +23 -0
  116. package/template/src/components/ui/dialog/DialogTrigger.vue +15 -0
  117. package/template/src/components/ui/dialog/index.ts +10 -0
  118. package/template/src/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
  119. package/template/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +39 -0
  120. package/template/src/components/ui/dropdown-menu/DropdownMenuContent.vue +41 -0
  121. package/template/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +15 -0
  122. package/template/src/components/ui/dropdown-menu/DropdownMenuItem.vue +31 -0
  123. package/template/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +23 -0
  124. package/template/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  125. package/template/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +40 -0
  126. package/template/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  127. package/template/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +17 -0
  128. package/template/src/components/ui/dropdown-menu/DropdownMenuSub.vue +18 -0
  129. package/template/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +27 -0
  130. package/template/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +31 -0
  131. package/template/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  132. package/template/src/components/ui/dropdown-menu/index.ts +16 -0
  133. package/template/src/components/ui/form/FormControl.vue +17 -0
  134. package/template/src/components/ui/form/FormDescription.vue +21 -0
  135. package/template/src/components/ui/form/FormItem.vue +23 -0
  136. package/template/src/components/ui/form/FormLabel.vue +25 -0
  137. package/template/src/components/ui/form/FormMessage.vue +23 -0
  138. package/template/src/components/ui/form/index.ts +7 -0
  139. package/template/src/components/ui/form/injectionKeys.ts +4 -0
  140. package/template/src/components/ui/form/useFormField.ts +30 -0
  141. package/template/src/components/ui/hover-card/HoverCard.vue +19 -0
  142. package/template/src/components/ui/hover-card/HoverCardContent.vue +43 -0
  143. package/template/src/components/ui/hover-card/HoverCardTrigger.vue +15 -0
  144. package/template/src/components/ui/hover-card/index.ts +3 -0
  145. package/template/src/components/ui/index.ts +47 -0
  146. package/template/src/components/ui/input/Input.vue +33 -0
  147. package/template/src/components/ui/input/InputAddon.vue +29 -0
  148. package/template/src/components/ui/input/InputGroup.vue +17 -0
  149. package/template/src/components/ui/input/InputIcon.vue +29 -0
  150. package/template/src/components/ui/input/index.ts +4 -0
  151. package/template/src/components/ui/kbd/Kbd.vue +30 -0
  152. package/template/src/components/ui/kbd/index.ts +1 -0
  153. package/template/src/components/ui/label/Label.vue +26 -0
  154. package/template/src/components/ui/label/index.ts +1 -0
  155. package/template/src/components/ui/loading-bar/LoadingBar.vue +41 -0
  156. package/template/src/components/ui/loading-bar/index.ts +2 -0
  157. package/template/src/components/ui/pagination/Pagination.vue +26 -0
  158. package/template/src/components/ui/pagination/PaginationContent.vue +22 -0
  159. package/template/src/components/ui/pagination/PaginationEllipsis.vue +25 -0
  160. package/template/src/components/ui/pagination/PaginationFirst.vue +33 -0
  161. package/template/src/components/ui/pagination/PaginationItem.vue +34 -0
  162. package/template/src/components/ui/pagination/PaginationLast.vue +33 -0
  163. package/template/src/components/ui/pagination/PaginationNext.vue +33 -0
  164. package/template/src/components/ui/pagination/PaginationPrevious.vue +33 -0
  165. package/template/src/components/ui/pagination/index.ts +8 -0
  166. package/template/src/components/ui/pin-input/PinInput.vue +28 -0
  167. package/template/src/components/ui/pin-input/PinInputGroup.vue +18 -0
  168. package/template/src/components/ui/pin-input/PinInputInput.vue +24 -0
  169. package/template/src/components/ui/pin-input/PinInputSeparator.vue +21 -0
  170. package/template/src/components/ui/pin-input/index.ts +4 -0
  171. package/template/src/components/ui/popover/Popover.vue +19 -0
  172. package/template/src/components/ui/popover/PopoverAnchor.vue +15 -0
  173. package/template/src/components/ui/popover/PopoverContent.vue +45 -0
  174. package/template/src/components/ui/popover/PopoverTrigger.vue +15 -0
  175. package/template/src/components/ui/popover/index.ts +4 -0
  176. package/template/src/components/ui/progress/Progress.vue +35 -0
  177. package/template/src/components/ui/progress/index.ts +1 -0
  178. package/template/src/components/ui/radio-group/RadioGroup.vue +23 -0
  179. package/template/src/components/ui/radio-group/RadioGroupItem.vue +30 -0
  180. package/template/src/components/ui/radio-group/index.ts +2 -0
  181. package/template/src/components/ui/scroll-area/ScrollArea.vue +40 -0
  182. package/template/src/components/ui/scroll-area/ScrollBar.vue +44 -0
  183. package/template/src/components/ui/scroll-area/index.ts +2 -0
  184. package/template/src/components/ui/select/Select.vue +19 -0
  185. package/template/src/components/ui/select/SelectContent.vue +51 -0
  186. package/template/src/components/ui/select/SelectGroup.vue +15 -0
  187. package/template/src/components/ui/select/SelectItem.vue +44 -0
  188. package/template/src/components/ui/select/SelectItemText.vue +15 -0
  189. package/template/src/components/ui/select/SelectLabel.vue +17 -0
  190. package/template/src/components/ui/select/SelectScrollDownButton.vue +26 -0
  191. package/template/src/components/ui/select/SelectScrollUpButton.vue +26 -0
  192. package/template/src/components/ui/select/SelectSeparator.vue +19 -0
  193. package/template/src/components/ui/select/SelectTrigger.vue +33 -0
  194. package/template/src/components/ui/select/SelectValue.vue +15 -0
  195. package/template/src/components/ui/select/index.ts +11 -0
  196. package/template/src/components/ui/separator/Separator.vue +29 -0
  197. package/template/src/components/ui/separator/index.ts +1 -0
  198. package/template/src/components/ui/sheet/Sheet.vue +19 -0
  199. package/template/src/components/ui/sheet/SheetClose.vue +15 -0
  200. package/template/src/components/ui/sheet/SheetContent.vue +62 -0
  201. package/template/src/components/ui/sheet/SheetDescription.vue +21 -0
  202. package/template/src/components/ui/sheet/SheetFooter.vue +16 -0
  203. package/template/src/components/ui/sheet/SheetHeader.vue +15 -0
  204. package/template/src/components/ui/sheet/SheetOverlay.vue +21 -0
  205. package/template/src/components/ui/sheet/SheetTitle.vue +21 -0
  206. package/template/src/components/ui/sheet/SheetTrigger.vue +15 -0
  207. package/template/src/components/ui/sheet/index.ts +8 -0
  208. package/template/src/components/ui/sidebar/Sidebar.vue +113 -0
  209. package/template/src/components/ui/sidebar/SidebarContent.vue +18 -0
  210. package/template/src/components/ui/sidebar/SidebarControl.vue +53 -0
  211. package/template/src/components/ui/sidebar/SidebarFooter.vue +18 -0
  212. package/template/src/components/ui/sidebar/SidebarGroup.vue +18 -0
  213. package/template/src/components/ui/sidebar/SidebarGroupAction.vue +27 -0
  214. package/template/src/components/ui/sidebar/SidebarGroupContent.vue +18 -0
  215. package/template/src/components/ui/sidebar/SidebarGroupLabel.vue +25 -0
  216. package/template/src/components/ui/sidebar/SidebarHeader.vue +18 -0
  217. package/template/src/components/ui/sidebar/SidebarInput.vue +22 -0
  218. package/template/src/components/ui/sidebar/SidebarInset.vue +21 -0
  219. package/template/src/components/ui/sidebar/SidebarMenu.vue +18 -0
  220. package/template/src/components/ui/sidebar/SidebarMenuAction.vue +35 -0
  221. package/template/src/components/ui/sidebar/SidebarMenuBadge.vue +26 -0
  222. package/template/src/components/ui/sidebar/SidebarMenuButton.vue +48 -0
  223. package/template/src/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
  224. package/template/src/components/ui/sidebar/SidebarMenuItem.vue +18 -0
  225. package/template/src/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
  226. package/template/src/components/ui/sidebar/SidebarMenuSub.vue +22 -0
  227. package/template/src/components/ui/sidebar/SidebarMenuSubButton.vue +36 -0
  228. package/template/src/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
  229. package/template/src/components/ui/sidebar/SidebarProvider.vue +136 -0
  230. package/template/src/components/ui/sidebar/SidebarRail.vue +33 -0
  231. package/template/src/components/ui/sidebar/SidebarSeparator.vue +19 -0
  232. package/template/src/components/ui/sidebar/SidebarTrigger.vue +27 -0
  233. package/template/src/components/ui/sidebar/index.ts +61 -0
  234. package/template/src/components/ui/sidebar/utils.ts +27 -0
  235. package/template/src/components/ui/skeleton/Skeleton.vue +17 -0
  236. package/template/src/components/ui/skeleton/index.ts +1 -0
  237. package/template/src/components/ui/slider/Slider.vue +42 -0
  238. package/template/src/components/ui/slider/index.ts +1 -0
  239. package/template/src/components/ui/sonner/Sonner.vue +42 -0
  240. package/template/src/components/ui/sonner/index.ts +2 -0
  241. package/template/src/components/ui/stepper/Stepper.vue +102 -0
  242. package/template/src/components/ui/stepper/index.ts +1 -0
  243. package/template/src/components/ui/switch/Switch.vue +38 -0
  244. package/template/src/components/ui/switch/index.ts +1 -0
  245. package/template/src/components/ui/table/Table.vue +16 -0
  246. package/template/src/components/ui/table/TableBody.vue +17 -0
  247. package/template/src/components/ui/table/TableCaption.vue +17 -0
  248. package/template/src/components/ui/table/TableCell.vue +22 -0
  249. package/template/src/components/ui/table/TableEmpty.vue +34 -0
  250. package/template/src/components/ui/table/TableFooter.vue +17 -0
  251. package/template/src/components/ui/table/TableHead.vue +17 -0
  252. package/template/src/components/ui/table/TableHeader.vue +17 -0
  253. package/template/src/components/ui/table/TableRow.vue +17 -0
  254. package/template/src/components/ui/table/index.ts +9 -0
  255. package/template/src/components/ui/table/utils.ts +10 -0
  256. package/template/src/components/ui/tabs/Tabs.vue +24 -0
  257. package/template/src/components/ui/tabs/TabsContent.vue +21 -0
  258. package/template/src/components/ui/tabs/TabsList.vue +24 -0
  259. package/template/src/components/ui/tabs/TabsTrigger.vue +26 -0
  260. package/template/src/components/ui/tabs/index.ts +4 -0
  261. package/template/src/components/ui/textarea/Textarea.vue +28 -0
  262. package/template/src/components/ui/textarea/index.ts +1 -0
  263. package/template/src/components/ui/timeline/Timeline.vue +73 -0
  264. package/template/src/components/ui/timeline/index.ts +1 -0
  265. package/template/src/components/ui/toggle/Toggle.vue +35 -0
  266. package/template/src/components/ui/toggle/index.ts +28 -0
  267. package/template/src/components/ui/toggle-group/ToggleGroup.vue +41 -0
  268. package/template/src/components/ui/toggle-group/ToggleGroupItem.vue +43 -0
  269. package/template/src/components/ui/toggle-group/index.ts +12 -0
  270. package/template/src/components/ui/tooltip/Tooltip.vue +19 -0
  271. package/template/src/components/ui/tooltip/TooltipContent.vue +34 -0
  272. package/template/src/components/ui/tooltip/TooltipProvider.vue +14 -0
  273. package/template/src/components/ui/tooltip/TooltipTrigger.vue +15 -0
  274. package/template/src/components/ui/tooltip/index.ts +4 -0
  275. package/template/src/components.d.ts +228 -0
  276. package/template/src/composables/useFormatter.ts +105 -0
  277. package/template/src/composables/useThemeConfig.ts +252 -0
  278. package/template/src/layouts/AdminLayout.vue +55 -0
  279. package/template/src/layouts/AuthLayout.vue +42 -0
  280. package/template/src/lib/axios.spec.ts +46 -0
  281. package/template/src/lib/axios.ts +243 -0
  282. package/template/src/lib/formatters.spec.ts +137 -0
  283. package/template/src/lib/formatters.ts +332 -0
  284. package/template/src/lib/loading-bar.ts +103 -0
  285. package/template/src/lib/utils.spec.ts +26 -0
  286. package/template/src/lib/utils.ts +7 -0
  287. package/template/src/lib/validation.spec.ts +78 -0
  288. package/template/src/main.ts +13 -0
  289. package/template/src/router/index.ts +147 -0
  290. package/template/src/services/auth.service.spec.ts +93 -0
  291. package/template/src/services/auth.service.ts +243 -0
  292. package/template/src/services/index.ts +3 -0
  293. package/template/src/services/types.ts +28 -0
  294. package/template/src/services/user.service.spec.ts +91 -0
  295. package/template/src/services/user.service.ts +283 -0
  296. package/template/src/stores/auth.spec.ts +52 -0
  297. package/template/src/stores/auth.ts +130 -0
  298. package/template/src/style.css +587 -0
  299. package/template/src/views/_starter/BlankView.vue +47 -0
  300. package/template/src/views/auth/ConfirmEmailView.vue +209 -0
  301. package/template/src/views/auth/ForgotPasswordView.vue +151 -0
  302. package/template/src/views/auth/LockScreenView.vue +175 -0
  303. package/template/src/views/auth/LoginView.vue +54 -0
  304. package/template/src/views/auth/RegisterView.vue +265 -0
  305. package/template/src/views/auth/ResetPasswordView.vue +260 -0
  306. package/template/src/views/auth/VerifyOtpView.vue +261 -0
  307. package/template/src/views/dashboard/IndexView.vue +159 -0
  308. package/template/src/views/errors/ComingSoonView.vue +241 -0
  309. package/template/src/views/errors/MaintenanceView.vue +252 -0
  310. package/template/src/views/errors/NotFoundView.vue +81 -0
  311. package/template/src/views/errors/ServerErrorView.vue +101 -0
  312. package/template/src/views/errors/UnauthorizedView.vue +64 -0
  313. package/template/tsconfig.app.json +27 -0
  314. package/template/tsconfig.json +19 -0
  315. package/template/tsconfig.node.json +23 -0
  316. package/template/vite.config.ts +46 -0
@@ -0,0 +1,22 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes["class"]
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <ul
12
+ data-slot="sidebar-menu-sub"
13
+ data-sidebar="menu-badge"
14
+ :class="cn(
15
+ 'border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5',
16
+ 'group-data-[collapsible=icon]:hidden',
17
+ props.class,
18
+ )"
19
+ >
20
+ <slot />
21
+ </ul>
22
+ </template>
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import type { PrimitiveProps } from "reka-ui"
3
+ import type { HTMLAttributes } from "vue"
4
+ import { Primitive } from "reka-ui"
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const props = withDefaults(defineProps<PrimitiveProps & {
8
+ size?: "sm" | "md"
9
+ isActive?: boolean
10
+ class?: HTMLAttributes["class"]
11
+ }>(), {
12
+ as: "a",
13
+ size: "md",
14
+ })
15
+ </script>
16
+
17
+ <template>
18
+ <Primitive
19
+ data-slot="sidebar-menu-sub-button"
20
+ data-sidebar="menu-sub-button"
21
+ :as="as"
22
+ :as-child="asChild"
23
+ :data-size="size"
24
+ :data-active="isActive"
25
+ :class="cn(
26
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
27
+ 'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground',
28
+ size === 'sm' && 'text-xs',
29
+ size === 'md' && 'text-sm',
30
+ 'group-data-[collapsible=icon]:hidden',
31
+ props.class,
32
+ )"
33
+ >
34
+ <slot />
35
+ </Primitive>
36
+ </template>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes["class"]
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <li
12
+ data-slot="sidebar-menu-sub-item"
13
+ data-sidebar="menu-sub-item"
14
+ :class="cn('group/menu-sub-item relative', props.class)"
15
+ >
16
+ <slot />
17
+ </li>
18
+ </template>
@@ -0,0 +1,136 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes, Ref } from "vue"
3
+ import { defaultDocument, useEventListener, useMediaQuery, useVModel } from "@vueuse/core"
4
+ import { TooltipProvider } from "reka-ui"
5
+ import { computed, ref } from "vue"
6
+ import { cn } from "@/lib/utils"
7
+ import { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON, type SidebarControlMode } from "./utils"
8
+
9
+ const props = withDefaults(defineProps<{
10
+ defaultOpen?: boolean
11
+ open?: boolean
12
+ class?: HTMLAttributes["class"]
13
+ }>(), {
14
+ defaultOpen: !defaultDocument?.cookie.includes(`${SIDEBAR_COOKIE_NAME}=false`),
15
+ open: undefined,
16
+ })
17
+
18
+ const emits = defineEmits<{
19
+ "update:open": [open: boolean]
20
+ }>()
21
+
22
+ const isMobile = useMediaQuery("(max-width: 768px)")
23
+ const openMobile = ref(false)
24
+
25
+ const open = useVModel(props, "open", emits, {
26
+ defaultValue: props.defaultOpen ?? false,
27
+ passive: (props.open === undefined) as false,
28
+ }) as Ref<boolean>
29
+
30
+ const getSavedMode = (): SidebarControlMode => {
31
+ if (typeof document === 'undefined') return 'expanded'
32
+ const match = document.cookie.match(/sidebar_mode=([^;]+)/)
33
+ if (match && ['expanded', 'collapsed', 'hover'].includes(match[1])) {
34
+ return match[1] as SidebarControlMode
35
+ }
36
+ return open.value ? 'expanded' : 'collapsed'
37
+ }
38
+
39
+ const sidebarMode = ref<SidebarControlMode>(getSavedMode())
40
+ const isHovered = ref(false)
41
+ const isMenuOpen = ref(false)
42
+
43
+ function setSidebarMode(mode: SidebarControlMode) {
44
+ sidebarMode.value = mode
45
+ document.cookie = `sidebar_mode=${mode}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
46
+ if (mode === "expanded") {
47
+ setOpen(true)
48
+ } else if (mode === "collapsed") {
49
+ setOpen(false)
50
+ } else if (mode === "hover") {
51
+ setOpen(false)
52
+ }
53
+ }
54
+
55
+ function setIsHovered(val: boolean) {
56
+ isHovered.value = val
57
+ }
58
+
59
+ function setIsMenuOpen(val: boolean) {
60
+ isMenuOpen.value = val
61
+ if (val) {
62
+ isHovered.value = true
63
+ }
64
+ }
65
+
66
+ function setOpen(value: boolean) {
67
+ open.value = value // emits('update:open', value)
68
+
69
+ // This sets the cookie to keep the sidebar state.
70
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${open.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
71
+ }
72
+
73
+ function setOpenMobile(value: boolean) {
74
+ openMobile.value = value
75
+ }
76
+
77
+ // Helper to toggle the sidebar.
78
+ function toggleSidebar() {
79
+ if (isMobile.value) {
80
+ setOpenMobile(!openMobile.value)
81
+ } else {
82
+ const nextState = !open.value
83
+ setOpen(nextState)
84
+ sidebarMode.value = nextState ? 'expanded' : 'collapsed'
85
+ document.cookie = `sidebar_mode=${sidebarMode.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
86
+ }
87
+ }
88
+
89
+ useEventListener("keydown", (event: KeyboardEvent) => {
90
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
91
+ event.preventDefault()
92
+ toggleSidebar()
93
+ }
94
+ })
95
+
96
+ // We add a state so that we can do data-state="expanded" or "collapsed".
97
+ // This makes it easier to style the sidebar with Tailwind classes.
98
+ const state = computed(() => {
99
+ if (sidebarMode.value === "hover") {
100
+ return (isHovered.value || isMenuOpen.value) ? "expanded" : "collapsed"
101
+ }
102
+ return open.value ? "expanded" : "collapsed"
103
+ })
104
+
105
+ provideSidebarContext({
106
+ state,
107
+ open,
108
+ setOpen,
109
+ isMobile,
110
+ openMobile,
111
+ setOpenMobile,
112
+ toggleSidebar,
113
+ sidebarMode,
114
+ setSidebarMode,
115
+ isHovered,
116
+ setIsHovered,
117
+ isMenuOpen,
118
+ setIsMenuOpen,
119
+ })
120
+ </script>
121
+
122
+ <template>
123
+ <TooltipProvider :delay-duration="0">
124
+ <div
125
+ data-slot="sidebar-wrapper"
126
+ :style="{
127
+ '--sidebar-width': SIDEBAR_WIDTH,
128
+ '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
129
+ }"
130
+ :class="cn('group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full', props.class)"
131
+ v-bind="$attrs"
132
+ >
133
+ <slot />
134
+ </div>
135
+ </TooltipProvider>
136
+ </template>
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+ import { useSidebar } from "./utils"
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes["class"]
8
+ }>()
9
+
10
+ const { toggleSidebar } = useSidebar()
11
+ </script>
12
+
13
+ <template>
14
+ <button
15
+ data-sidebar="rail"
16
+ data-slot="sidebar-rail"
17
+ aria-label="Toggle Sidebar"
18
+ :tabindex="-1"
19
+ title="Toggle Sidebar"
20
+ :class="cn(
21
+ 'hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-0.5 sm:flex',
22
+ 'in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize',
23
+ '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
24
+ 'hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full',
25
+ '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
26
+ '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
27
+ props.class,
28
+ )"
29
+ @click="toggleSidebar"
30
+ >
31
+ <slot />
32
+ </button>
33
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+ import { Separator } from '@/components/ui/separator'
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes["class"]
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <Separator
13
+ data-slot="sidebar-separator"
14
+ data-sidebar="separator"
15
+ :class="cn('bg-sidebar-border mx-2 w-auto', props.class)"
16
+ >
17
+ <slot />
18
+ </Separator>
19
+ </template>
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { PanelLeft } from "@lucide/vue"
4
+ import { cn } from "@/lib/utils"
5
+ import { Button } from '@/components/ui/button'
6
+ import { useSidebar } from "./utils"
7
+
8
+ const props = defineProps<{
9
+ class?: HTMLAttributes["class"]
10
+ }>()
11
+
12
+ const { toggleSidebar } = useSidebar()
13
+ </script>
14
+
15
+ <template>
16
+ <Button
17
+ data-sidebar="trigger"
18
+ data-slot="sidebar-trigger"
19
+ variant="ghost"
20
+ size="icon"
21
+ :class="cn('h-7 w-7', props.class)"
22
+ @click="toggleSidebar"
23
+ >
24
+ <PanelLeft />
25
+ <span class="sr-only">Toggle Sidebar</span>
26
+ </Button>
27
+ </template>
@@ -0,0 +1,61 @@
1
+ import type { VariantProps } from "class-variance-authority"
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cva } from "class-variance-authority"
4
+
5
+ export interface SidebarProps {
6
+ side?: "left" | "right"
7
+ variant?: "sidebar" | "floating" | "inset"
8
+ collapsible?: "offcanvas" | "icon" | "none"
9
+ class?: HTMLAttributes["class"]
10
+ }
11
+
12
+ export { default as Sidebar } from "./Sidebar.vue"
13
+ export { default as SidebarContent } from "./SidebarContent.vue"
14
+ export { default as SidebarFooter } from "./SidebarFooter.vue"
15
+ export { default as SidebarGroup } from "./SidebarGroup.vue"
16
+ export { default as SidebarGroupAction } from "./SidebarGroupAction.vue"
17
+ export { default as SidebarGroupContent } from "./SidebarGroupContent.vue"
18
+ export { default as SidebarGroupLabel } from "./SidebarGroupLabel.vue"
19
+ export { default as SidebarHeader } from "./SidebarHeader.vue"
20
+ export { default as SidebarInput } from "./SidebarInput.vue"
21
+ export { default as SidebarInset } from "./SidebarInset.vue"
22
+ export { default as SidebarMenu } from "./SidebarMenu.vue"
23
+ export { default as SidebarMenuAction } from "./SidebarMenuAction.vue"
24
+ export { default as SidebarMenuBadge } from "./SidebarMenuBadge.vue"
25
+ export { default as SidebarMenuButton } from "./SidebarMenuButton.vue"
26
+ export { default as SidebarMenuItem } from "./SidebarMenuItem.vue"
27
+ export { default as SidebarMenuSkeleton } from "./SidebarMenuSkeleton.vue"
28
+ export { default as SidebarMenuSub } from "./SidebarMenuSub.vue"
29
+ export { default as SidebarMenuSubButton } from "./SidebarMenuSubButton.vue"
30
+ export { default as SidebarMenuSubItem } from "./SidebarMenuSubItem.vue"
31
+ export { default as SidebarProvider } from "./SidebarProvider.vue"
32
+ export { default as SidebarRail } from "./SidebarRail.vue"
33
+ export { default as SidebarSeparator } from "./SidebarSeparator.vue"
34
+ export { default as SidebarTrigger } from "./SidebarTrigger.vue"
35
+ export { default as SidebarControl } from "./SidebarControl.vue"
36
+
37
+ export { useSidebar } from "./utils"
38
+
39
+ export const sidebarMenuButtonVariants = cva(
40
+ "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm text-sidebar-foreground outline-hidden ring-sidebar-ring transition-colors duration-150 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-foreground hover:[&>svg]:text-sidebar-accent-foreground data-[active=true]:[&>svg]:text-sidebar-accent-foreground",
41
+ {
42
+ variants: {
43
+ variant: {
44
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
45
+ outline:
46
+ "bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]",
47
+ },
48
+ size: {
49
+ default: "h-8 text-sm",
50
+ sm: "h-7 text-xs",
51
+ lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
52
+ },
53
+ },
54
+ defaultVariants: {
55
+ variant: "default",
56
+ size: "default",
57
+ },
58
+ },
59
+ )
60
+
61
+ export type SidebarMenuButtonVariants = VariantProps<typeof sidebarMenuButtonVariants>
@@ -0,0 +1,27 @@
1
+ import type { ComputedRef, Ref } from "vue"
2
+ import { createContext } from "reka-ui"
3
+
4
+ export const SIDEBAR_COOKIE_NAME = "sidebar_state"
5
+ export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
6
+ export const SIDEBAR_WIDTH = "14rem"
7
+ export const SIDEBAR_WIDTH_MOBILE = "18rem"
8
+ export const SIDEBAR_WIDTH_ICON = "3.5rem"
9
+ export const SIDEBAR_KEYBOARD_SHORTCUT = "b"
10
+
11
+ export type SidebarControlMode = "expanded" | "collapsed" | "hover"
12
+
13
+ export const [useSidebar, provideSidebarContext] = createContext<{
14
+ state: ComputedRef<"expanded" | "collapsed">
15
+ open: Ref<boolean>
16
+ setOpen: (value: boolean) => void
17
+ isMobile: Ref<boolean>
18
+ openMobile: Ref<boolean>
19
+ setOpenMobile: (value: boolean) => void
20
+ toggleSidebar: () => void
21
+ sidebarMode: Ref<SidebarControlMode>
22
+ setSidebarMode: (mode: SidebarControlMode) => void
23
+ isHovered: Ref<boolean>
24
+ setIsHovered: (value: boolean) => void
25
+ isMenuOpen: Ref<boolean>
26
+ setIsMenuOpen: (value: boolean) => void
27
+ }>("Sidebar")
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ interface SkeletonProps {
6
+ class?: HTMLAttributes["class"]
7
+ }
8
+
9
+ const props = defineProps<SkeletonProps>()
10
+ </script>
11
+
12
+ <template>
13
+ <div
14
+ data-slot="skeleton"
15
+ :class="cn('animate-pulse rounded-md bg-primary/10', props.class)"
16
+ />
17
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Skeleton } from "./Skeleton.vue"
@@ -0,0 +1,42 @@
1
+ <script setup lang="ts">
2
+ import type { SliderRootEmits, SliderRootProps } from "reka-ui"
3
+ import type { HTMLAttributes } from "vue"
4
+ import { reactiveOmit } from "@vueuse/core"
5
+ import { SliderRange, SliderRoot, SliderThumb, SliderTrack, useForwardPropsEmits } from "reka-ui"
6
+ import { cn } from "@/lib/utils"
7
+
8
+ const props = defineProps<SliderRootProps & { class?: HTMLAttributes["class"] }>()
9
+ const emits = defineEmits<SliderRootEmits>()
10
+
11
+ const delegatedProps = reactiveOmit(props, "class")
12
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
13
+ </script>
14
+
15
+ <template>
16
+ <SliderRoot
17
+ data-slot="slider"
18
+ :class="
19
+ cn(
20
+ 'relative flex w-full touch-none select-none items-center data-[orientation=vertical]:h-full data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
21
+ props.class
22
+ )
23
+ "
24
+ v-bind="forwarded"
25
+ >
26
+ <SliderTrack
27
+ data-slot="slider-track"
28
+ class="bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
29
+ >
30
+ <SliderRange
31
+ data-slot="slider-range"
32
+ class="bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
33
+ />
34
+ </SliderTrack>
35
+ <SliderThumb
36
+ v-for="(_, key) in (modelValue ?? defaultValue ?? [0])"
37
+ :key="key"
38
+ data-slot="slider-thumb"
39
+ class="border-primary bg-background ring-offset-background focus-visible:ring-ring block size-4 rounded-full border-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 cursor-grab active:cursor-grabbing hover:scale-110"
40
+ />
41
+ </SliderRoot>
42
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Slider } from './Slider.vue'
@@ -0,0 +1,42 @@
1
+ <script lang="ts" setup>
2
+ import type { ToasterProps } from "vue-sonner"
3
+ import { CircleCheckIcon, InfoIcon, Loader2Icon, OctagonXIcon, TriangleAlertIcon, XIcon } from "@lucide/vue"
4
+ import { Toaster as Sonner } from "vue-sonner"
5
+ import { cn } from "@/lib/utils"
6
+
7
+ const props = defineProps<ToasterProps>()
8
+ </script>
9
+
10
+ <template>
11
+ <Sonner
12
+ :class="cn('toaster group', props.class)"
13
+ :style="{
14
+ '--normal-bg': 'var(--popover)',
15
+ '--normal-text': 'var(--popover-foreground)',
16
+ '--normal-border': 'var(--border)',
17
+ '--border-radius': 'var(--radius)',
18
+ }"
19
+ v-bind="props"
20
+ >
21
+ <template #success-icon>
22
+ <CircleCheckIcon class="size-4" />
23
+ </template>
24
+ <template #info-icon>
25
+ <InfoIcon class="size-4" />
26
+ </template>
27
+ <template #warning-icon>
28
+ <TriangleAlertIcon class="size-4" />
29
+ </template>
30
+ <template #error-icon>
31
+ <OctagonXIcon class="size-4" />
32
+ </template>
33
+ <template #loading-icon>
34
+ <div>
35
+ <Loader2Icon class="size-4 animate-spin" />
36
+ </div>
37
+ </template>
38
+ <template #close-icon>
39
+ <XIcon class="size-4" />
40
+ </template>
41
+ </Sonner>
42
+ </template>
@@ -0,0 +1,2 @@
1
+ export { default as Toaster } from "./Sonner.vue"
2
+ export { toast } from "vue-sonner"
@@ -0,0 +1,102 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ interface Step {
6
+ id: number | string
7
+ title: string
8
+ description?: string
9
+ }
10
+
11
+ interface Props {
12
+ steps: Step[]
13
+ modelValue: number
14
+ class?: HTMLAttributes["class"]
15
+ orientation?: "horizontal" | "vertical"
16
+ }
17
+
18
+ const props = withDefaults(defineProps<Props>(), {
19
+ orientation: "horizontal",
20
+ })
21
+
22
+ const emit = defineEmits<{
23
+ (e: "update:modelValue", value: number): void
24
+ }>()
25
+
26
+ const setStep = (stepIndex: number) => {
27
+ emit("update:modelValue", stepIndex)
28
+ }
29
+ </script>
30
+
31
+ <template>
32
+ <div
33
+ data-slot="stepper"
34
+ :class="
35
+ cn(
36
+ 'w-full',
37
+ orientation === 'horizontal' ? 'flex items-center justify-between' : 'flex flex-col gap-4',
38
+ props.class
39
+ )
40
+ "
41
+ >
42
+ <div
43
+ v-for="(step, index) in steps"
44
+ :key="step.id"
45
+ class="flex items-center flex-1 last:flex-none relative"
46
+ :class="orientation === 'vertical' ? 'flex-col items-start' : ''"
47
+ >
48
+ <!-- Step Trigger -->
49
+ <button
50
+ type="button"
51
+ @click="setStep(index + 1)"
52
+ class="flex items-center gap-3 text-left group cursor-pointer focus:outline-none"
53
+ >
54
+ <!-- Step Indicator Circle -->
55
+ <span
56
+ class="relative flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-xs font-semibold font-mono transition-all duration-300 shadow-2xs"
57
+ :class="[
58
+ index + 1 < modelValue
59
+ ? 'bg-primary text-primary-foreground'
60
+ : index + 1 === modelValue
61
+ ? 'bg-primary/10 text-primary border-2 border-primary ring-4 ring-primary/10'
62
+ : 'border border-border bg-muted/40 text-muted-foreground group-hover:border-muted-foreground/50'
63
+ ]"
64
+ >
65
+ <!-- Checkmark for completed -->
66
+ <svg
67
+ v-if="index + 1 < modelValue"
68
+ class="h-4 w-4 stroke-3"
69
+ fill="none"
70
+ viewBox="0 0 24 24"
71
+ stroke="currentColor"
72
+ >
73
+ <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
74
+ </svg>
75
+ <span v-else>{{ index + 1 }}</span>
76
+ </span>
77
+
78
+ <!-- Step Labels -->
79
+ <div class="space-y-0.5">
80
+ <p
81
+ class="text-xs font-medium transition-colors"
82
+ :class="[
83
+ index + 1 <= modelValue ? 'text-foreground font-semibold' : 'text-muted-foreground'
84
+ ]"
85
+ >
86
+ {{ step.title }}
87
+ </p>
88
+ <p v-if="step.description" class="text-[11px] text-muted-foreground hidden sm:block">
89
+ {{ step.description }}
90
+ </p>
91
+ </div>
92
+ </button>
93
+
94
+ <!-- Connecting Separator Line (if not last) -->
95
+ <div
96
+ v-if="index < steps.length - 1 && orientation === 'horizontal'"
97
+ class="flex-1 mx-3 h-0.5 transition-colors duration-300"
98
+ :class="index + 1 < modelValue ? 'bg-primary' : 'bg-border'"
99
+ />
100
+ </div>
101
+ </div>
102
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Stepper } from './Stepper.vue'
@@ -0,0 +1,38 @@
1
+ <script setup lang="ts">
2
+ import type { SwitchRootEmits, SwitchRootProps } from "reka-ui"
3
+ import type { HTMLAttributes } from "vue"
4
+ import { reactiveOmit } from "@vueuse/core"
5
+ import {
6
+ SwitchRoot,
7
+ SwitchThumb,
8
+ useForwardPropsEmits,
9
+ } from "reka-ui"
10
+ import { cn } from "@/lib/utils"
11
+
12
+ const props = defineProps<SwitchRootProps & { class?: HTMLAttributes["class"] }>()
13
+
14
+ const emits = defineEmits<SwitchRootEmits>()
15
+
16
+ const delegatedProps = reactiveOmit(props, "class")
17
+
18
+ const forwarded = useForwardPropsEmits(delegatedProps, emits)
19
+ </script>
20
+
21
+ <template>
22
+ <SwitchRoot
23
+ v-slot="slotProps"
24
+ data-slot="switch"
25
+ v-bind="forwarded"
26
+ :class="cn(
27
+ 'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50',
28
+ props.class,
29
+ )"
30
+ >
31
+ <SwitchThumb
32
+ data-slot="switch-thumb"
33
+ :class="cn('bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0')"
34
+ >
35
+ <slot name="thumb" v-bind="slotProps" />
36
+ </SwitchThumb>
37
+ </SwitchRoot>
38
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Switch } from "./Switch.vue"
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from "vue"
3
+ import { cn } from "@/lib/utils"
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes["class"]
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <div data-slot="table-container" class="relative w-full overflow-auto">
12
+ <table data-slot="table" :class="cn('w-full caption-bottom text-sm', props.class)">
13
+ <slot />
14
+ </table>
15
+ </div>
16
+ </template>