@vestow/vue 0.1.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 (491) hide show
  1. package/README.md +233 -0
  2. package/index.ts +8 -0
  3. package/package.json +68 -0
  4. package/src/components/accordion/Accordion.vue +45 -0
  5. package/src/components/accordion/AccordionContent.vue +31 -0
  6. package/src/components/accordion/AccordionItem.vue +26 -0
  7. package/src/components/accordion/AccordionTrigger.vue +39 -0
  8. package/src/components/accordion/index.ts +18 -0
  9. package/src/components/alert/Alert.vue +17 -0
  10. package/src/components/alert/AlertDescription.vue +12 -0
  11. package/src/components/alert/AlertTitle.vue +12 -0
  12. package/src/components/alert/index.ts +5 -0
  13. package/src/components/avatar/Avatar.vue +32 -0
  14. package/src/components/avatar/AvatarFallback.vue +23 -0
  15. package/src/components/avatar/AvatarImage.vue +18 -0
  16. package/src/components/avatar/index.ts +3 -0
  17. package/src/components/badge/Badge.vue +25 -0
  18. package/src/components/badge/index.ts +3 -0
  19. package/src/components/breadcrumb/Breadcrumb.vue +14 -0
  20. package/src/components/breadcrumb/BreadcrumbItem.vue +12 -0
  21. package/src/components/breadcrumb/BreadcrumbLink.vue +19 -0
  22. package/src/components/breadcrumb/BreadcrumbPage.vue +12 -0
  23. package/src/components/breadcrumb/BreadcrumbSeparator.vue +15 -0
  24. package/src/components/breadcrumb/index.ts +5 -0
  25. package/src/components/button/Button.vue +55 -0
  26. package/src/components/button/index.ts +3 -0
  27. package/src/components/button-group/ButtonGroup.vue +29 -0
  28. package/src/components/button-group/ButtonGroupSeparator.vue +30 -0
  29. package/src/components/button-group/ButtonGroupText.vue +29 -0
  30. package/src/components/button-group/SplitButton.vue +103 -0
  31. package/src/components/button-group/SplitButtonItems.vue +50 -0
  32. package/src/components/button-group/index.ts +34 -0
  33. package/src/components/calendar/Calendar.vue +120 -0
  34. package/src/components/calendar/RangeCalendar.vue +127 -0
  35. package/src/components/calendar/index.ts +2 -0
  36. package/src/components/card/Card.vue +12 -0
  37. package/src/components/card/CardAction.vue +12 -0
  38. package/src/components/card/CardContent.vue +12 -0
  39. package/src/components/card/CardDescription.vue +12 -0
  40. package/src/components/card/CardFooter.vue +12 -0
  41. package/src/components/card/CardHeader.vue +15 -0
  42. package/src/components/card/CardTitle.vue +12 -0
  43. package/src/components/card/index.ts +7 -0
  44. package/src/components/carousel/Carousel.vue +164 -0
  45. package/src/components/carousel/CarouselContent.vue +43 -0
  46. package/src/components/carousel/CarouselDots.vue +42 -0
  47. package/src/components/carousel/CarouselItem.vue +58 -0
  48. package/src/components/carousel/CarouselNext.vue +45 -0
  49. package/src/components/carousel/CarouselPrevious.vue +45 -0
  50. package/src/components/carousel/index.ts +44 -0
  51. package/src/components/cascade-select/CascadeSelect.vue +314 -0
  52. package/src/components/cascade-select/index.ts +11 -0
  53. package/src/components/chart/AreaChart.vue +201 -0
  54. package/src/components/chart/BarChart.vue +389 -0
  55. package/src/components/chart/ChartContainer.vue +127 -0
  56. package/src/components/chart/ChartCrosshair.vue +92 -0
  57. package/src/components/chart/ChartLegend.vue +63 -0
  58. package/src/components/chart/ChartTooltipCard.vue +49 -0
  59. package/src/components/chart/LineChart.vue +214 -0
  60. package/src/components/chart/PieChart.vue +280 -0
  61. package/src/components/chart/RadarChart.vue +291 -0
  62. package/src/components/chart/RadialChart.vue +354 -0
  63. package/src/components/chart/index.ts +30 -0
  64. package/src/components/chart/polar.ts +5 -0
  65. package/src/components/chart/tooltip.ts +5 -0
  66. package/src/components/chart/types.ts +52 -0
  67. package/src/components/chart/useChartSeries.ts +138 -0
  68. package/src/components/chart/xy-label.ts +5 -0
  69. package/src/components/checkbox/Checkbox.vue +81 -0
  70. package/src/components/checkbox/CheckboxField.vue +129 -0
  71. package/src/components/checkbox/CheckboxGroup.vue +62 -0
  72. package/src/components/checkbox/index.ts +21 -0
  73. package/src/components/chip/Chip.vue +73 -0
  74. package/src/components/chip/index.ts +3 -0
  75. package/src/components/code-block/CodeBlock.vue +100 -0
  76. package/src/components/code-block/index.ts +4 -0
  77. package/src/components/collapsible/Collapsible.vue +15 -0
  78. package/src/components/collapsible/CollapsibleContent.vue +26 -0
  79. package/src/components/collapsible/CollapsibleTrigger.vue +12 -0
  80. package/src/components/collapsible/index.ts +3 -0
  81. package/src/components/combobox/Combobox.vue +23 -0
  82. package/src/components/combobox/ComboboxAnchor.vue +20 -0
  83. package/src/components/combobox/ComboboxEmpty.vue +21 -0
  84. package/src/components/combobox/ComboboxGroup.vue +23 -0
  85. package/src/components/combobox/ComboboxInput.vue +32 -0
  86. package/src/components/combobox/ComboboxItem.vue +38 -0
  87. package/src/components/combobox/ComboboxList.vue +43 -0
  88. package/src/components/combobox/ComboboxSeparator.vue +18 -0
  89. package/src/components/combobox/ComboboxTrigger.vue +12 -0
  90. package/src/components/combobox/index.ts +9 -0
  91. package/src/components/command/Command.vue +54 -0
  92. package/src/components/command/CommandDialog.vue +41 -0
  93. package/src/components/command/CommandEmpty.vue +19 -0
  94. package/src/components/command/CommandGroup.vue +28 -0
  95. package/src/components/command/CommandInput.vue +25 -0
  96. package/src/components/command/CommandItem.vue +40 -0
  97. package/src/components/command/CommandList.vue +13 -0
  98. package/src/components/command/CommandSeparator.vue +11 -0
  99. package/src/components/command/CommandShortcut.vue +13 -0
  100. package/src/components/command/index.ts +34 -0
  101. package/src/components/command-block/CommandBlock.vue +90 -0
  102. package/src/components/command-block/index.ts +2 -0
  103. package/src/components/confirm-dialog/ConfirmDialog.vue +37 -0
  104. package/src/components/confirm-dialog/index.ts +1 -0
  105. package/src/components/confirm-popup/ConfirmPopup.vue +123 -0
  106. package/src/components/confirm-popup/index.ts +1 -0
  107. package/src/components/context-menu/ContextMenu.vue +15 -0
  108. package/src/components/context-menu/ContextMenuCheckboxItem.vue +30 -0
  109. package/src/components/context-menu/ContextMenuContent.vue +36 -0
  110. package/src/components/context-menu/ContextMenuGroup.vue +12 -0
  111. package/src/components/context-menu/ContextMenuItem.vue +32 -0
  112. package/src/components/context-menu/ContextMenuLabel.vue +21 -0
  113. package/src/components/context-menu/ContextMenuRadioGroup.vue +15 -0
  114. package/src/components/context-menu/ContextMenuRadioItem.vue +30 -0
  115. package/src/components/context-menu/ContextMenuSeparator.vue +19 -0
  116. package/src/components/context-menu/ContextMenuShortcut.vue +13 -0
  117. package/src/components/context-menu/ContextMenuSub.vue +15 -0
  118. package/src/components/context-menu/ContextMenuSubContent.vue +26 -0
  119. package/src/components/context-menu/ContextMenuSubTrigger.vue +26 -0
  120. package/src/components/context-menu/ContextMenuTrigger.vue +12 -0
  121. package/src/components/context-menu/index.ts +14 -0
  122. package/src/components/data-table/DataTable.vue +458 -0
  123. package/src/components/data-table/DataTableFacetedFilter.vue +97 -0
  124. package/src/components/data-table/DataTablePagination.vue +103 -0
  125. package/src/components/data-table/DataTableViewOptions.vue +69 -0
  126. package/src/components/data-table/features.ts +87 -0
  127. package/src/components/data-table/index.ts +27 -0
  128. package/src/components/data-table/pagination-adapter.ts +67 -0
  129. package/src/components/data-table/selection-column.ts +48 -0
  130. package/src/components/data-table/types.ts +36 -0
  131. package/src/components/data-view/DataView.vue +136 -0
  132. package/src/components/data-view/index.ts +1 -0
  133. package/src/components/date-picker/DatePicker.vue +117 -0
  134. package/src/components/date-picker/DateRangePicker.vue +122 -0
  135. package/src/components/date-picker/index.ts +2 -0
  136. package/src/components/deferred/Deferred.vue +80 -0
  137. package/src/components/deferred/index.ts +1 -0
  138. package/src/components/dialog/Dialog.vue +15 -0
  139. package/src/components/dialog/DialogClose.vue +12 -0
  140. package/src/components/dialog/DialogContent.vue +46 -0
  141. package/src/components/dialog/DialogDescription.vue +19 -0
  142. package/src/components/dialog/DialogFooter.vue +12 -0
  143. package/src/components/dialog/DialogHeader.vue +12 -0
  144. package/src/components/dialog/DialogTitle.vue +19 -0
  145. package/src/components/dialog/DialogTrigger.vue +12 -0
  146. package/src/components/dialog/index.ts +10 -0
  147. package/src/components/doc-example/DocExample.vue +41 -0
  148. package/src/components/doc-example/index.ts +1 -0
  149. package/src/components/doc-text/DocText.vue +64 -0
  150. package/src/components/doc-text/index.ts +1 -0
  151. package/src/components/dropdown-menu/DropdownMenu.vue +15 -0
  152. package/src/components/dropdown-menu/DropdownMenuCheckboxItem.vue +33 -0
  153. package/src/components/dropdown-menu/DropdownMenuContent.vue +36 -0
  154. package/src/components/dropdown-menu/DropdownMenuGroup.vue +12 -0
  155. package/src/components/dropdown-menu/DropdownMenuItem.vue +32 -0
  156. package/src/components/dropdown-menu/DropdownMenuLabel.vue +24 -0
  157. package/src/components/dropdown-menu/DropdownMenuRadioGroup.vue +15 -0
  158. package/src/components/dropdown-menu/DropdownMenuRadioItem.vue +33 -0
  159. package/src/components/dropdown-menu/DropdownMenuSeparator.vue +19 -0
  160. package/src/components/dropdown-menu/DropdownMenuShortcut.vue +13 -0
  161. package/src/components/dropdown-menu/DropdownMenuSub.vue +15 -0
  162. package/src/components/dropdown-menu/DropdownMenuSubContent.vue +29 -0
  163. package/src/components/dropdown-menu/DropdownMenuSubTrigger.vue +26 -0
  164. package/src/components/dropdown-menu/DropdownMenuTrigger.vue +12 -0
  165. package/src/components/dropdown-menu/index.ts +14 -0
  166. package/src/components/editable/Editable.vue +41 -0
  167. package/src/components/editable/EditableArea.vue +22 -0
  168. package/src/components/editable/EditableCancelTrigger.vue +40 -0
  169. package/src/components/editable/EditableEditTrigger.vue +40 -0
  170. package/src/components/editable/EditableInput.vue +28 -0
  171. package/src/components/editable/EditablePreview.vue +34 -0
  172. package/src/components/editable/EditableSubmitTrigger.vue +40 -0
  173. package/src/components/editable/index.ts +17 -0
  174. package/src/components/empty/Empty.vue +17 -0
  175. package/src/components/empty/EmptyActions.vue +14 -0
  176. package/src/components/empty/EmptyDescription.vue +12 -0
  177. package/src/components/empty/EmptyMedia.vue +16 -0
  178. package/src/components/empty/EmptyTitle.vue +17 -0
  179. package/src/components/empty/index.ts +7 -0
  180. package/src/components/field/Field.vue +22 -0
  181. package/src/components/field/FieldDescription.vue +20 -0
  182. package/src/components/field/FieldGroup.vue +22 -0
  183. package/src/components/field/FieldLabel.vue +27 -0
  184. package/src/components/field/FieldSeparator.vue +28 -0
  185. package/src/components/field/index.ts +7 -0
  186. package/src/components/fieldset/Fieldset.vue +126 -0
  187. package/src/components/fieldset/index.ts +1 -0
  188. package/src/components/file-upload/FileUpload.vue +149 -0
  189. package/src/components/file-upload/index.ts +8 -0
  190. package/src/components/float-label/FloatLabel.vue +26 -0
  191. package/src/components/float-label/index.ts +3 -0
  192. package/src/components/form/Form.vue +126 -0
  193. package/src/components/form/FormDescription.vue +12 -0
  194. package/src/components/form/FormField.vue +127 -0
  195. package/src/components/form/FormItem.vue +12 -0
  196. package/src/components/form/FormLabel.vue +14 -0
  197. package/src/components/form/FormMessage.vue +31 -0
  198. package/src/components/form/context.ts +54 -0
  199. package/src/components/form/errors.ts +6 -0
  200. package/src/components/form/index.ts +7 -0
  201. package/src/components/form/types.ts +55 -0
  202. package/src/components/hover-card/HoverCard.vue +27 -0
  203. package/src/components/hover-card/HoverCardContent.vue +36 -0
  204. package/src/components/hover-card/HoverCardTrigger.vue +12 -0
  205. package/src/components/hover-card/index.ts +3 -0
  206. package/src/components/ifta-label/IftaLabel.vue +26 -0
  207. package/src/components/ifta-label/index.ts +1 -0
  208. package/src/components/index.ts +89 -0
  209. package/src/components/input/Input.vue +87 -0
  210. package/src/components/input/index.ts +1 -0
  211. package/src/components/input-color/ColorArea.vue +36 -0
  212. package/src/components/input-color/ColorField.vue +32 -0
  213. package/src/components/input-color/ColorSlider.vue +31 -0
  214. package/src/components/input-color/InputColor.vue +65 -0
  215. package/src/components/input-color/index.ts +16 -0
  216. package/src/components/input-group/InputGroup.vue +26 -0
  217. package/src/components/input-group/InputGroupAddon.vue +32 -0
  218. package/src/components/input-group/InputGroupInput.vue +33 -0
  219. package/src/components/input-group/index.ts +17 -0
  220. package/src/components/input-number/InputNumber.vue +82 -0
  221. package/src/components/input-number/index.ts +1 -0
  222. package/src/components/input-otp/InputOtp.vue +186 -0
  223. package/src/components/input-otp/index.ts +1 -0
  224. package/src/components/input-password/InputPassword.vue +116 -0
  225. package/src/components/input-password/index.ts +5 -0
  226. package/src/components/input-tags/InputTags.vue +38 -0
  227. package/src/components/input-tags/InputTagsClear.vue +39 -0
  228. package/src/components/input-tags/InputTagsInput.vue +27 -0
  229. package/src/components/input-tags/InputTagsItem.vue +40 -0
  230. package/src/components/input-tags/InputTagsItemDelete.vue +32 -0
  231. package/src/components/input-tags/InputTagsItemText.vue +18 -0
  232. package/src/components/input-tags/index.ts +16 -0
  233. package/src/components/kbd/Kbd.vue +17 -0
  234. package/src/components/kbd/KbdGroup.vue +15 -0
  235. package/src/components/kbd/index.ts +4 -0
  236. package/src/components/label/Label.vue +23 -0
  237. package/src/components/label/index.ts +1 -0
  238. package/src/components/listbox/Listbox.vue +42 -0
  239. package/src/components/listbox/ListboxContent.vue +22 -0
  240. package/src/components/listbox/ListboxFilter.vue +34 -0
  241. package/src/components/listbox/ListboxGroup.vue +31 -0
  242. package/src/components/listbox/ListboxItem.vue +46 -0
  243. package/src/components/listbox/index.ts +19 -0
  244. package/src/components/mask/Mask.vue +205 -0
  245. package/src/components/mask/index.ts +15 -0
  246. package/src/components/menubar/Menubar.vue +26 -0
  247. package/src/components/menubar/MenubarCheckboxItem.vue +30 -0
  248. package/src/components/menubar/MenubarContent.vue +52 -0
  249. package/src/components/menubar/MenubarGroup.vue +12 -0
  250. package/src/components/menubar/MenubarItem.vue +32 -0
  251. package/src/components/menubar/MenubarLabel.vue +21 -0
  252. package/src/components/menubar/MenubarMenu.vue +12 -0
  253. package/src/components/menubar/MenubarRadioGroup.vue +15 -0
  254. package/src/components/menubar/MenubarRadioItem.vue +30 -0
  255. package/src/components/menubar/MenubarSeparator.vue +12 -0
  256. package/src/components/menubar/MenubarShortcut.vue +13 -0
  257. package/src/components/menubar/MenubarSub.vue +15 -0
  258. package/src/components/menubar/MenubarSubContent.vue +26 -0
  259. package/src/components/menubar/MenubarSubTrigger.vue +26 -0
  260. package/src/components/menubar/MenubarTrigger.vue +30 -0
  261. package/src/components/menubar/index.ts +29 -0
  262. package/src/components/navigation-menu/NavigationMenu.vue +43 -0
  263. package/src/components/navigation-menu/NavigationMenuContent.vue +63 -0
  264. package/src/components/navigation-menu/NavigationMenuIndicator.vue +31 -0
  265. package/src/components/navigation-menu/NavigationMenuItem.vue +20 -0
  266. package/src/components/navigation-menu/NavigationMenuLink.vue +34 -0
  267. package/src/components/navigation-menu/NavigationMenuList.vue +23 -0
  268. package/src/components/navigation-menu/NavigationMenuTrigger.vue +38 -0
  269. package/src/components/navigation-menu/NavigationMenuViewport.vue +34 -0
  270. package/src/components/navigation-menu/index.ts +18 -0
  271. package/src/components/order-list/OrderList.vue +168 -0
  272. package/src/components/order-list/SelectableList.vue +200 -0
  273. package/src/components/order-list/index.ts +1 -0
  274. package/src/components/pagination/Pagination.vue +133 -0
  275. package/src/components/pagination/index.ts +1 -0
  276. package/src/components/panel/Panel.vue +69 -0
  277. package/src/components/panel/index.ts +1 -0
  278. package/src/components/pick-list/PickList.vue +211 -0
  279. package/src/components/pick-list/index.ts +1 -0
  280. package/src/components/popover/Popover.vue +15 -0
  281. package/src/components/popover/PopoverAnchor.vue +12 -0
  282. package/src/components/popover/PopoverContent.vue +39 -0
  283. package/src/components/popover/PopoverTrigger.vue +12 -0
  284. package/src/components/popover/index.ts +4 -0
  285. package/src/components/progress/Progress.vue +39 -0
  286. package/src/components/progress/index.ts +1 -0
  287. package/src/components/props-table/PropsTable.vue +62 -0
  288. package/src/components/props-table/index.ts +2 -0
  289. package/src/components/radio-group/RadioGroup.vue +52 -0
  290. package/src/components/radio-group/RadioGroupItem.vue +80 -0
  291. package/src/components/radio-group/RadioGroupItemField.vue +128 -0
  292. package/src/components/radio-group/index.ts +21 -0
  293. package/src/components/rating/Rating.vue +70 -0
  294. package/src/components/rating/RatingItem.vue +26 -0
  295. package/src/components/rating/RatingItemIndicator.vue +28 -0
  296. package/src/components/rating/RatingStar.vue +16 -0
  297. package/src/components/rating/index.ts +13 -0
  298. package/src/components/scroll-area/ScrollArea.vue +52 -0
  299. package/src/components/scroll-area/index.ts +1 -0
  300. package/src/components/search-input/SearchInput.vue +46 -0
  301. package/src/components/search-input/index.ts +1 -0
  302. package/src/components/select/Select.vue +15 -0
  303. package/src/components/select/SelectContent.vue +67 -0
  304. package/src/components/select/SelectGroup.vue +20 -0
  305. package/src/components/select/SelectItem.vue +59 -0
  306. package/src/components/select/SelectLabel.vue +20 -0
  307. package/src/components/select/SelectSeparator.vue +18 -0
  308. package/src/components/select/SelectTrigger.vue +101 -0
  309. package/src/components/select/SelectValue.vue +46 -0
  310. package/src/components/select/index.ts +8 -0
  311. package/src/components/separator/Separator.vue +25 -0
  312. package/src/components/separator/index.ts +1 -0
  313. package/src/components/sheet/Sheet.vue +15 -0
  314. package/src/components/sheet/SheetClose.vue +12 -0
  315. package/src/components/sheet/SheetContent.vue +45 -0
  316. package/src/components/sheet/SheetDescription.vue +19 -0
  317. package/src/components/sheet/SheetFooter.vue +12 -0
  318. package/src/components/sheet/SheetHeader.vue +12 -0
  319. package/src/components/sheet/SheetTitle.vue +19 -0
  320. package/src/components/sheet/SheetTrigger.vue +12 -0
  321. package/src/components/sheet/index.ts +10 -0
  322. package/src/components/sidebar/Sidebar.vue +108 -0
  323. package/src/components/sidebar/SidebarContent.vue +19 -0
  324. package/src/components/sidebar/SidebarFooter.vue +19 -0
  325. package/src/components/sidebar/SidebarGroup.vue +19 -0
  326. package/src/components/sidebar/SidebarGroupAction.vue +28 -0
  327. package/src/components/sidebar/SidebarGroupContent.vue +19 -0
  328. package/src/components/sidebar/SidebarGroupLabel.vue +25 -0
  329. package/src/components/sidebar/SidebarHeader.vue +19 -0
  330. package/src/components/sidebar/SidebarInput.vue +15 -0
  331. package/src/components/sidebar/SidebarInset.vue +22 -0
  332. package/src/components/sidebar/SidebarMenu.vue +19 -0
  333. package/src/components/sidebar/SidebarMenuAction.vue +41 -0
  334. package/src/components/sidebar/SidebarMenuBadge.vue +24 -0
  335. package/src/components/sidebar/SidebarMenuButton.vue +94 -0
  336. package/src/components/sidebar/SidebarMenuItem.vue +19 -0
  337. package/src/components/sidebar/SidebarMenuSkeleton.vue +36 -0
  338. package/src/components/sidebar/SidebarMenuSub.vue +22 -0
  339. package/src/components/sidebar/SidebarMenuSubButton.vue +39 -0
  340. package/src/components/sidebar/SidebarMenuSubItem.vue +19 -0
  341. package/src/components/sidebar/SidebarProvider.vue +114 -0
  342. package/src/components/sidebar/SidebarRail.vue +37 -0
  343. package/src/components/sidebar/SidebarSeparator.vue +15 -0
  344. package/src/components/sidebar/SidebarTrigger.vue +27 -0
  345. package/src/components/sidebar/context.ts +39 -0
  346. package/src/components/sidebar/index.ts +34 -0
  347. package/src/components/skeleton/Skeleton.vue +10 -0
  348. package/src/components/skeleton/index.ts +1 -0
  349. package/src/components/skip-link/SkipLink.vue +45 -0
  350. package/src/components/skip-link/index.ts +1 -0
  351. package/src/components/slider/Slider.vue +57 -0
  352. package/src/components/slider/index.ts +3 -0
  353. package/src/components/speed-dial/SpeedDial.vue +362 -0
  354. package/src/components/speed-dial/index.ts +28 -0
  355. package/src/components/spinner/Spinner.vue +20 -0
  356. package/src/components/spinner/index.ts +1 -0
  357. package/src/components/splitter/Splitter.vue +24 -0
  358. package/src/components/splitter/SplitterHandle.vue +51 -0
  359. package/src/components/splitter/SplitterPanel.vue +30 -0
  360. package/src/components/splitter/index.ts +14 -0
  361. package/src/components/stepper/Stepper.vue +34 -0
  362. package/src/components/stepper/StepperItem.vue +113 -0
  363. package/src/components/stepper/index.ts +2 -0
  364. package/src/components/switch/Switch.vue +35 -0
  365. package/src/components/switch/index.ts +1 -0
  366. package/src/components/table/Table.vue +24 -0
  367. package/src/components/table/TableBody.vue +12 -0
  368. package/src/components/table/TableCell.vue +12 -0
  369. package/src/components/table/TableEmpty.vue +20 -0
  370. package/src/components/table/TableHead.vue +17 -0
  371. package/src/components/table/TableHeader.vue +12 -0
  372. package/src/components/table/TableRow.vue +19 -0
  373. package/src/components/table/index.ts +7 -0
  374. package/src/components/tabs/Tabs.vue +23 -0
  375. package/src/components/tabs/TabsContent.vue +23 -0
  376. package/src/components/tabs/TabsList.vue +26 -0
  377. package/src/components/tabs/TabsTrigger.vue +30 -0
  378. package/src/components/tabs/index.ts +4 -0
  379. package/src/components/textarea/Textarea.vue +25 -0
  380. package/src/components/textarea/index.ts +1 -0
  381. package/src/components/theme-controls/LocaleMenu.vue +95 -0
  382. package/src/components/theme-controls/PaletteMenu.vue +155 -0
  383. package/src/components/theme-controls/ThemeToggle.vue +21 -0
  384. package/src/components/theme-controls/index.ts +15 -0
  385. package/src/components/timeline/Timeline.vue +20 -0
  386. package/src/components/timeline/TimelineItem.vue +68 -0
  387. package/src/components/timeline/index.ts +15 -0
  388. package/src/components/toast/Toaster.vue +62 -0
  389. package/src/components/toast/index.ts +4 -0
  390. package/src/components/toast/toast.ts +57 -0
  391. package/src/components/toggle/Toggle.vue +32 -0
  392. package/src/components/toggle/ToggleGroup.vue +56 -0
  393. package/src/components/toggle/ToggleGroupItem.vue +33 -0
  394. package/src/components/toggle/index.ts +18 -0
  395. package/src/components/token-table/TokenTable.vue +67 -0
  396. package/src/components/token-table/index.ts +2 -0
  397. package/src/components/toolbar/Toolbar.vue +34 -0
  398. package/src/components/toolbar/ToolbarButton.vue +33 -0
  399. package/src/components/toolbar/ToolbarSeparator.vue +21 -0
  400. package/src/components/toolbar/index.ts +3 -0
  401. package/src/components/tooltip/Tooltip.vue +15 -0
  402. package/src/components/tooltip/TooltipContent.vue +38 -0
  403. package/src/components/tooltip/TooltipProvider.vue +16 -0
  404. package/src/components/tooltip/TooltipTrigger.vue +12 -0
  405. package/src/components/tooltip/index.ts +4 -0
  406. package/src/components/tree/Tree.vue +53 -0
  407. package/src/components/tree/TreeItem.vue +59 -0
  408. package/src/components/tree/index.ts +21 -0
  409. package/src/components/tree-select/TreeSelect.vue +141 -0
  410. package/src/components/tree-select/index.ts +1 -0
  411. package/src/components/tree-table/TreeTable.vue +302 -0
  412. package/src/components/tree-table/features.ts +49 -0
  413. package/src/components/tree-table/index.ts +3 -0
  414. package/src/components/video-player/VideoPlayer.vue +472 -0
  415. package/src/components/video-player/index.ts +20 -0
  416. package/src/composables/index.ts +15 -0
  417. package/src/composables/useBase.ts +32 -0
  418. package/src/composables/useChartPalette.ts +33 -0
  419. package/src/composables/useColorMode.ts +29 -0
  420. package/src/composables/useConfirm.ts +81 -0
  421. package/src/composables/useDelayedFlag.ts +62 -0
  422. package/src/composables/useI18n.ts +107 -0
  423. package/src/composables/useIsMobile.ts +34 -0
  424. package/src/composables/useMenuAccent.ts +32 -0
  425. package/src/composables/useMenuAppearance.ts +31 -0
  426. package/src/composables/useMenuColor.ts +31 -0
  427. package/src/composables/usePalette.ts +30 -0
  428. package/src/composables/useStyle.ts +35 -0
  429. package/src/composables/useSurface.ts +30 -0
  430. package/src/composables/useTableQuery.ts +73 -0
  431. package/src/composables/useThemeController.ts +48 -0
  432. package/src/i18n/README.md +68 -0
  433. package/src/i18n/controller.ts +233 -0
  434. package/src/i18n/dictionary.ts +43 -0
  435. package/src/i18n/index.ts +34 -0
  436. package/src/i18n/registry.ts +64 -0
  437. package/src/i18n/ui/en/ui.json +114 -0
  438. package/src/i18n/ui/en/zod.json +16 -0
  439. package/src/i18n/ui/index.ts +48 -0
  440. package/src/i18n/ui/vi/ui.json +114 -0
  441. package/src/i18n/ui/vi/zod.json +16 -0
  442. package/src/lib/date.ts +24 -0
  443. package/src/lib/focus.ts +12 -0
  444. package/src/lib/icons.ts +345 -0
  445. package/src/lib/menu-styles.ts +16 -0
  446. package/src/lib/menu.ts +20 -0
  447. package/src/lib/platform.ts +5 -0
  448. package/src/lib/types.ts +6 -0
  449. package/src/lib/utils.ts +9 -0
  450. package/src/lib/zod-messages.ts +127 -0
  451. package/src/styles/chart.css +30 -0
  452. package/src/styles/index.css +18 -0
  453. package/src/variants/README.md +55 -0
  454. package/src/variants/components/accordion.ts +71 -0
  455. package/src/variants/components/alert.ts +20 -0
  456. package/src/variants/components/badge.ts +76 -0
  457. package/src/variants/components/button-group.ts +136 -0
  458. package/src/variants/components/button.ts +160 -0
  459. package/src/variants/components/checkbox.ts +67 -0
  460. package/src/variants/components/chip.ts +51 -0
  461. package/src/variants/components/code-block.ts +22 -0
  462. package/src/variants/components/dialog.ts +28 -0
  463. package/src/variants/components/empty.ts +60 -0
  464. package/src/variants/components/field.ts +35 -0
  465. package/src/variants/components/float-label.ts +95 -0
  466. package/src/variants/components/input-group.ts +73 -0
  467. package/src/variants/components/input-password.ts +68 -0
  468. package/src/variants/components/kbd.ts +47 -0
  469. package/src/variants/components/picker-trigger.ts +30 -0
  470. package/src/variants/components/radio-group.ts +63 -0
  471. package/src/variants/components/sheet.ts +23 -0
  472. package/src/variants/components/sidebar.ts +33 -0
  473. package/src/variants/components/slider.ts +49 -0
  474. package/src/variants/components/timeline.ts +45 -0
  475. package/src/variants/components/toggle.ts +58 -0
  476. package/src/variants/index.ts +35 -0
  477. package/src/variants/lib/chart/polar.ts +139 -0
  478. package/src/variants/lib/chart/tooltip.ts +101 -0
  479. package/src/variants/lib/chart/types.ts +172 -0
  480. package/src/variants/lib/chart/xy-label.ts +42 -0
  481. package/src/variants/lib/focus.ts +66 -0
  482. package/src/variants/lib/form-errors.ts +59 -0
  483. package/src/variants/lib/highlight.ts +548 -0
  484. package/src/variants/lib/list-move.ts +63 -0
  485. package/src/variants/lib/mask.ts +106 -0
  486. package/src/variants/lib/media.ts +56 -0
  487. package/src/variants/lib/menu-styles.ts +71 -0
  488. package/src/variants/lib/platform.ts +68 -0
  489. package/src/variants/lib/tree.ts +119 -0
  490. package/src/variants/lib/upload.ts +58 -0
  491. package/src/variants/lib/utils.ts +11 -0
