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,228 @@
1
+ /* eslint-disable */
2
+ // @ts-nocheck
3
+ // biome-ignore lint: disable
4
+ // oxlint-disable
5
+ // ------
6
+ // Generated by unplugin-vue-components
7
+ // Read more: https://github.com/vuejs/core/pull/3399
8
+
9
+ export {}
10
+
11
+ /* prettier-ignore */
12
+ declare module 'vue' {
13
+ export interface GlobalComponents {
14
+ Accordion: typeof import('./components/ui/accordion/Accordion.vue')['default']
15
+ AccordionContent: typeof import('./components/ui/accordion/AccordionContent.vue')['default']
16
+ AccordionItem: typeof import('./components/ui/accordion/AccordionItem.vue')['default']
17
+ AccordionTrigger: typeof import('./components/ui/accordion/AccordionTrigger.vue')['default']
18
+ Alert: typeof import('./components/ui/alert/Alert.vue')['default']
19
+ AlertDescription: typeof import('./components/ui/alert/AlertDescription.vue')['default']
20
+ AlertDialog: typeof import('./components/ui/alert-dialog/AlertDialog.vue')['default']
21
+ AlertDialogAction: typeof import('./components/ui/alert-dialog/AlertDialogAction.vue')['default']
22
+ AlertDialogCancel: typeof import('./components/ui/alert-dialog/AlertDialogCancel.vue')['default']
23
+ AlertDialogContent: typeof import('./components/ui/alert-dialog/AlertDialogContent.vue')['default']
24
+ AlertDialogDescription: typeof import('./components/ui/alert-dialog/AlertDialogDescription.vue')['default']
25
+ AlertDialogFooter: typeof import('./components/ui/alert-dialog/AlertDialogFooter.vue')['default']
26
+ AlertDialogHeader: typeof import('./components/ui/alert-dialog/AlertDialogHeader.vue')['default']
27
+ AlertDialogTitle: typeof import('./components/ui/alert-dialog/AlertDialogTitle.vue')['default']
28
+ AlertDialogTrigger: typeof import('./components/ui/alert-dialog/AlertDialogTrigger.vue')['default']
29
+ AlertTitle: typeof import('./components/ui/alert/AlertTitle.vue')['default']
30
+ AppLogo: typeof import('./components/AppLogo.vue')['default']
31
+ AppNavbar: typeof import('./components/layout/AppNavbar.vue')['default']
32
+ AppSidebar: typeof import('./components/layout/AppSidebar.vue')['default']
33
+ AreaChart: typeof import('./components/ui/chart/AreaChart.vue')['default']
34
+ Avatar: typeof import('./components/ui/avatar/Avatar.vue')['default']
35
+ AvatarFallback: typeof import('./components/ui/avatar/AvatarFallback.vue')['default']
36
+ AvatarGroup: typeof import('./components/ui/avatar/AvatarGroup.vue')['default']
37
+ AvatarImage: typeof import('./components/ui/avatar/AvatarImage.vue')['default']
38
+ Badge: typeof import('./components/ui/badge/Badge.vue')['default']
39
+ BarChart: typeof import('./components/ui/chart/BarChart.vue')['default']
40
+ Breadcrumb: typeof import('./components/ui/breadcrumb/Breadcrumb.vue')['default']
41
+ BreadcrumbEllipsis: typeof import('./components/ui/breadcrumb/BreadcrumbEllipsis.vue')['default']
42
+ BreadcrumbItem: typeof import('./components/ui/breadcrumb/BreadcrumbItem.vue')['default']
43
+ BreadcrumbLink: typeof import('./components/ui/breadcrumb/BreadcrumbLink.vue')['default']
44
+ BreadcrumbList: typeof import('./components/ui/breadcrumb/BreadcrumbList.vue')['default']
45
+ BreadcrumbPage: typeof import('./components/ui/breadcrumb/BreadcrumbPage.vue')['default']
46
+ BreadcrumbSeparator: typeof import('./components/ui/breadcrumb/BreadcrumbSeparator.vue')['default']
47
+ Button: typeof import('./components/ui/button/Button.vue')['default']
48
+ Calendar: typeof import('./components/ui/calendar/Calendar.vue')['default']
49
+ Card: typeof import('./components/ui/card/Card.vue')['default']
50
+ CardAction: typeof import('./components/ui/card/CardAction.vue')['default']
51
+ CardContent: typeof import('./components/ui/card/CardContent.vue')['default']
52
+ CardDescription: typeof import('./components/ui/card/CardDescription.vue')['default']
53
+ CardFooter: typeof import('./components/ui/card/CardFooter.vue')['default']
54
+ CardHeader: typeof import('./components/ui/card/CardHeader.vue')['default']
55
+ CardTitle: typeof import('./components/ui/card/CardTitle.vue')['default']
56
+ Checkbox: typeof import('./components/ui/checkbox/Checkbox.vue')['default']
57
+ CodePreview: typeof import('./components/CodePreview.vue')['default']
58
+ Collapsible: typeof import('./components/ui/collapsible/Collapsible.vue')['default']
59
+ CollapsibleContent: typeof import('./components/ui/collapsible/CollapsibleContent.vue')['default']
60
+ CollapsibleTrigger: typeof import('./components/ui/collapsible/CollapsibleTrigger.vue')['default']
61
+ Command: typeof import('./components/ui/command/Command.vue')['default']
62
+ CommandDialog: typeof import('./components/ui/command/CommandDialog.vue')['default']
63
+ CommandEmpty: typeof import('./components/ui/command/CommandEmpty.vue')['default']
64
+ CommandGroup: typeof import('./components/ui/command/CommandGroup.vue')['default']
65
+ CommandInput: typeof import('./components/ui/command/CommandInput.vue')['default']
66
+ CommandItem: typeof import('./components/ui/command/CommandItem.vue')['default']
67
+ CommandList: typeof import('./components/ui/command/CommandList.vue')['default']
68
+ CommandSearchDialog: typeof import('./components/layout/CommandSearchDialog.vue')['default']
69
+ CommandSeparator: typeof import('./components/ui/command/CommandSeparator.vue')['default']
70
+ CommandShortcut: typeof import('./components/ui/command/CommandShortcut.vue')['default']
71
+ ContextMenu: typeof import('./components/ui/context-menu/ContextMenu.vue')['default']
72
+ ContextMenuCheckboxItem: typeof import('./components/ui/context-menu/ContextMenuCheckboxItem.vue')['default']
73
+ ContextMenuContent: typeof import('./components/ui/context-menu/ContextMenuContent.vue')['default']
74
+ ContextMenuGroup: typeof import('./components/ui/context-menu/ContextMenuGroup.vue')['default']
75
+ ContextMenuItem: typeof import('./components/ui/context-menu/ContextMenuItem.vue')['default']
76
+ ContextMenuLabel: typeof import('./components/ui/context-menu/ContextMenuLabel.vue')['default']
77
+ ContextMenuRadioGroup: typeof import('./components/ui/context-menu/ContextMenuRadioGroup.vue')['default']
78
+ ContextMenuRadioItem: typeof import('./components/ui/context-menu/ContextMenuRadioItem.vue')['default']
79
+ ContextMenuSeparator: typeof import('./components/ui/context-menu/ContextMenuSeparator.vue')['default']
80
+ ContextMenuShortcut: typeof import('./components/ui/context-menu/ContextMenuShortcut.vue')['default']
81
+ ContextMenuSub: typeof import('./components/ui/context-menu/ContextMenuSub.vue')['default']
82
+ ContextMenuSubContent: typeof import('./components/ui/context-menu/ContextMenuSubContent.vue')['default']
83
+ ContextMenuSubTrigger: typeof import('./components/ui/context-menu/ContextMenuSubTrigger.vue')['default']
84
+ ContextMenuTrigger: typeof import('./components/ui/context-menu/ContextMenuTrigger.vue')['default']
85
+ DatePicker: typeof import('./components/ui/date-picker/DatePicker.vue')['default']
86
+ Dialog: typeof import('./components/ui/dialog/Dialog.vue')['default']
87
+ DialogClose: typeof import('./components/ui/dialog/DialogClose.vue')['default']
88
+ DialogContent: typeof import('./components/ui/dialog/DialogContent.vue')['default']
89
+ DialogDescription: typeof import('./components/ui/dialog/DialogDescription.vue')['default']
90
+ DialogFooter: typeof import('./components/ui/dialog/DialogFooter.vue')['default']
91
+ DialogHeader: typeof import('./components/ui/dialog/DialogHeader.vue')['default']
92
+ DialogOverlay: typeof import('./components/ui/dialog/DialogOverlay.vue')['default']
93
+ DialogScrollContent: typeof import('./components/ui/dialog/DialogScrollContent.vue')['default']
94
+ DialogTitle: typeof import('./components/ui/dialog/DialogTitle.vue')['default']
95
+ DialogTrigger: typeof import('./components/ui/dialog/DialogTrigger.vue')['default']
96
+ DonutChart: typeof import('./components/ui/chart/DonutChart.vue')['default']
97
+ DropdownMenu: typeof import('./components/ui/dropdown-menu/DropdownMenu.vue')['default']
98
+ DropdownMenuCheckboxItem: typeof import('./components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue')['default']
99
+ DropdownMenuContent: typeof import('./components/ui/dropdown-menu/DropdownMenuContent.vue')['default']
100
+ DropdownMenuGroup: typeof import('./components/ui/dropdown-menu/DropdownMenuGroup.vue')['default']
101
+ DropdownMenuItem: typeof import('./components/ui/dropdown-menu/DropdownMenuItem.vue')['default']
102
+ DropdownMenuLabel: typeof import('./components/ui/dropdown-menu/DropdownMenuLabel.vue')['default']
103
+ DropdownMenuRadioGroup: typeof import('./components/ui/dropdown-menu/DropdownMenuRadioGroup.vue')['default']
104
+ DropdownMenuRadioItem: typeof import('./components/ui/dropdown-menu/DropdownMenuRadioItem.vue')['default']
105
+ DropdownMenuSeparator: typeof import('./components/ui/dropdown-menu/DropdownMenuSeparator.vue')['default']
106
+ DropdownMenuShortcut: typeof import('./components/ui/dropdown-menu/DropdownMenuShortcut.vue')['default']
107
+ DropdownMenuSub: typeof import('./components/ui/dropdown-menu/DropdownMenuSub.vue')['default']
108
+ DropdownMenuSubContent: typeof import('./components/ui/dropdown-menu/DropdownMenuSubContent.vue')['default']
109
+ DropdownMenuSubTrigger: typeof import('./components/ui/dropdown-menu/DropdownMenuSubTrigger.vue')['default']
110
+ DropdownMenuTrigger: typeof import('./components/ui/dropdown-menu/DropdownMenuTrigger.vue')['default']
111
+ EmptyState: typeof import('./components/EmptyState.vue')['default']
112
+ FormControl: typeof import('./components/ui/form/FormControl.vue')['default']
113
+ FormDescription: typeof import('./components/ui/form/FormDescription.vue')['default']
114
+ FormItem: typeof import('./components/ui/form/FormItem.vue')['default']
115
+ FormLabel: typeof import('./components/ui/form/FormLabel.vue')['default']
116
+ FormMessage: typeof import('./components/ui/form/FormMessage.vue')['default']
117
+ HoverCard: typeof import('./components/ui/hover-card/HoverCard.vue')['default']
118
+ HoverCardContent: typeof import('./components/ui/hover-card/HoverCardContent.vue')['default']
119
+ HoverCardTrigger: typeof import('./components/ui/hover-card/HoverCardTrigger.vue')['default']
120
+ Input: typeof import('./components/ui/input/Input.vue')['default']
121
+ InputAddon: typeof import('./components/ui/input/InputAddon.vue')['default']
122
+ InputGroup: typeof import('./components/ui/input/InputGroup.vue')['default']
123
+ InputIcon: typeof import('./components/ui/input/InputIcon.vue')['default']
124
+ Kbd: typeof import('./components/ui/kbd/Kbd.vue')['default']
125
+ Label: typeof import('./components/ui/label/Label.vue')['default']
126
+ LineChart: typeof import('./components/ui/chart/LineChart.vue')['default']
127
+ LoadingBar: typeof import('./components/ui/loading-bar/LoadingBar.vue')['default']
128
+ NotificationDrawer: typeof import('./components/layout/NotificationDrawer.vue')['default']
129
+ PageHeader: typeof import('./components/PageHeader.vue')['default']
130
+ Pagination: typeof import('./components/ui/pagination/Pagination.vue')['default']
131
+ PaginationContent: typeof import('./components/ui/pagination/PaginationContent.vue')['default']
132
+ PaginationEllipsis: typeof import('./components/ui/pagination/PaginationEllipsis.vue')['default']
133
+ PaginationFirst: typeof import('./components/ui/pagination/PaginationFirst.vue')['default']
134
+ PaginationItem: typeof import('./components/ui/pagination/PaginationItem.vue')['default']
135
+ PaginationLast: typeof import('./components/ui/pagination/PaginationLast.vue')['default']
136
+ PaginationNext: typeof import('./components/ui/pagination/PaginationNext.vue')['default']
137
+ PaginationPrevious: typeof import('./components/ui/pagination/PaginationPrevious.vue')['default']
138
+ PinInput: typeof import('./components/ui/pin-input/PinInput.vue')['default']
139
+ PinInputGroup: typeof import('./components/ui/pin-input/PinInputGroup.vue')['default']
140
+ PinInputInput: typeof import('./components/ui/pin-input/PinInputInput.vue')['default']
141
+ PinInputSeparator: typeof import('./components/ui/pin-input/PinInputSeparator.vue')['default']
142
+ Popover: typeof import('./components/ui/popover/Popover.vue')['default']
143
+ PopoverAnchor: typeof import('./components/ui/popover/PopoverAnchor.vue')['default']
144
+ PopoverContent: typeof import('./components/ui/popover/PopoverContent.vue')['default']
145
+ PopoverTrigger: typeof import('./components/ui/popover/PopoverTrigger.vue')['default']
146
+ Progress: typeof import('./components/ui/progress/Progress.vue')['default']
147
+ RadioGroup: typeof import('./components/ui/radio-group/RadioGroup.vue')['default']
148
+ RadioGroupItem: typeof import('./components/ui/radio-group/RadioGroupItem.vue')['default']
149
+ RouterLink: typeof import('vue-router')['RouterLink']
150
+ RouterView: typeof import('vue-router')['RouterView']
151
+ ScrollArea: typeof import('./components/ui/scroll-area/ScrollArea.vue')['default']
152
+ ScrollBar: typeof import('./components/ui/scroll-area/ScrollBar.vue')['default']
153
+ Select: typeof import('./components/ui/select/Select.vue')['default']
154
+ SelectContent: typeof import('./components/ui/select/SelectContent.vue')['default']
155
+ SelectGroup: typeof import('./components/ui/select/SelectGroup.vue')['default']
156
+ SelectItem: typeof import('./components/ui/select/SelectItem.vue')['default']
157
+ SelectItemText: typeof import('./components/ui/select/SelectItemText.vue')['default']
158
+ SelectLabel: typeof import('./components/ui/select/SelectLabel.vue')['default']
159
+ SelectScrollDownButton: typeof import('./components/ui/select/SelectScrollDownButton.vue')['default']
160
+ SelectScrollUpButton: typeof import('./components/ui/select/SelectScrollUpButton.vue')['default']
161
+ SelectSeparator: typeof import('./components/ui/select/SelectSeparator.vue')['default']
162
+ SelectTrigger: typeof import('./components/ui/select/SelectTrigger.vue')['default']
163
+ SelectValue: typeof import('./components/ui/select/SelectValue.vue')['default']
164
+ Separator: typeof import('./components/ui/separator/Separator.vue')['default']
165
+ Sheet: typeof import('./components/ui/sheet/Sheet.vue')['default']
166
+ SheetClose: typeof import('./components/ui/sheet/SheetClose.vue')['default']
167
+ SheetContent: typeof import('./components/ui/sheet/SheetContent.vue')['default']
168
+ SheetDescription: typeof import('./components/ui/sheet/SheetDescription.vue')['default']
169
+ SheetFooter: typeof import('./components/ui/sheet/SheetFooter.vue')['default']
170
+ SheetHeader: typeof import('./components/ui/sheet/SheetHeader.vue')['default']
171
+ SheetOverlay: typeof import('./components/ui/sheet/SheetOverlay.vue')['default']
172
+ SheetTitle: typeof import('./components/ui/sheet/SheetTitle.vue')['default']
173
+ SheetTrigger: typeof import('./components/ui/sheet/SheetTrigger.vue')['default']
174
+ Sidebar: typeof import('./components/ui/sidebar/Sidebar.vue')['default']
175
+ SidebarContent: typeof import('./components/ui/sidebar/SidebarContent.vue')['default']
176
+ SidebarControl: typeof import('./components/ui/sidebar/SidebarControl.vue')['default']
177
+ SidebarFooter: typeof import('./components/ui/sidebar/SidebarFooter.vue')['default']
178
+ SidebarGroup: typeof import('./components/ui/sidebar/SidebarGroup.vue')['default']
179
+ SidebarGroupAction: typeof import('./components/ui/sidebar/SidebarGroupAction.vue')['default']
180
+ SidebarGroupContent: typeof import('./components/ui/sidebar/SidebarGroupContent.vue')['default']
181
+ SidebarGroupLabel: typeof import('./components/ui/sidebar/SidebarGroupLabel.vue')['default']
182
+ SidebarHeader: typeof import('./components/ui/sidebar/SidebarHeader.vue')['default']
183
+ SidebarInput: typeof import('./components/ui/sidebar/SidebarInput.vue')['default']
184
+ SidebarInset: typeof import('./components/ui/sidebar/SidebarInset.vue')['default']
185
+ SidebarMenu: typeof import('./components/ui/sidebar/SidebarMenu.vue')['default']
186
+ SidebarMenuAction: typeof import('./components/ui/sidebar/SidebarMenuAction.vue')['default']
187
+ SidebarMenuBadge: typeof import('./components/ui/sidebar/SidebarMenuBadge.vue')['default']
188
+ SidebarMenuButton: typeof import('./components/ui/sidebar/SidebarMenuButton.vue')['default']
189
+ SidebarMenuButtonChild: typeof import('./components/ui/sidebar/SidebarMenuButtonChild.vue')['default']
190
+ SidebarMenuItem: typeof import('./components/ui/sidebar/SidebarMenuItem.vue')['default']
191
+ SidebarMenuSkeleton: typeof import('./components/ui/sidebar/SidebarMenuSkeleton.vue')['default']
192
+ SidebarMenuSub: typeof import('./components/ui/sidebar/SidebarMenuSub.vue')['default']
193
+ SidebarMenuSubButton: typeof import('./components/ui/sidebar/SidebarMenuSubButton.vue')['default']
194
+ SidebarMenuSubItem: typeof import('./components/ui/sidebar/SidebarMenuSubItem.vue')['default']
195
+ SidebarProvider: typeof import('./components/ui/sidebar/SidebarProvider.vue')['default']
196
+ SidebarRail: typeof import('./components/ui/sidebar/SidebarRail.vue')['default']
197
+ SidebarSeparator: typeof import('./components/ui/sidebar/SidebarSeparator.vue')['default']
198
+ SidebarTrigger: typeof import('./components/ui/sidebar/SidebarTrigger.vue')['default']
199
+ Skeleton: typeof import('./components/ui/skeleton/Skeleton.vue')['default']
200
+ Slider: typeof import('./components/ui/slider/Slider.vue')['default']
201
+ Sonner: typeof import('./components/ui/sonner/Sonner.vue')['default']
202
+ Stepper: typeof import('./components/ui/stepper/Stepper.vue')['default']
203
+ Switch: typeof import('./components/ui/switch/Switch.vue')['default']
204
+ Table: typeof import('./components/ui/table/Table.vue')['default']
205
+ TableBody: typeof import('./components/ui/table/TableBody.vue')['default']
206
+ TableCaption: typeof import('./components/ui/table/TableCaption.vue')['default']
207
+ TableCell: typeof import('./components/ui/table/TableCell.vue')['default']
208
+ TableEmpty: typeof import('./components/ui/table/TableEmpty.vue')['default']
209
+ TableFooter: typeof import('./components/ui/table/TableFooter.vue')['default']
210
+ TableHead: typeof import('./components/ui/table/TableHead.vue')['default']
211
+ TableHeader: typeof import('./components/ui/table/TableHeader.vue')['default']
212
+ TableRow: typeof import('./components/ui/table/TableRow.vue')['default']
213
+ Tabs: typeof import('./components/ui/tabs/Tabs.vue')['default']
214
+ TabsContent: typeof import('./components/ui/tabs/TabsContent.vue')['default']
215
+ TabsList: typeof import('./components/ui/tabs/TabsList.vue')['default']
216
+ TabsTrigger: typeof import('./components/ui/tabs/TabsTrigger.vue')['default']
217
+ Textarea: typeof import('./components/ui/textarea/Textarea.vue')['default']
218
+ ThemeCustomizer: typeof import('./components/layout/ThemeCustomizer.vue')['default']
219
+ Timeline: typeof import('./components/ui/timeline/Timeline.vue')['default']
220
+ Toggle: typeof import('./components/ui/toggle/Toggle.vue')['default']
221
+ ToggleGroup: typeof import('./components/ui/toggle-group/ToggleGroup.vue')['default']
222
+ ToggleGroupItem: typeof import('./components/ui/toggle-group/ToggleGroupItem.vue')['default']
223
+ Tooltip: typeof import('./components/ui/tooltip/Tooltip.vue')['default']
224
+ TooltipContent: typeof import('./components/ui/tooltip/TooltipContent.vue')['default']
225
+ TooltipProvider: typeof import('./components/ui/tooltip/TooltipProvider.vue')['default']
226
+ TooltipTrigger: typeof import('./components/ui/tooltip/TooltipTrigger.vue')['default']
227
+ }
228
+ }
@@ -0,0 +1,105 @@
1
+ import {
2
+ formatCurrency,
3
+ formatNumber,
4
+ formatCompactNumber,
5
+ formatDate,
6
+ formatDateTime,
7
+ formatTime,
8
+ formatDateTimeWithTz,
9
+ formatRelativeTime,
10
+ formatBytes,
11
+ getInitials,
12
+ truncate,
13
+ type CurrencyFormatOptions,
14
+ type DateTimeFormatOptions,
15
+ type TimeOnlyFormatOptions,
16
+ type TimeFormat,
17
+ } from '@/lib/formatters'
18
+
19
+ /**
20
+ * Composable that exposes all data formatting utilities under a single object.
21
+ *
22
+ * Auto-imported via unplugin-auto-import — no explicit import needed in <script setup>.
23
+ *
24
+ * @example
25
+ * // In any <script setup> — no import required
26
+ * const fmt = useFormatter()
27
+ *
28
+ * fmt.currency(price) // uses VITE_DEFAULT_CURRENCY / VITE_DEFAULT_LOCALE
29
+ * fmt.currency(price, { currency: 'EUR', locale: 'de-DE' }) // per-call override
30
+ * fmt.date(row.createdAt) // "Aug 21, 2026"
31
+ * fmt.date(row.createdAt, 'short') // "8/21/26"
32
+ * fmt.relative(row.lastActive) // "5 minutes ago"
33
+ * fmt.compact(revenue) // "2.4M"
34
+ * fmt.bytes(file.size) // "4.5 MB"
35
+ * fmt.initials(user.name) // "OM"
36
+ * fmt.truncate(description, 60) // "This is a long des..."
37
+ */
38
+ export function useFormatter() {
39
+ return {
40
+ /** Format value as localized currency. Defaults to VITE_DEFAULT_CURRENCY / VITE_DEFAULT_LOCALE */
41
+ currency: (value: number | string | null | undefined, opts?: CurrencyFormatOptions) =>
42
+ formatCurrency(value, opts),
43
+
44
+ /** Format number with thousand separators */
45
+ number: (value: number | string | null | undefined, locale?: string) =>
46
+ formatNumber(value, locale),
47
+
48
+ /** Format large numbers in compact notation (1.5K, 2.4M, 1.2B) */
49
+ compact: (value: number | string | null | undefined, locale?: string) =>
50
+ formatCompactNumber(value, locale),
51
+
52
+ /** Format date-only: 'short' | 'medium' | 'long' | 'full' */
53
+ date: (
54
+ date: string | number | Date | null | undefined,
55
+ style: 'short' | 'medium' | 'long' | 'full' = 'medium',
56
+ locale?: string,
57
+ ) => formatDate(date, style, locale),
58
+
59
+ /** Format date + time together with 24h / 12h clock and timezone support */
60
+ dateTime: (
61
+ date: string | number | Date | null | undefined,
62
+ options?: DateTimeFormatOptions | string,
63
+ ) => formatDateTime(date, options),
64
+
65
+ /**
66
+ * Format time only (e.g. "14:30" or "02:30 PM") with 24h / 12h clock support
67
+ * @example fmt.time(order.createdAt) => "14:30" (default 24h)
68
+ * @example fmt.time(order.createdAt, { format: '12h' }) => "02:30 PM"
69
+ * @example fmt.time(order.createdAt, { showSeconds: true }) => "14:30:00"
70
+ */
71
+ time: (
72
+ date: string | number | Date | null | undefined,
73
+ options?: TimeOnlyFormatOptions,
74
+ ) => formatTime(date, options),
75
+
76
+ /** Format as relative time: "5 minutes ago", "yesterday", "in 3 days" */
77
+ relative: (date: string | number | Date | null | undefined, locale?: string) =>
78
+ formatRelativeTime(date, locale),
79
+
80
+ /** Format byte sizes into human-readable units (KB, MB, GB) with locale-aware decimal separator */
81
+ bytes: (bytes: number | null | undefined, decimals?: number, locale?: string) =>
82
+ formatBytes(bytes, decimals, locale),
83
+
84
+ /**
85
+ * Format date + time with explicit timezone and clock format
86
+ * @param timeZone IANA tz: 'Asia/Jakarta' (WIB) | 'Asia/Makassar' (WITA) | 'Asia/Jayapura' (WIT)
87
+ * @param format '24h' | '12h' | 'auto' (defaults to .env: '24h')
88
+ * @example fmt.dateTimeWithTz(date, 'Asia/Jakarta', '24h') => "21 Agt 2026, 14.30"
89
+ */
90
+ dateTimeWithTz: (
91
+ date: string | number | Date | null | undefined,
92
+ timeZone?: string,
93
+ format?: TimeFormat,
94
+ locale?: string,
95
+ ) => formatDateTimeWithTz(date, timeZone, format, locale),
96
+
97
+ /** Extract 2-letter initials from a full name ("Olivia Martin" → "OM") */
98
+ initials: (name: string | null | undefined) =>
99
+ getInitials(name),
100
+
101
+ /** Truncate long strings with ellipsis */
102
+ truncate: (text: string | null | undefined, length?: number) =>
103
+ truncate(text, length),
104
+ }
105
+ }
@@ -0,0 +1,252 @@
1
+ import { ref, watch } from 'vue'
2
+ import { useStorage } from '@vueuse/core'
3
+
4
+ export type PrimaryColorKey = 'emerald' | 'indigo' | 'violet' | 'rose' | 'amber' | 'cyan' | 'zinc'
5
+ export type RadiusKey = '0' | '0.25' | '0.375' | '0.5' | '0.75' | '1.0'
6
+ export type ContentWidthKey = 'fluid' | 'boxed'
7
+
8
+ export interface PrimaryColorDefinition {
9
+ name: string
10
+ key: PrimaryColorKey
11
+ hex: string
12
+ light: {
13
+ primary: string
14
+ ring: string
15
+ primaryForeground: string
16
+ }
17
+ dark: {
18
+ primary: string
19
+ ring: string
20
+ primaryForeground: string
21
+ }
22
+ }
23
+
24
+ export interface RadiusDefinition {
25
+ label: string
26
+ value: RadiusKey
27
+ rem: string
28
+ }
29
+
30
+ export const PRIMARY_COLORS: PrimaryColorDefinition[] = [
31
+ {
32
+ name: 'Emerald',
33
+ key: 'emerald',
34
+ hex: '#10b981',
35
+ light: {
36
+ primary: 'oklch(0.55 0.145 163.2)',
37
+ ring: 'oklch(0.55 0.145 163.2 / 35%)',
38
+ primaryForeground: 'oklch(0.99 0 0)',
39
+ },
40
+ dark: {
41
+ primary: 'oklch(0.48 0.125 163.2)',
42
+ ring: 'oklch(0.48 0.125 163.2 / 35%)',
43
+ primaryForeground: 'oklch(0.99 0 0)',
44
+ },
45
+ },
46
+ {
47
+ name: 'Indigo',
48
+ key: 'indigo',
49
+ hex: '#6366f1',
50
+ light: {
51
+ primary: 'oklch(0.51 0.23 277)',
52
+ ring: 'oklch(0.51 0.23 277 / 35%)',
53
+ primaryForeground: 'oklch(0.99 0 0)',
54
+ },
55
+ dark: {
56
+ primary: 'oklch(0.59 0.21 277)',
57
+ ring: 'oklch(0.59 0.21 277 / 35%)',
58
+ primaryForeground: 'oklch(0.99 0 0)',
59
+ },
60
+ },
61
+ {
62
+ name: 'Violet',
63
+ key: 'violet',
64
+ hex: '#8b5cf6',
65
+ light: {
66
+ primary: 'oklch(0.54 0.24 293)',
67
+ ring: 'oklch(0.54 0.24 293 / 35%)',
68
+ primaryForeground: 'oklch(0.99 0 0)',
69
+ },
70
+ dark: {
71
+ primary: 'oklch(0.61 0.22 293)',
72
+ ring: 'oklch(0.61 0.22 293 / 35%)',
73
+ primaryForeground: 'oklch(0.99 0 0)',
74
+ },
75
+ },
76
+ {
77
+ name: 'Rose',
78
+ key: 'rose',
79
+ hex: '#f43f5e',
80
+ light: {
81
+ primary: 'oklch(0.59 0.22 17)',
82
+ ring: 'oklch(0.59 0.22 17 / 35%)',
83
+ primaryForeground: 'oklch(0.99 0 0)',
84
+ },
85
+ dark: {
86
+ primary: 'oklch(0.64 0.20 17)',
87
+ ring: 'oklch(0.64 0.20 17 / 35%)',
88
+ primaryForeground: 'oklch(0.99 0 0)',
89
+ },
90
+ },
91
+ {
92
+ name: 'Amber',
93
+ key: 'amber',
94
+ hex: '#f59e0b',
95
+ light: {
96
+ primary: 'oklch(0.68 0.19 65)',
97
+ ring: 'oklch(0.68 0.19 65 / 35%)',
98
+ primaryForeground: 'oklch(0.15 0 0)',
99
+ },
100
+ dark: {
101
+ primary: 'oklch(0.74 0.17 65)',
102
+ ring: 'oklch(0.74 0.17 65 / 35%)',
103
+ primaryForeground: 'oklch(0.15 0 0)',
104
+ },
105
+ },
106
+ {
107
+ name: 'Cyan',
108
+ key: 'cyan',
109
+ hex: '#06b6d4',
110
+ light: {
111
+ primary: 'oklch(0.62 0.15 215)',
112
+ ring: 'oklch(0.62 0.15 215 / 35%)',
113
+ primaryForeground: 'oklch(0.99 0 0)',
114
+ },
115
+ dark: {
116
+ primary: 'oklch(0.68 0.14 215)',
117
+ ring: 'oklch(0.68 0.14 215 / 35%)',
118
+ primaryForeground: 'oklch(0.15 0 0)',
119
+ },
120
+ },
121
+ {
122
+ name: 'Zinc',
123
+ key: 'zinc',
124
+ hex: '#71717a',
125
+ light: {
126
+ primary: 'oklch(0.205 0 0)',
127
+ ring: 'oklch(0.205 0 0 / 35%)',
128
+ primaryForeground: 'oklch(0.985 0 0)',
129
+ },
130
+ dark: {
131
+ primary: 'oklch(0.985 0 0)',
132
+ ring: 'oklch(0.985 0 0 / 35%)',
133
+ primaryForeground: 'oklch(0.145 0 0)',
134
+ },
135
+ },
136
+ ]
137
+
138
+ export const RADIUS_PRESETS: RadiusDefinition[] = [
139
+ { label: '0', value: '0', rem: '0rem' },
140
+ { label: '0.25', value: '0.25', rem: '0.25rem' },
141
+ { label: '0.375', value: '0.375', rem: '0.375rem' },
142
+ { label: '0.5', value: '0.5', rem: '0.5rem' },
143
+ { label: '0.75', value: '0.75', rem: '0.75rem' },
144
+ { label: '1.0', value: '1.0', rem: '1rem' },
145
+ ]
146
+
147
+ export interface ThemeConfig {
148
+ primaryColor: PrimaryColorKey
149
+ radius: RadiusKey
150
+ contentWidth: ContentWidthKey
151
+ }
152
+
153
+ const DEFAULT_CONFIG: ThemeConfig = {
154
+ primaryColor: 'emerald',
155
+ radius: '0.375',
156
+ contentWidth: 'fluid',
157
+ }
158
+
159
+ const isCustomizerOpen = ref(false)
160
+ const themeConfig = useStorage<ThemeConfig>('nala-theme-config', { ...DEFAULT_CONFIG })
161
+
162
+ // Style element injection helper for reliable CSS variable overrides in both light and dark mode
163
+ let customThemeStyleElement: HTMLStyleElement | null = null
164
+
165
+ function ensureThemeStyleElement(): HTMLStyleElement {
166
+ if (!customThemeStyleElement && typeof document !== 'undefined') {
167
+ customThemeStyleElement = document.getElementById('nala-dynamic-theme-vars') as HTMLStyleElement
168
+ if (!customThemeStyleElement) {
169
+ customThemeStyleElement = document.createElement('style')
170
+ customThemeStyleElement.id = 'nala-dynamic-theme-vars'
171
+ document.head.appendChild(customThemeStyleElement)
172
+ }
173
+ }
174
+ return customThemeStyleElement!
175
+ }
176
+
177
+ export function useThemeConfig() {
178
+ const applyTheme = () => {
179
+ if (typeof document === 'undefined') return
180
+
181
+ const colorDef = PRIMARY_COLORS.find(c => c.key === themeConfig.value.primaryColor) || PRIMARY_COLORS[0]
182
+ const radiusDef = RADIUS_PRESETS.find(r => r.value === themeConfig.value.radius) || RADIUS_PRESETS[2]
183
+
184
+ const styleEl = ensureThemeStyleElement()
185
+ if (styleEl) {
186
+ styleEl.innerHTML = `
187
+ :root {
188
+ --radius: ${radiusDef.rem};
189
+ --primary: ${colorDef.light.primary};
190
+ --ring: ${colorDef.light.ring};
191
+ --primary-foreground: ${colorDef.light.primaryForeground};
192
+ }
193
+ .dark {
194
+ --primary: ${colorDef.dark.primary};
195
+ --ring: ${colorDef.dark.ring};
196
+ --primary-foreground: ${colorDef.dark.primaryForeground};
197
+ }
198
+ `
199
+ }
200
+
201
+ // Set dataset attribute for inspection
202
+ document.documentElement.dataset.themeColor = colorDef.key
203
+ document.documentElement.dataset.themeRadius = radiusDef.value
204
+ document.documentElement.dataset.contentWidth = themeConfig.value.contentWidth
205
+ }
206
+
207
+ const setPrimaryColor = (color: PrimaryColorKey) => {
208
+ themeConfig.value.primaryColor = color
209
+ }
210
+
211
+ const setRadius = (radius: RadiusKey) => {
212
+ themeConfig.value.radius = radius
213
+ }
214
+
215
+ const setContentWidth = (width: ContentWidthKey) => {
216
+ themeConfig.value.contentWidth = width
217
+ }
218
+
219
+ const resetThemeConfig = () => {
220
+ themeConfig.value = { ...DEFAULT_CONFIG }
221
+ }
222
+
223
+ const toggleCustomizer = (open?: boolean) => {
224
+ if (typeof open === 'boolean') {
225
+ isCustomizerOpen.value = open
226
+ } else {
227
+ isCustomizerOpen.value = !isCustomizerOpen.value
228
+ }
229
+ }
230
+
231
+ // Watch for changes and apply immediately
232
+ watch(
233
+ () => [themeConfig.value.primaryColor, themeConfig.value.radius, themeConfig.value.contentWidth],
234
+ () => {
235
+ applyTheme()
236
+ },
237
+ { immediate: true },
238
+ )
239
+
240
+ return {
241
+ themeConfig,
242
+ isCustomizerOpen,
243
+ primaryColors: PRIMARY_COLORS,
244
+ radiusPresets: RADIUS_PRESETS,
245
+ setPrimaryColor,
246
+ setRadius,
247
+ setContentWidth,
248
+ resetThemeConfig,
249
+ toggleCustomizer,
250
+ applyTheme,
251
+ }
252
+ }
@@ -0,0 +1,55 @@
1
+ <script setup lang="ts">
2
+ import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar'
3
+ import AppNavbar from '@/components/layout/AppNavbar.vue'
4
+ import AppSidebar from '@/components/layout/AppSidebar.vue'
5
+ import CommandSearchDialog from '@/components/layout/CommandSearchDialog.vue'
6
+ import { useThemeConfig } from '@/composables/useThemeConfig'
7
+
8
+ const isSearchOpen = ref(false)
9
+ const { themeConfig } = useThemeConfig()
10
+
11
+ // Global keyboard shortcut: Ctrl+K or Cmd+K
12
+ const handleKeyDown = (e: KeyboardEvent) => {
13
+ if ((e.ctrlKey || e.metaKey) && (e.key === 'k' || e.key === 'K')) {
14
+ e.preventDefault()
15
+ isSearchOpen.value = !isSearchOpen.value
16
+ }
17
+ }
18
+
19
+ onMounted(() => {
20
+ window.addEventListener('keydown', handleKeyDown)
21
+ })
22
+
23
+ onUnmounted(() => {
24
+ window.removeEventListener('keydown', handleKeyDown)
25
+ })
26
+ </script>
27
+
28
+ <template>
29
+ <SidebarProvider class="h-dvh max-h-dvh min-h-0 w-full overflow-hidden flex flex-col pt-14">
30
+ <!-- Top Navigation Header (Fixed at top) -->
31
+ <AppNavbar @open-search="isSearchOpen = true" />
32
+
33
+ <!-- Main Container below Navbar -->
34
+ <div class="flex flex-1 min-h-0 min-w-0 w-full relative overflow-hidden">
35
+ <!-- Left Sidebar Navigation -->
36
+ <AppSidebar />
37
+
38
+ <!-- Main Scrollable Inset Page View -->
39
+ <SidebarInset class="flex flex-col min-h-0 min-w-0 max-w-full overflow-hidden flex-1">
40
+ <main class="flex-1 min-h-0 overflow-y-auto overflow-x-hidden p-4 sm:p-6 bg-background">
41
+ <div :class="themeConfig.contentWidth === 'boxed' ? 'max-w-7xl mx-auto w-full transition-all duration-300' : 'w-full transition-all duration-300'">
42
+ <RouterView v-slot="{ Component }">
43
+ <Transition name="page" mode="out-in">
44
+ <component :is="Component" />
45
+ </Transition>
46
+ </RouterView>
47
+ </div>
48
+ </main>
49
+ </SidebarInset>
50
+ </div>
51
+
52
+ <!-- Quick Search Dialog Modal (Ctrl+K) -->
53
+ <CommandSearchDialog v-model:open="isSearchOpen" />
54
+ </SidebarProvider>
55
+ </template>