@@ -0,0 +1,35 @@
1
+ <script setup lang="ts">
2
+ import type { SwitchRootEmits, SwitchRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { SwitchRoot, SwitchThumb, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { focusRing } from '../../lib/focus'
7
+ import { cn } from '../../lib/utils'
8
+
9
+ const props = defineProps<SwitchRootProps & ClassProps>()
10
+ const emits = defineEmits<SwitchRootEmits>()
11
+
12
+ const delegated = computed(() => {
13
+ const { class: _class, ...rest } = props
14
+ return rest
15
+ })
16
+
17
+ const forwarded = useForwardPropsEmits(delegated, emits)
18
+ </script>
19
+
20
+ <template>
21
+ <SwitchRoot
22
+ v-bind="forwarded"
23
+ :class="cn(
24
+ 'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors',
25
+ focusRing,
26
+ 'disabled:cursor-not-allowed disabled:opacity-50',
27
+ 'data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
28
+ props.class,
29
+ )"
30
+ >
31
+ <SwitchThumb
32
+ class="pointer-events-none block size-4 rounded-full bg-background shadow-sm ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
33
+ />
34
+ </SwitchRoot>
35
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Switch } from './Switch.vue'
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ /**
6
+ * Thuộc tính rơi tự do đi xuống `<table>`, KHÔNG xuống cái div bọc.
7
+ *
8
+ * Cái div chỉ là vùng cuộn — nó đã có `containerClass` của riêng nó. Đặt
9
+ * `role="treegrid"` lên `<Table>` mà nó dính vào div thì bảng vẫn là `table`,
10
+ * còn cái div thành một treegrid rỗng: hai lời khai sai cùng lúc, không có gì báo.
11
+ */
12
+ defineOptions({ inheritAttrs: false })
13
+
14
+ const props = defineProps<ClassProps & { containerClass?: string }>()
15
+ </script>
16
+
17
+ <template>
18
+ <!-- Bảng luôn cuộn trong container riêng -> body trang không bao giờ cuộn ngang -->
19
+ <div :class="cn('relative w-full overflow-auto', props.containerClass)">
20
+ <table v-bind="$attrs" :class="cn('w-full caption-bottom border-separate border-spacing-0 text-sm', props.class)">
21
+ <slot />
22
+ </table>
23
+ </div>
24
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ const props = defineProps<ClassProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <tbody :class="cn('[&_tr:last-child_td]:border-b-0', props.class)">
10
+ <slot />
11
+ </tbody>
12
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ const props = defineProps<ClassProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <td :class="cn('border-b border-border px-3 py-2 align-middle', props.class)">
10
+ <slot />
11
+ </td>
12
+ </template>
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { useI18n } from '../../composables/useI18n'
4
+ import { Inbox } from '../../lib/icons'
5
+ import { cn } from '../../lib/utils'
6
+
7
+ const props = defineProps<ClassProps & { colspan: number, message?: string }>()
8
+ const { t } = useI18n()
9
+ </script>
10
+
11
+ <template>
12
+ <tr>
13
+ <td :colspan="props.colspan" :class="cn('h-40 text-center', props.class)">
14
+ <div class="flex flex-col items-center justify-center gap-2 text-muted-foreground">
15
+ <Inbox class="size-6" />
16
+ <span class="text-sm">{{ props.message ?? t('ui.table.empty') }}</span>
17
+ </div>
18
+ </td>
19
+ </tr>
20
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ const props = defineProps<ClassProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <th
10
+ :class="cn(
11
+ 'h-10 whitespace-nowrap border-b border-border bg-muted/60 px-3 text-left align-middle text-xs font-medium text-muted-foreground backdrop-blur',
12
+ props.class,
13
+ )"
14
+ >
15
+ <slot />
16
+ </th>
17
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ const props = defineProps<ClassProps & { sticky?: boolean }>()
6
+ </script>
7
+
8
+ <template>
9
+ <thead :class="cn(props.sticky && '[&_th]:sticky [&_th]:top-0 [&_th]:z-(--z-raised)', props.class)">
10
+ <slot />
11
+ </thead>
12
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { cn } from '../../lib/utils'
4
+
5
+ const props = defineProps<ClassProps & { selected?: boolean, clickable?: boolean }>()
6
+ </script>
7
+
8
+ <template>
9
+ <tr
10
+ :data-state="props.selected ? 'selected' : undefined"
11
+ :class="cn(
12
+ 'transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
13
+ props.clickable && 'cursor-pointer',
14
+ props.class,
15
+ )"
16
+ >
17
+ <slot />
18
+ </tr>
19
+ </template>
@@ -0,0 +1,7 @@
1
+ export { default as Table } from './Table.vue'
2
+ export { default as TableBody } from './TableBody.vue'
3
+ export { default as TableCell } from './TableCell.vue'
4
+ export { default as TableEmpty } from './TableEmpty.vue'
5
+ export { default as TableHead } from './TableHead.vue'
6
+ export { default as TableHeader } from './TableHeader.vue'
7
+ export { default as TableRow } from './TableRow.vue'
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import type { TabsRootEmits, TabsRootProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { TabsRoot, useForwardPropsEmits } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<TabsRootProps & ClassProps>()
9
+ const emits = defineEmits<TabsRootEmits>()
10
+
11
+ const delegated = computed(() => {
12
+ const { class: _class, ...rest } = props
13
+ return rest
14
+ })
15
+
16
+ const forwarded = useForwardPropsEmits(delegated, emits)
17
+ </script>
18
+
19
+ <template>
20
+ <TabsRoot v-bind="forwarded" :class="cn('flex flex-col gap-4', props.class)">
21
+ <slot />
22
+ </TabsRoot>
23
+ </template>
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import type { TabsContentProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { TabsContent } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<TabsContentProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <TabsContent
18
+ v-bind="delegated"
19
+ :class="cn('outline-none focus-visible:ring-2 focus-visible:ring-ring', props.class)"
20
+ >
21
+ <slot />
22
+ </TabsContent>
23
+ </template>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { TabsListProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { TabsList } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<TabsListProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <TabsList
18
+ v-bind="delegated"
19
+ :class="cn(
20
+ 'inline-flex h-9 w-fit items-center justify-center gap-1 rounded-lg bg-muted p-1 text-muted-foreground',
21
+ props.class,
22
+ )"
23
+ >
24
+ <slot />
25
+ </TabsList>
26
+ </template>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import type { TabsTriggerProps } from 'reka-ui'
3
+ import type { ClassProps } from '../../lib/types'
4
+ import { TabsTrigger } from 'reka-ui'
5
+ import { computed } from 'vue'
6
+ import { cn } from '../../lib/utils'
7
+
8
+ const props = defineProps<TabsTriggerProps & ClassProps>()
9
+
10
+ const delegated = computed(() => {
11
+ const { class: _class, ...rest } = props
12
+ return rest
13
+ })
14
+ </script>
15
+
16
+ <template>
17
+ <TabsTrigger
18
+ v-bind="delegated"
19
+ :class="cn(
20
+ 'inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all',
21
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
22
+ 'disabled:pointer-events-none disabled:opacity-50',
23
+ 'data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
24
+ '[&_svg]:size-4 [&_svg]:shrink-0',
25
+ props.class,
26
+ )"
27
+ >
28
+ <slot />
29
+ </TabsTrigger>
30
+ </template>
@@ -0,0 +1,4 @@
1
+ export { default as Tabs } from './Tabs.vue'
2
+ export { default as TabsContent } from './TabsContent.vue'
3
+ export { default as TabsList } from './TabsList.vue'
4
+ export { default as TabsTrigger } from './TabsTrigger.vue'
@@ -0,0 +1,25 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import { focusRing, invalidRing } from '../../lib/focus'
4
+ import { cn } from '../../lib/utils'
5
+
6
+ defineProps<ClassProps & { invalid?: boolean }>()
7
+
8
+ const model = defineModel<string | null>()
9
+ </script>
10
+
11
+ <template>
12
+ <textarea
13
+ v-model="model"
14
+ :aria-invalid="invalid || undefined"
15
+ :data-invalid="invalid || undefined"
16
+ :class="cn(
17
+ 'flex min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs transition-colors',
18
+ 'placeholder:text-muted-foreground',
19
+ focusRing,
20
+ 'disabled:cursor-not-allowed disabled:opacity-50',
21
+ invalidRing,
22
+ $props.class,
23
+ )"
24
+ />
25
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Textarea } from './Textarea.vue'
@@ -0,0 +1,95 @@
1
+ <script setup lang="ts">
2
+ import { useI18n } from '../../composables/useI18n'
3
+ import { Check, Languages } from '../../lib/icons'
4
+ import { Button } from '../button'
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuLabel,
10
+ DropdownMenuTrigger,
11
+ } from '../dropdown-menu'
12
+
13
+ /**
14
+ * Nút đổi ngôn ngữ. Dùng ở CẢ HAI header — `KitHeader` của trang giới thiệu và
15
+ * `AdminLayout` của màn quản trị.
16
+ *
17
+ * Trước đó danh sách ngôn ngữ nằm trong `PaletteMenu`, mà `PaletteMenu` chỉ có ở
18
+ * `KitHeader` — nghĩa là vào `/admin` rồi thì không còn đường đổi ngôn ngữ. Tách
19
+ * ra thành control riêng vì ngôn ngữ không phải một trục *giao diện*: nó không
20
+ * đi cùng nhóm với bảng màu, chế độ sáng tối và bề mặt.
21
+ *
22
+ * Nút là ICON, không phải mã ngôn ngữ.
23
+ *
24
+ * Bản trước hiện "EN" / "VI" với lý do: người đang lạc sang thứ tiếng không đọc
25
+ * được vẫn nhận ra mã, còn icon thì chỉ nói đây là chỗ đổi ngôn ngữ chứ không
26
+ * nói đang ở ngôn ngữ nào. Đánh đổi đó vẫn có thật — nhưng thông tin ấy không
27
+ * mất, nó lùi vào trong menu: mục đang bật có dấu tick, và tên mỗi ngôn ngữ
28
+ * viết bằng CHÍNH ngôn ngữ đó nên vẫn nhận ra được mà không cần đọc hiểu.
29
+ *
30
+ * `Languages` chứ không phải `Globe`: quả địa cầu trong lucide đọc ra là vùng /
31
+ * trang web, còn cái này là dịch thuật.
32
+ *
33
+ * **Nét 2,2 chứ không phải 2 mặc định của Lucide** — chỉnh cho THUẬN MẮT, và là
34
+ * chỗ duy nhất trong repo đi chệch nét chuẩn.
35
+ *
36
+ * `languages` là một glyph THƯA: hai cụm nhỏ nằm chéo nhau, nét ngắn, ở giữa
37
+ * gần như trống. Đo độ phủ mực trên 24 icon Lucide đang dùng thì nó được 0,219
38
+ * — thấp hơn trung vị 0,265 khoảng 17%, và thấp nhất trong ba icon của cụm bên
39
+ * phải `KitHeader`. Cùng khung 16px mà nhìn ra nhạt hơn hẳn.
40
+ *
41
+ * Không chữa bằng cách phóng to: thiếu MỰC chứ không thiếu BỀ NGANG — nét chéo
42
+ * đã trải kín khung, nên 17–18px làm nó to hơn hai icon kia thấy rõ (đã dựng
43
+ * thử ở mức phóng 4×). Chữa bằng nét thì mực dày lên mà hình không đổi cỡ.
44
+ *
45
+ * 2,4 bù đủ mực theo số đo nhưng nhìn ra ĐẬM hơn hai icon kia — dấu hiệu cho
46
+ * thấy khớp riêng độ phủ là sai, vì phép đo đó phạt oan glyph thưa mà rộng.
47
+ * 2,2 là chỗ mắt thấy cả ba cùng sức nặng.
48
+ */
49
+ const props = defineProps<{
50
+ /** Class cho nút bấm. Hai header có kích thước nút khác nhau. */
51
+ class?: string
52
+ }>()
53
+
54
+ const { locale, locales, setLocale, t } = useI18n()
55
+ </script>
56
+
57
+ <template>
58
+ <DropdownMenu>
59
+ <DropdownMenuTrigger as-child>
60
+ <Button
61
+ variant="ghost"
62
+ :class="props.class"
63
+ :aria-label="t('ui.locale.language')"
64
+ >
65
+ <!-- Nét 2,2, không phải 2 — lý do ở JSDoc đầu file. -->
66
+ <Languages :stroke-width="2.2" />
67
+ </Button>
68
+ </DropdownMenuTrigger>
69
+
70
+ <DropdownMenuContent align="end" class="w-[212px]">
71
+ <DropdownMenuLabel>{{ t('ui.locale.language') }}</DropdownMenuLabel>
72
+
73
+ <DropdownMenuItem
74
+ v-for="item in locales"
75
+ :key="item.id"
76
+ class="gap-2.5"
77
+ @select="setLocale(item.id)"
78
+ >
79
+ <span class="grid size-[26px] flex-none place-items-center rounded-lg border border-border bg-secondary text-[10px] font-semibold uppercase">
80
+ {{ item.id }}
81
+ </span>
82
+
83
+ <span class="flex min-w-0 flex-1 flex-col">
84
+ <!-- Tên viết bằng CHÍNH ngôn ngữ đó, không dịch — xem `locales` trong
85
+ `src/i18n`. Dịch nó ra thì người đang lạc ngôn ngữ không tìm
86
+ được đường về. -->
87
+ <span class="text-[12.5px] font-medium">{{ item.name }}</span>
88
+ <span class="truncate text-[11px] text-muted-foreground">{{ item.tag }}</span>
89
+ </span>
90
+
91
+ <Check v-if="item.id === locale" class="flex-none text-primary" />
92
+ </DropdownMenuItem>
93
+ </DropdownMenuContent>
94
+ </DropdownMenu>
95
+ </template>
@@ -0,0 +1,155 @@
1
+ <script setup lang="ts">
2
+ import type { Component } from 'vue'
3
+ import type { ColorMode } from '../../composables/useColorMode'
4
+ import { computed } from 'vue'
5
+ import { useColorMode } from '../../composables/useColorMode'
6
+ import { useI18n } from '../../composables/useI18n'
7
+ import { usePalette } from '../../composables/usePalette'
8
+ import { Check, Monitor, Moon, Palette, Sun } from '../../lib/icons'
9
+ import { cn } from '../../lib/utils'
10
+ import { Button } from '../button'
11
+ import {
12
+ DropdownMenu,
13
+ DropdownMenuContent,
14
+ DropdownMenuItem,
15
+ DropdownMenuLabel,
16
+ DropdownMenuSeparator,
17
+ DropdownMenuTrigger,
18
+ } from '../dropdown-menu'
19
+
20
+ /*
21
+ * Ngôn ngữ KHÔNG nằm ở đây — nó có `LocaleMenu` riêng. Ba trục trong menu này
22
+ * đều là diện mạo và đều ghi lên `<html>` qua `themeController`; ngôn ngữ thì
23
+ * không cùng nhóm, và menu này lại chỉ có ở `KitHeader`, nên để chung là màn
24
+ * quản trị không có đường đổi ngôn ngữ.
25
+ */
26
+
27
+ /**
28
+ * Đọc thẳng ba composable, KHÔNG qua pinia store của app.
29
+ *
30
+ * Trước đây control này nằm ở `apps/admin` và đi qua `useThemeStore`. Cái store
31
+ * đó không giữ state — nó chỉ chuyền tiếp đúng ba composable dưới đây — nên bỏ
32
+ * nó đi không tạo ra nguồn sự thật thứ hai, mà lại gỡ được ràng buộc cuối cùng
33
+ * giữ control này ngoài `packages/ui`: không router, không store.
34
+ *
35
+ * Nhờ vậy cả ba app (kit, blocks, admin) dùng chung một bản.
36
+ */
37
+ const props = defineProps<{
38
+ /**
39
+ * Class cho nút bấm. Cùng khuôn với `LocaleMenu` — hai control này luôn đứng
40
+ * cạnh nhau nên chúng phải nhận sắc thái từ cùng một chỗ.
41
+ */
42
+ class?: string
43
+ }>()
44
+
45
+ const { t } = useI18n()
46
+ const { mode, setMode } = useColorMode()
47
+ const { palette, palettes, setPalette } = usePalette()
48
+
49
+ const activePalette = computed(() => palettes.find(item => item.id === palette.value) ?? palettes[0])
50
+
51
+ /**
52
+ * Khai ngay tại đây chứ không đưa vào `useColorMode`: composable nằm trong
53
+ * `packages/ui`, mà chuỗi người dùng nhìn thấy thì thuộc về app.
54
+ *
55
+ * Phải là `computed`, không phải hằng ở tầng module: hằng tính đúng một lần lúc
56
+ * import nên nó đóng băng ở ngôn ngữ lúc ấy — cùng cái bẫy của `withDefaults`.
57
+ */
58
+ const colorModes = computed<{ id: ColorMode, name: string, description: string, icon: Component }[]>(() => [
59
+ { id: 'light', name: t('ui.theme.modeLight'), description: t('ui.theme.modeLightHint'), icon: Sun },
60
+ { id: 'dark', name: t('ui.theme.modeDark'), description: t('ui.theme.modeDarkHint'), icon: Moon },
61
+ { id: 'system', name: t('ui.theme.modeSystem'), description: t('ui.theme.modeSystemHint'), icon: Monitor },
62
+ ])
63
+
64
+ /**
65
+ * Mô tả của bảng màu PHỦ lên registry, không sửa registry.
66
+ *
67
+ * `@vestow/theme` là dữ liệu thuần dùng chung cho mọi framework — nhét một
68
+ * danh sách ngôn ngữ vào đó là bắt nó biết tới i18n. Chuỗi tiếng Anh ở registry
69
+ * vì vậy vẫn còn nguyên và làm bản mặc định cho bên dùng không có i18n; app thì
70
+ * phủ lên theo `id`.
71
+ *
72
+ * Tên bảng màu là danh từ riêng nên giữ nguyên — chỉ mô tả mới dịch.
73
+ */
74
+ const paletteOptions = computed(() =>
75
+ palettes.map(item => ({ ...item, description: t(`ui.theme.paletteHint.${item.id}`) })),
76
+ )
77
+ </script>
78
+
79
+ <template>
80
+ <DropdownMenu>
81
+ <DropdownMenuTrigger as-child>
82
+ <!--
83
+ Icon, không phải ô màu của bảng đang chọn.
84
+
85
+ Bản trước vẽ một chấm tròn mang đúng màu primary đang bật — nó nói được
86
+ "đang ở bảng nào" ngay ở trạng thái nghỉ. Đổi sang icon thì mất vế đó,
87
+ nhưng thông tin lùi vào menu chứ không mất hẳn: mục đang bật có dấu tick,
88
+ và mỗi bảng màu vẫn hiện dải ô màu của nó.
89
+
90
+ Đổi lại, ba nút trong cụm bên phải header giờ cùng một ngôn ngữ hình ảnh
91
+ (icon đơn sắc) thay vì một chấm màu đứng giữa hai icon.
92
+
93
+ Nhãn nói CHUNG về giao diện, không riêng bảng màu: menu này gom cả ba
94
+ trục — bảng màu, sáng/tối, bề mặt.
95
+ -->
96
+ <Button variant="ghost" size="icon" :class="cn('size-[30px] rounded-full', props.class)" :aria-label="t('ui.theme.appearanceSettings')">
97
+ <Palette />
98
+ </Button>
99
+ </DropdownMenuTrigger>
100
+
101
+ <DropdownMenuContent align="end" class="w-[262px]">
102
+ <DropdownMenuLabel>{{ t('ui.theme.palette') }}</DropdownMenuLabel>
103
+
104
+ <DropdownMenuItem
105
+ v-for="item in paletteOptions"
106
+ :key="item.id"
107
+ class="gap-2.5"
108
+ @select="setPalette(item.id)"
109
+ >
110
+ <span class="flex flex-none gap-[3px]">
111
+ <span
112
+ v-for="(swatch, index) in item.swatches"
113
+ :key="index"
114
+ class="size-3.5 rounded-md border border-border"
115
+ :style="{ background: swatch }"
116
+ />
117
+ </span>
118
+
119
+ <span class="flex min-w-0 flex-1 flex-col">
120
+ <span class="text-[12.5px] font-medium">{{ item.name }}</span>
121
+ <span class="truncate text-[11px] text-muted-foreground">{{ item.description }}</span>
122
+ </span>
123
+
124
+ <Check v-if="item.id === palette" class="flex-none text-primary" />
125
+ </DropdownMenuItem>
126
+
127
+ <DropdownMenuSeparator />
128
+
129
+ <DropdownMenuLabel>{{ t('ui.theme.appearance') }}</DropdownMenuLabel>
130
+
131
+ <DropdownMenuItem
132
+ v-for="item in colorModes"
133
+ :key="item.id"
134
+ class="gap-2.5"
135
+ @select="setMode(item.id)"
136
+ >
137
+ <span class="grid size-[26px] flex-none place-items-center rounded-lg border border-border bg-secondary">
138
+ <component :is="item.icon" />
139
+ </span>
140
+
141
+ <span class="flex min-w-0 flex-1 flex-col">
142
+ <span class="text-[12.5px] font-medium">{{ item.name }}</span>
143
+ <span class="truncate text-[11px] text-muted-foreground">{{ item.description }}</span>
144
+ </span>
145
+
146
+ <Check v-if="item.id === mode" class="flex-none text-primary" />
147
+ </DropdownMenuItem>
148
+
149
+ <div class="flex items-center justify-between gap-2 px-2 pb-1 pt-0.5 font-mono text-[11px] text-muted-foreground">
150
+ <span>--primary</span>
151
+ <span class="text-foreground">{{ activePalette.swatches[0] }}</span>
152
+ </div>
153
+ </DropdownMenuContent>
154
+ </DropdownMenu>
155
+ </template>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import { useColorMode } from '../../composables/useColorMode'
3
+ import { useI18n } from '../../composables/useI18n'
4
+ import { Moon, Sun } from '../../lib/icons'
5
+ import { Button } from '../button'
6
+
7
+ const { t } = useI18n()
8
+ const { isDark, toggle } = useColorMode()
9
+ </script>
10
+
11
+ <template>
12
+ <Button
13
+ variant="ghost"
14
+ size="icon"
15
+ :aria-label="isDark ? t('ui.theme.toLight') : t('ui.theme.toDark')"
16
+ @click="toggle()"
17
+ >
18
+ <Moon v-if="isDark" />
19
+ <Sun v-else />
20
+ </Button>
21
+ </template>
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Ba control cho ba trục giao diện, cộng nút đổi ngôn ngữ.
3
+ *
4
+ * Nằm ở `packages/ui` chứ không ở app vì chúng **không đọc router và không đọc
5
+ * store** — chỉ đi qua `useColorMode` / `usePalette` / `useSurface` / `useI18n`,
6
+ * mà cả bốn đều ở ngay trong package này. Nhờ vậy kit, blocks và admin dùng
7
+ * chung đúng một bản thay vì mỗi app một bản trôi dần khỏi nhau.
8
+ *
9
+ * Trước đây chúng ở `apps/admin` với lý do "phải đọc pinia store". Lý do đó
10
+ * không đứng vững: cái store ấy không giữ state, nó chỉ chuyền tiếp đúng ba
11
+ * composable trên.
12
+ */
13
+ export { default as LocaleMenu } from './LocaleMenu.vue'
14
+ export { default as PaletteMenu } from './PaletteMenu.vue'
15
+ export { default as ThemeToggle } from './ThemeToggle.vue'
@@ -0,0 +1,20 @@
1
+ <script setup lang="ts">
2
+ import type { ClassProps } from '../../lib/types'
3
+ import type { TimelineVariants } from './index'
4
+ import { computed } from 'vue'
5
+ import { cn } from '../../lib/utils'
6
+ import { provideTimelineContext, timelineVariants } from './index'
7
+
8
+ const props = withDefaults(
9
+ defineProps<ClassProps & { size?: TimelineVariants['size'] }>(),
10
+ { size: 'default' },
11
+ )
12
+
13
+ provideTimelineContext({ size: computed(() => props.size) })
14
+ </script>
15
+
16
+ <template>
17
+ <ol :class="cn(timelineVariants({ size: props.size }), props.class)">
18
+ <slot />
19
+ </ol>
20
+ </template>