@brumaombra/ui-vintage 0.9.1 → 0.9.2

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 (334) hide show
  1. package/module.mjs +43 -43
  2. package/package.json +175 -175
  3. package/src/components/background-grid/BackgroundGrid.vue +4 -4
  4. package/src/components/blog/AllPostsSection.vue +33 -33
  5. package/src/components/blog/BlogContentRenderer.vue +111 -111
  6. package/src/components/blog/BlogFAQSection.vue +19 -19
  7. package/src/components/blog/BlogHeaderSection.vue +80 -80
  8. package/src/components/blog/BlogInfoSection.vue +47 -47
  9. package/src/components/blog/BlogPostHeader.vue +135 -135
  10. package/src/components/blog/BlogProgressBar.vue +33 -33
  11. package/src/components/blog/BlogSectionTitle.vue +22 -22
  12. package/src/components/blog/BlogTagsSection.vue +25 -25
  13. package/src/components/blog/CategoriesList.vue +14 -14
  14. package/src/components/blog/CategoriesSection.vue +11 -11
  15. package/src/components/blog/CategoryCard.vue +25 -25
  16. package/src/components/blog/HeaderCarousel.vue +97 -97
  17. package/src/components/blog/PostCard.vue +33 -33
  18. package/src/components/blog/PostsList.vue +15 -15
  19. package/src/components/blog/SocialShareSidebar.vue +84 -84
  20. package/src/components/blog/TableOfContents.vue +307 -307
  21. package/src/components/busy-indicator/BusyIndicator.vue +7 -7
  22. package/src/components/busy-indicator/busy-indicator-state.ts +56 -56
  23. package/src/components/card-grid/CardGrid.vue +34 -34
  24. package/src/components/chip/Chip.vue +15 -15
  25. package/src/components/confirm-dialog/ConfirmDialog.vue +50 -50
  26. package/src/components/confirm-dialog/confirm-dialog-state.ts +131 -131
  27. package/src/components/content/BlogList.vue +30 -30
  28. package/src/components/content/BlogTable.vue +36 -36
  29. package/src/components/content/CodeBlock.vue +136 -136
  30. package/src/components/content/Flow.vue +60 -60
  31. package/src/components/content/ProseHr.vue +15 -15
  32. package/src/components/content/ProsePre.vue +12 -12
  33. package/src/components/content/Terminal.vue +59 -59
  34. package/src/components/cookie-consent/CookieConsent.vue +36 -36
  35. package/src/components/cookie-consent/useCookieConsent.ts +37 -37
  36. package/src/components/dashboard-shell/DashboardShell.vue +171 -171
  37. package/src/components/data-list/DataList.vue +6 -6
  38. package/src/components/data-list/DataListItem.vue +4 -4
  39. package/src/components/data-list/DataListLabel.vue +4 -4
  40. package/src/components/data-list/DataListText.vue +4 -4
  41. package/src/components/data-list/DataListValue.vue +4 -4
  42. package/src/components/empty-state-card/EmptyStateCard.vue +40 -40
  43. package/src/components/error-page/ErrorPage.vue +72 -72
  44. package/src/components/info-card/InfoCard.vue +31 -31
  45. package/src/components/landing/landing-content/LandingContent.vue +4 -4
  46. package/src/components/landing/landing-footer/LandingFooter.vue +128 -128
  47. package/src/components/landing/landing-navbar/LandingNavbar.vue +50 -50
  48. package/src/components/landing/landing-shell/LandingShell.vue +36 -36
  49. package/src/components/language-flag/LanguageFlag.vue +25 -25
  50. package/src/components/language-flag/flags/ChineseFlag.vue +8 -8
  51. package/src/components/language-flag/flags/EnglishFlag.vue +7 -7
  52. package/src/components/language-flag/flags/FrenchFlag.vue +5 -5
  53. package/src/components/language-flag/flags/GermanFlag.vue +5 -5
  54. package/src/components/language-flag/flags/ItalianFlag.vue +7 -7
  55. package/src/components/language-flag/flags/JapaneseFlag.vue +4 -4
  56. package/src/components/language-flag/flags/PortugueseFlag.vue +57 -57
  57. package/src/components/language-flag/flags/RussianFlag.vue +5 -5
  58. package/src/components/language-flag/flags/SpanishFlag.vue +4 -4
  59. package/src/components/language-selector/LanguageSelector.vue +76 -76
  60. package/src/components/load-more-button/LoadMoreButton.vue +17 -17
  61. package/src/components/loading-state-card/LoadingStateCard.vue +28 -28
  62. package/src/components/message-dialog/MessageDialog.vue +59 -59
  63. package/src/components/message-dialog/message-dialog-state.ts +105 -105
  64. package/src/components/message-toast/MessageToast.vue +149 -149
  65. package/src/components/message-toast/message-toast-state.ts +146 -146
  66. package/src/components/page-header/PageHeader.vue +34 -34
  67. package/src/components/progress-component/ProgressComponent.vue +33 -33
  68. package/src/components/single-value-card/SingleValueCard.vue +57 -57
  69. package/src/components/slider-form-component/SliderFormComponent.vue +36 -36
  70. package/src/components/stat-strip/StatStrip.vue +22 -22
  71. package/src/components/switch-form-component/SwitchFormComponent.vue +20 -20
  72. package/src/components/text-link/TextLink.vue +14 -14
  73. package/src/components/theme-selector/ThemeSelector.vue +61 -61
  74. package/src/components/theme-selector/theme-transition.ts +63 -63
  75. package/src/components/ui/accordion/Accordion.vue +38 -38
  76. package/src/components/ui/alert/Alert.vue +5 -5
  77. package/src/components/ui/alert/AlertDescription.vue +4 -4
  78. package/src/components/ui/alert/AlertTitle.vue +4 -4
  79. package/src/components/ui/alert/index.ts +2 -2
  80. package/src/components/ui/alert-dialog/AlertDialog.vue +3 -3
  81. package/src/components/ui/alert-dialog/AlertDialogAction.vue +3 -3
  82. package/src/components/ui/alert-dialog/AlertDialogCancel.vue +3 -3
  83. package/src/components/ui/alert-dialog/AlertDialogContent.vue +7 -7
  84. package/src/components/ui/alert-dialog/AlertDialogDescription.vue +3 -3
  85. package/src/components/ui/alert-dialog/AlertDialogFooter.vue +4 -4
  86. package/src/components/ui/alert-dialog/AlertDialogHeader.vue +4 -4
  87. package/src/components/ui/alert-dialog/AlertDialogTitle.vue +3 -3
  88. package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +3 -3
  89. package/src/components/ui/animated-number/AnimatedNumber.vue +49 -48
  90. package/src/components/ui/avatar/Avatar.vue +28 -28
  91. package/src/components/ui/avatar/AvatarFallback.vue +6 -6
  92. package/src/components/ui/avatar/AvatarGroup.vue +40 -40
  93. package/src/components/ui/avatar/AvatarImage.vue +3 -3
  94. package/src/components/ui/avatar/index.ts +17 -17
  95. package/src/components/ui/badge/Badge.vue +20 -20
  96. package/src/components/ui/breadcrumb/Breadcrumb.vue +4 -4
  97. package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +9 -9
  98. package/src/components/ui/breadcrumb/BreadcrumbItem.vue +4 -4
  99. package/src/components/ui/breadcrumb/BreadcrumbLink.vue +4 -4
  100. package/src/components/ui/breadcrumb/BreadcrumbList.vue +4 -4
  101. package/src/components/ui/breadcrumb/BreadcrumbPage.vue +4 -4
  102. package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +4 -4
  103. package/src/components/ui/busy/Busy.vue +33 -33
  104. package/src/components/ui/button/Button.vue +23 -23
  105. package/src/components/ui/button/index.ts +56 -56
  106. package/src/components/ui/calendar/Calendar.vue +138 -138
  107. package/src/components/ui/calendar/CalendarCell.vue +7 -7
  108. package/src/components/ui/calendar/CalendarCellTrigger.vue +18 -18
  109. package/src/components/ui/calendar/CalendarGrid.vue +3 -3
  110. package/src/components/ui/calendar/CalendarGridBody.vue +3 -3
  111. package/src/components/ui/calendar/CalendarGridHead.vue +3 -3
  112. package/src/components/ui/calendar/CalendarGridRow.vue +3 -3
  113. package/src/components/ui/calendar/CalendarHeadCell.vue +7 -7
  114. package/src/components/ui/calendar/CalendarHeader.vue +7 -7
  115. package/src/components/ui/calendar/CalendarHeading.vue +6 -6
  116. package/src/components/ui/calendar/CalendarNextButton.vue +15 -15
  117. package/src/components/ui/calendar/CalendarPrevButton.vue +15 -15
  118. package/src/components/ui/calendar/index.ts +4 -4
  119. package/src/components/ui/card/Card.vue +20 -20
  120. package/src/components/ui/card/CardAction.vue +8 -8
  121. package/src/components/ui/card/CardContent.vue +4 -4
  122. package/src/components/ui/card/CardDescription.vue +12 -12
  123. package/src/components/ui/card/CardFooter.vue +4 -4
  124. package/src/components/ui/card/CardHeader.vue +8 -8
  125. package/src/components/ui/card/CardText.vue +8 -8
  126. package/src/components/ui/card/CardTitle.vue +8 -8
  127. package/src/components/ui/checkbox/Checkbox.vue +27 -27
  128. package/src/components/ui/collapsible/Collapsible.vue +3 -3
  129. package/src/components/ui/collapsible/CollapsibleContent.vue +3 -3
  130. package/src/components/ui/collapsible/CollapsibleTrigger.vue +3 -3
  131. package/src/components/ui/combobox/Combobox.vue +4 -4
  132. package/src/components/ui/combobox/ComboboxAnchor.vue +16 -16
  133. package/src/components/ui/combobox/ComboboxEmpty.vue +3 -3
  134. package/src/components/ui/combobox/ComboboxGroup.vue +9 -9
  135. package/src/components/ui/combobox/ComboboxInput.vue +6 -6
  136. package/src/components/ui/combobox/ComboboxItem.vue +17 -17
  137. package/src/components/ui/combobox/ComboboxList.vue +19 -19
  138. package/src/components/ui/combobox/ComboboxSelect.vue +77 -77
  139. package/src/components/ui/combobox/ComboboxSeparator.vue +1 -1
  140. package/src/components/ui/combobox/ComboboxTrigger.vue +10 -10
  141. package/src/components/ui/combobox/types.ts +5 -5
  142. package/src/components/ui/command/Command.vue +48 -48
  143. package/src/components/ui/command/CommandDialog.vue +14 -14
  144. package/src/components/ui/command/CommandEmpty.vue +4 -4
  145. package/src/components/ui/command/CommandGroup.vue +23 -23
  146. package/src/components/ui/command/CommandInput.vue +9 -9
  147. package/src/components/ui/command/CommandItem.vue +40 -40
  148. package/src/components/ui/command/CommandList.vue +9 -9
  149. package/src/components/ui/command/CommandSeparator.vue +3 -3
  150. package/src/components/ui/command/CommandShortcut.vue +8 -8
  151. package/src/components/ui/command/index.ts +11 -11
  152. package/src/components/ui/data-table/DataTable.vue +145 -145
  153. package/src/components/ui/data-table/index.ts +11 -11
  154. package/src/components/ui/date-picker/DatePicker.vue +31 -31
  155. package/src/components/ui/date-time-picker/DateTimePicker.vue +97 -97
  156. package/src/components/ui/dialog/Dialog.vue +3 -3
  157. package/src/components/ui/dialog/DialogClose.vue +3 -3
  158. package/src/components/ui/dialog/DialogContent.vue +21 -21
  159. package/src/components/ui/dialog/DialogDescription.vue +7 -7
  160. package/src/components/ui/dialog/DialogFooter.vue +8 -8
  161. package/src/components/ui/dialog/DialogHeader.vue +4 -4
  162. package/src/components/ui/dialog/DialogOverlay.vue +7 -7
  163. package/src/components/ui/dialog/DialogScrollContent.vue +32 -32
  164. package/src/components/ui/dialog/DialogTitle.vue +3 -3
  165. package/src/components/ui/dialog/DialogTrigger.vue +3 -3
  166. package/src/components/ui/dropdown-menu/DropdownMenu.vue +3 -3
  167. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +11 -11
  168. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +15 -15
  169. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +3 -3
  170. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +12 -12
  171. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +9 -9
  172. package/src/components/ui/dropdown-menu/DropdownMenuPortal.vue +3 -3
  173. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +3 -3
  174. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +11 -11
  175. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +1 -1
  176. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +4 -4
  177. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +3 -3
  178. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +15 -15
  179. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +15 -15
  180. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +3 -3
  181. package/src/components/ui/dropdown-menu/classes.ts +16 -16
  182. package/src/components/ui/field/Field.vue +5 -5
  183. package/src/components/ui/field/FieldContent.vue +8 -8
  184. package/src/components/ui/field/FieldDescription.vue +10 -10
  185. package/src/components/ui/field/FieldError.vue +39 -39
  186. package/src/components/ui/field/FieldGroup.vue +8 -8
  187. package/src/components/ui/field/FieldLabel.vue +10 -10
  188. package/src/components/ui/field/FieldLegend.vue +11 -11
  189. package/src/components/ui/field/FieldSeparator.vue +11 -11
  190. package/src/components/ui/field/FieldSet.vue +9 -9
  191. package/src/components/ui/field/FieldTitle.vue +8 -8
  192. package/src/components/ui/field/field-context.ts +36 -36
  193. package/src/components/ui/field/index.ts +22 -22
  194. package/src/components/ui/file-dropzone/FileDropzone.vue +144 -144
  195. package/src/components/ui/file-dropzone/index.ts +19 -19
  196. package/src/components/ui/hover-card/HoverCard.vue +5 -5
  197. package/src/components/ui/hover-card/HoverCardContent.vue +13 -13
  198. package/src/components/ui/hover-card/HoverCardTrigger.vue +3 -3
  199. package/src/components/ui/input/Input.vue +13 -13
  200. package/src/components/ui/kbd/Kbd.vue +10 -10
  201. package/src/components/ui/kbd/KbdGroup.vue +49 -49
  202. package/src/components/ui/label/Label.vue +7 -7
  203. package/src/components/ui/native-select/NativeSelect.vue +16 -16
  204. package/src/components/ui/native-select/NativeSelectOptGroup.vue +3 -3
  205. package/src/components/ui/native-select/NativeSelectOption.vue +3 -3
  206. package/src/components/ui/number-field/NumberField.vue +88 -88
  207. package/src/components/ui/pagination/Pagination.vue +4 -4
  208. package/src/components/ui/pagination/PaginationContent.vue +4 -4
  209. package/src/components/ui/pagination/PaginationEllipsis.vue +9 -9
  210. package/src/components/ui/pagination/PaginationFirst.vue +8 -8
  211. package/src/components/ui/pagination/PaginationItem.vue +14 -14
  212. package/src/components/ui/pagination/PaginationLast.vue +8 -8
  213. package/src/components/ui/pagination/PaginationNext.vue +8 -8
  214. package/src/components/ui/pagination/PaginationPrevious.vue +8 -8
  215. package/src/components/ui/pagination/SimplePagination.vue +25 -25
  216. package/src/components/ui/pin-input/PinInput.vue +20 -20
  217. package/src/components/ui/pin-input/PinInputInput.vue +17 -17
  218. package/src/components/ui/pin-input/context.ts +1 -1
  219. package/src/components/ui/popover/Popover.vue +3 -3
  220. package/src/components/ui/popover/PopoverAnchor.vue +3 -3
  221. package/src/components/ui/popover/PopoverContent.vue +12 -12
  222. package/src/components/ui/popover/PopoverTrigger.vue +3 -3
  223. package/src/components/ui/progress/Progress.vue +16 -16
  224. package/src/components/ui/radio-group/RadioGroup.vue +7 -7
  225. package/src/components/ui/radio-group/RadioGroupCard.vue +39 -39
  226. package/src/components/ui/radio-group/RadioGroupItem.vue +20 -20
  227. package/src/components/ui/scroll-area/ScrollArea.vue +14 -14
  228. package/src/components/ui/scroll-area/ScrollBar.vue +12 -12
  229. package/src/components/ui/select/Select.vue +3 -3
  230. package/src/components/ui/select/SelectContent.vue +25 -25
  231. package/src/components/ui/select/SelectGroup.vue +3 -3
  232. package/src/components/ui/select/SelectItem.vue +24 -24
  233. package/src/components/ui/select/SelectItemContent.vue +32 -32
  234. package/src/components/ui/select/SelectItemText.vue +3 -3
  235. package/src/components/ui/select/SelectLabel.vue +3 -3
  236. package/src/components/ui/select/SelectScrollDownButton.vue +9 -9
  237. package/src/components/ui/select/SelectScrollUpButton.vue +9 -9
  238. package/src/components/ui/select/SelectSeparator.vue +2 -2
  239. package/src/components/ui/select/SelectTrigger.vue +14 -14
  240. package/src/components/ui/select/SelectValue.vue +3 -3
  241. package/src/components/ui/select/SelectValueContent.vue +39 -39
  242. package/src/components/ui/separator/Separator.vue +7 -7
  243. package/src/components/ui/sheet/Sheet.vue +3 -3
  244. package/src/components/ui/sheet/SheetClose.vue +3 -3
  245. package/src/components/ui/sheet/SheetContent.vue +22 -22
  246. package/src/components/ui/sheet/SheetDescription.vue +3 -3
  247. package/src/components/ui/sheet/SheetFooter.vue +3 -3
  248. package/src/components/ui/sheet/SheetHeader.vue +3 -3
  249. package/src/components/ui/sheet/SheetOverlay.vue +7 -7
  250. package/src/components/ui/sheet/SheetTitle.vue +3 -3
  251. package/src/components/ui/sheet/SheetTrigger.vue +3 -3
  252. package/src/components/ui/sidebar/Sidebar.vue +57 -57
  253. package/src/components/ui/sidebar/SidebarContent.vue +8 -8
  254. package/src/components/ui/sidebar/SidebarFooter.vue +8 -8
  255. package/src/components/ui/sidebar/SidebarGroup.vue +8 -8
  256. package/src/components/ui/sidebar/SidebarGroupAction.vue +9 -9
  257. package/src/components/ui/sidebar/SidebarGroupContent.vue +4 -4
  258. package/src/components/ui/sidebar/SidebarGroupLabel.vue +8 -8
  259. package/src/components/ui/sidebar/SidebarHeader.vue +8 -8
  260. package/src/components/ui/sidebar/SidebarInput.vue +8 -8
  261. package/src/components/ui/sidebar/SidebarInset.vue +9 -9
  262. package/src/components/ui/sidebar/SidebarMenu.vue +4 -4
  263. package/src/components/ui/sidebar/SidebarMenuAction.vue +18 -18
  264. package/src/components/ui/sidebar/SidebarMenuBadge.vue +14 -14
  265. package/src/components/ui/sidebar/SidebarMenuButton.vue +21 -21
  266. package/src/components/ui/sidebar/SidebarMenuButtonChild.vue +10 -10
  267. package/src/components/ui/sidebar/SidebarMenuItem.vue +4 -4
  268. package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +10 -10
  269. package/src/components/ui/sidebar/SidebarMenuSub.vue +9 -9
  270. package/src/components/ui/sidebar/SidebarMenuSubButton.vue +17 -17
  271. package/src/components/ui/sidebar/SidebarMenuSubItem.vue +4 -4
  272. package/src/components/ui/sidebar/SidebarProvider.vue +46 -46
  273. package/src/components/ui/sidebar/SidebarRail.vue +13 -13
  274. package/src/components/ui/sidebar/SidebarSeparator.vue +4 -4
  275. package/src/components/ui/sidebar/SidebarTrigger.vue +5 -5
  276. package/src/components/ui/sidebar/index.ts +29 -29
  277. package/src/components/ui/sidebar/utils.ts +7 -7
  278. package/src/components/ui/skeleton/Skeleton.vue +6 -6
  279. package/src/components/ui/slider/Slider.vue +14 -14
  280. package/src/components/ui/spinner/Spinner.vue +21 -21
  281. package/src/components/ui/stepper/SimpleStepper.vue +26 -26
  282. package/src/components/ui/stepper/Stepper.vue +6 -6
  283. package/src/components/ui/stepper/StepperDescription.vue +5 -5
  284. package/src/components/ui/stepper/StepperIndicator.vue +17 -17
  285. package/src/components/ui/stepper/StepperItem.vue +4 -4
  286. package/src/components/ui/stepper/StepperSeparator.vue +7 -7
  287. package/src/components/ui/stepper/StepperTitle.vue +5 -5
  288. package/src/components/ui/stepper/StepperTrigger.vue +4 -4
  289. package/src/components/ui/stepper/index.ts +3 -3
  290. package/src/components/ui/switch/Switch.vue +15 -15
  291. package/src/components/ui/table/Table.vue +6 -6
  292. package/src/components/ui/table/TableBody.vue +4 -4
  293. package/src/components/ui/table/TableCaption.vue +4 -4
  294. package/src/components/ui/table/TableCell.vue +8 -8
  295. package/src/components/ui/table/TableEmpty.vue +14 -14
  296. package/src/components/ui/table/TableFooter.vue +8 -8
  297. package/src/components/ui/table/TableHead.vue +8 -8
  298. package/src/components/ui/table/TableHeader.vue +4 -4
  299. package/src/components/ui/table/TableRow.vue +8 -8
  300. package/src/components/ui/tabs/Tabs.vue +4 -4
  301. package/src/components/ui/tabs/TabsContent.vue +4 -4
  302. package/src/components/ui/tabs/TabsList.vue +15 -15
  303. package/src/components/ui/tabs/TabsTrigger.vue +10 -10
  304. package/src/components/ui/tags-input/TagsInput.vue +17 -17
  305. package/src/components/ui/tags-input/TagsInputInput.vue +6 -6
  306. package/src/components/ui/tags-input/TagsInputItem.vue +15 -15
  307. package/src/components/ui/tags-input/TagsInputItemDelete.vue +12 -12
  308. package/src/components/ui/tags-input/TagsInputItemText.vue +4 -4
  309. package/src/components/ui/textarea/Textarea.vue +12 -12
  310. package/src/components/ui/time-picker/TimePicker.vue +25 -25
  311. package/src/components/ui/toggle-group/Toggle.vue +10 -10
  312. package/src/components/ui/toggle-group/ToggleGroup.vue +38 -38
  313. package/src/components/ui/toggle-group/ToggleGroupItem.vue +9 -9
  314. package/src/components/ui/toggle-group/index.ts +46 -46
  315. package/src/components/ui/tooltip/Tooltip.vue +3 -3
  316. package/src/components/ui/tooltip/TooltipContent.vue +13 -13
  317. package/src/components/ui/tooltip/TooltipProvider.vue +4 -4
  318. package/src/components/ui/tooltip/TooltipTrigger.vue +3 -3
  319. package/src/i18n/de.json +185 -185
  320. package/src/i18n/en.json +185 -185
  321. package/src/i18n/es.json +185 -185
  322. package/src/i18n/fr.json +185 -185
  323. package/src/i18n/it.json +185 -185
  324. package/src/i18n/ja.json +185 -185
  325. package/src/i18n/pt.json +185 -185
  326. package/src/i18n/ru.json +185 -185
  327. package/src/i18n/zh.json +185 -185
  328. package/src/lib/color-tokens.ts +24 -24
  329. package/src/lib/i18n.ts +65 -65
  330. package/src/lib/utils.ts +33 -33
  331. package/src/nuxt-components.d.ts +2 -2
  332. package/src/runtime/ui-vintage-i18n-plugin.ts +49 -49
  333. package/src/shims-vue.d.ts +3 -3
  334. package/src/styles.css +377 -377
@@ -4,47 +4,47 @@ import type { HugeiconsIconDefinition } from '../../lib/common-types';
4
4
  export type MessageToastType = 'success' | 'info' | 'warning' | 'error';
5
5
 
6
6
  export interface MessageToastAction {
7
- label: string;
8
- onClick: () => void | Promise<void>;
7
+ label: string;
8
+ onClick: () => void | Promise<void>;
9
9
  }
10
10
 
11
11
  export interface ShowMessageToastOptions {
12
- message: string;
13
- type?: MessageToastType;
14
- duration?: number;
15
- title?: string;
16
- icon?: HugeiconsIconDefinition | null;
17
- action?: MessageToastAction | null;
18
- dismissible?: boolean;
12
+ message: string;
13
+ type?: MessageToastType;
14
+ duration?: number;
15
+ title?: string;
16
+ icon?: HugeiconsIconDefinition | null;
17
+ action?: MessageToastAction | null;
18
+ dismissible?: boolean;
19
19
  }
20
20
 
21
21
  export interface MessageToastItem {
22
- id: number;
23
- message: string;
24
- type: MessageToastType;
25
- title: string;
26
- icon: HugeiconsIconDefinition | null;
27
- action: MessageToastAction | null;
28
- dismissible: boolean;
29
- duration: number;
22
+ id: number;
23
+ message: string;
24
+ type: MessageToastType;
25
+ title: string;
26
+ icon: HugeiconsIconDefinition | null;
27
+ action: MessageToastAction | null;
28
+ dismissible: boolean;
29
+ duration: number;
30
30
  }
31
31
 
32
32
  interface MessageToastContent {
33
- message: string;
34
- type: MessageToastType;
33
+ message: string;
34
+ type: MessageToastType;
35
35
  }
36
36
 
37
37
  interface MessageToastState {
38
- current: MessageToastContent | null;
39
- isOpen: boolean;
40
- toasts: MessageToastItem[];
41
- paused: boolean;
38
+ current: MessageToastContent | null;
39
+ isOpen: boolean;
40
+ toasts: MessageToastItem[];
41
+ paused: boolean;
42
42
  }
43
43
 
44
44
  interface ToastTimer {
45
- handle: ReturnType<typeof setTimeout> | null;
46
- remaining: number;
47
- startedAt: number;
45
+ handle: ReturnType<typeof setTimeout> | null;
46
+ remaining: number;
47
+ startedAt: number;
48
48
  }
49
49
 
50
50
  const DEFAULT_TOAST_DURATION_MS = 5000;
@@ -58,156 +58,156 @@ let nextToastId = 0;
58
58
 
59
59
  // Shared message toast state (current/isOpen are kept for backward compatibility)
60
60
  export const messageToastState: MessageToastState = reactive({
61
- current: null,
62
- isOpen: false,
63
- toasts: [],
64
- paused: false
61
+ current: null,
62
+ isOpen: false,
63
+ toasts: [],
64
+ paused: false
65
65
  });
66
66
 
67
67
  // Keep the legacy single-toast fields in sync with the stack
68
68
  const syncLegacyState = () => {
69
- const latest = messageToastState.toasts[0];
70
- messageToastState.current = latest ? { message: latest.message, type: latest.type } : null;
71
- messageToastState.isOpen = Boolean(latest);
69
+ const latest = messageToastState.toasts[0];
70
+ messageToastState.current = latest ? { message: latest.message, type: latest.type } : null;
71
+ messageToastState.isOpen = Boolean(latest);
72
72
  };
73
73
 
74
74
  // Mount the toaster once on demand
75
75
  const ensureMessageToastMounted = () => {
76
- // Skip mounting during SSR
77
- if (typeof document === 'undefined') {
78
- return Promise.resolve();
79
- }
80
-
81
- // Reuse the existing mount root
82
- if (document.getElementById(MESSAGE_TOAST_ROOT_ID)) {
83
- return Promise.resolve();
84
- }
85
-
86
- // Reuse the in-flight mount
87
- if (messageToastMountPromise) {
88
- return messageToastMountPromise;
89
- }
90
-
91
- // Start the lazy mount
92
- messageToastMountPromise = (async () => {
93
- // Load the component only when needed
94
- const { default: MessageToast } = await import('./MessageToast.vue');
95
-
96
- // Guard against a concurrent mount
97
- if (document.getElementById(MESSAGE_TOAST_ROOT_ID)) {
98
- return;
99
- }
100
-
101
- // Create the host element and render the component
102
- const container = document.createElement('div');
103
- container.id = MESSAGE_TOAST_ROOT_ID;
104
- document.body.appendChild(container);
105
- render(h(MessageToast), container);
106
- })().finally(() => {
107
- messageToastMountPromise = null;
108
- });
109
-
110
- // Let callers await the mount
111
- return messageToastMountPromise;
76
+ // Skip mounting during SSR
77
+ if (typeof document === 'undefined') {
78
+ return Promise.resolve();
79
+ }
80
+
81
+ // Reuse the existing mount root
82
+ if (document.getElementById(MESSAGE_TOAST_ROOT_ID)) {
83
+ return Promise.resolve();
84
+ }
85
+
86
+ // Reuse the in-flight mount
87
+ if (messageToastMountPromise) {
88
+ return messageToastMountPromise;
89
+ }
90
+
91
+ // Start the lazy mount
92
+ messageToastMountPromise = (async () => {
93
+ // Load the component only when needed
94
+ const { default: MessageToast } = await import('./MessageToast.vue');
95
+
96
+ // Guard against a concurrent mount
97
+ if (document.getElementById(MESSAGE_TOAST_ROOT_ID)) {
98
+ return;
99
+ }
100
+
101
+ // Create the host element and render the component
102
+ const container = document.createElement('div');
103
+ container.id = MESSAGE_TOAST_ROOT_ID;
104
+ document.body.appendChild(container);
105
+ render(h(MessageToast), container);
106
+ })().finally(() => {
107
+ messageToastMountPromise = null;
108
+ });
109
+
110
+ // Let callers await the mount
111
+ return messageToastMountPromise;
112
112
  };
113
113
 
114
114
  // Start (or restart) the auto-dismiss countdown of a toast
115
115
  const startToastTimer = (id: number) => {
116
- const timer = toastTimers.get(id);
117
- if (!timer || timer.handle || messageToastState.paused) return;
118
- timer.startedAt = Date.now();
119
- timer.handle = setTimeout(() => closeMessageToast(id), timer.remaining);
116
+ const timer = toastTimers.get(id);
117
+ if (!timer || timer.handle || messageToastState.paused) return;
118
+ timer.startedAt = Date.now();
119
+ timer.handle = setTimeout(() => closeMessageToast(id), timer.remaining);
120
120
  };
121
121
 
122
122
  // Stop the countdown of a toast and remember how much time is left
123
123
  const stopToastTimer = (id: number) => {
124
- const timer = toastTimers.get(id);
125
- if (!timer?.handle) return;
126
- clearTimeout(timer.handle);
127
- timer.handle = null;
128
- timer.remaining = Math.max(0, timer.remaining - (Date.now() - timer.startedAt));
124
+ const timer = toastTimers.get(id);
125
+ if (!timer?.handle) return;
126
+ clearTimeout(timer.handle);
127
+ timer.handle = null;
128
+ timer.remaining = Math.max(0, timer.remaining - (Date.now() - timer.startedAt));
129
129
  };
130
130
 
131
131
  // Pause every countdown (used while the toaster is hovered or focused)
132
132
  export const pauseMessageToasts = () => {
133
- messageToastState.paused = true;
134
- toastTimers.forEach((_, id) => stopToastTimer(id));
133
+ messageToastState.paused = true;
134
+ toastTimers.forEach((_, id) => stopToastTimer(id));
135
135
  };
136
136
 
137
137
  // Resume every countdown
138
138
  export const resumeMessageToasts = () => {
139
- messageToastState.paused = false;
140
- toastTimers.forEach((_, id) => startToastTimer(id));
139
+ messageToastState.paused = false;
140
+ toastTimers.forEach((_, id) => startToastTimer(id));
141
141
  };
142
142
 
143
143
  // Dismiss one toast by id, or every toast when no id is passed
144
144
  export const closeMessageToast = (id?: number) => {
145
- const ids = id === undefined ? messageToastState.toasts.map(toast => toast.id) : [id];
146
-
147
- // Cancel toasts that were requested but are still waiting for the toaster to mount
148
- if (id === undefined) {
149
- pendingToastIds.clear();
150
- } else {
151
- pendingToastIds.delete(id);
152
- }
153
-
154
- // Clear timers and remove the toasts from the stack
155
- for (const toastId of ids) {
156
- stopToastTimer(toastId);
157
- toastTimers.delete(toastId);
158
- }
159
- messageToastState.toasts = messageToastState.toasts.filter(toast => !ids.includes(toast.id));
160
- syncLegacyState();
145
+ const ids = id === undefined ? messageToastState.toasts.map(toast => toast.id) : [id];
146
+
147
+ // Cancel toasts that were requested but are still waiting for the toaster to mount
148
+ if (id === undefined) {
149
+ pendingToastIds.clear();
150
+ } else {
151
+ pendingToastIds.delete(id);
152
+ }
153
+
154
+ // Clear timers and remove the toasts from the stack
155
+ for (const toastId of ids) {
156
+ stopToastTimer(toastId);
157
+ toastTimers.delete(toastId);
158
+ }
159
+ messageToastState.toasts = messageToastState.toasts.filter(toast => !ids.includes(toast.id));
160
+ syncLegacyState();
161
161
  };
162
162
 
163
163
  // Show a message toast and optionally auto-dismiss it; returns the toast id
164
164
  export const showMessageToast = (options: ShowMessageToastOptions) => {
165
- nextToastId += 1;
166
- const id = nextToastId;
167
- const duration = options.duration ?? DEFAULT_TOAST_DURATION_MS;
168
-
169
- // Build the toast item
170
- const toast: MessageToastItem = {
171
- id,
172
- message: options.message,
173
- type: options.type ?? 'success',
174
- title: options.title ?? '',
175
- icon: options.icon ? markRaw(options.icon) : null,
176
- action: options.action ?? null,
177
- dismissible: options.dismissible ?? true,
178
- duration
179
- };
180
-
181
- // Toasts are client-only: never store them in the module state shared across server requests
182
- if (typeof document === 'undefined') {
183
- return id;
184
- }
185
-
186
- // Expose the newest toast synchronously, as the single-toast API always did
187
- messageToastState.current = { message: toast.message, type: toast.type };
188
-
189
- // Mount first so the enter transition runs once the renderer exists
190
- pendingToastIds.add(id);
191
- void ensureMessageToastMounted().then(() => {
192
- // Skip toasts that were closed before the toaster finished mounting
193
- if (!pendingToastIds.delete(id)) {
194
- syncLegacyState();
195
- return;
196
- }
197
-
198
- // Push the newest toast on top and trim the overflow
199
- messageToastState.toasts = [toast, ...messageToastState.toasts];
200
- for (const overflow of messageToastState.toasts.slice(MAX_TOASTS)) {
201
- closeMessageToast(overflow.id);
202
- }
203
- syncLegacyState();
204
-
205
- // Auto-dismiss the toast after the specified duration
206
- if (duration > 0) {
207
- toastTimers.set(id, { handle: null, remaining: duration, startedAt: Date.now() });
208
- startToastTimer(id);
209
- }
210
- });
211
-
212
- return id;
165
+ nextToastId += 1;
166
+ const id = nextToastId;
167
+ const duration = options.duration ?? DEFAULT_TOAST_DURATION_MS;
168
+
169
+ // Build the toast item
170
+ const toast: MessageToastItem = {
171
+ id,
172
+ message: options.message,
173
+ type: options.type ?? 'success',
174
+ title: options.title ?? '',
175
+ icon: options.icon ? markRaw(options.icon) : null,
176
+ action: options.action ?? null,
177
+ dismissible: options.dismissible ?? true,
178
+ duration
179
+ };
180
+
181
+ // Toasts are client-only: never store them in the module state shared across server requests
182
+ if (typeof document === 'undefined') {
183
+ return id;
184
+ }
185
+
186
+ // Expose the newest toast synchronously, as the single-toast API always did
187
+ messageToastState.current = { message: toast.message, type: toast.type };
188
+
189
+ // Mount first so the enter transition runs once the renderer exists
190
+ pendingToastIds.add(id);
191
+ void ensureMessageToastMounted().then(() => {
192
+ // Skip toasts that were closed before the toaster finished mounting
193
+ if (!pendingToastIds.delete(id)) {
194
+ syncLegacyState();
195
+ return;
196
+ }
197
+
198
+ // Push the newest toast on top and trim the overflow
199
+ messageToastState.toasts = [toast, ...messageToastState.toasts];
200
+ for (const overflow of messageToastState.toasts.slice(MAX_TOASTS)) {
201
+ closeMessageToast(overflow.id);
202
+ }
203
+ syncLegacyState();
204
+
205
+ // Auto-dismiss the toast after the specified duration
206
+ if (duration > 0) {
207
+ toastTimers.set(id, { handle: null, remaining: duration, startedAt: Date.now() });
208
+ startToastTimer(id);
209
+ }
210
+ });
211
+
212
+ return id;
213
213
  };
@@ -3,53 +3,53 @@ import { Comment, Text, computed, useSlots, type VNode } from 'vue';
3
3
 
4
4
  // Props
5
5
  const props = withDefaults(defineProps<{
6
- title: string;
7
- headingLevel?: number;
8
- size?: 'small' | 'medium' | 'large';
6
+ title: string;
7
+ headingLevel?: number;
8
+ size?: 'small' | 'medium' | 'large';
9
9
  }>(), {
10
- headingLevel: 1,
11
- size: 'large'
10
+ headingLevel: 1,
11
+ size: 'large'
12
12
  });
13
13
 
14
14
  const slots = useSlots();
15
15
 
16
16
  // Check if there is content in the default slot
17
17
  const hasSlotContent = computed(() => {
18
- if (!slots.default) return false;
19
-
20
- // Check if the slot has any non-empty content
21
- return slots.default({}).some((vnode: VNode) => {
22
- if (vnode.type === Comment) return false;
23
- if (vnode.type === Text && typeof vnode.children === 'string' && !vnode.children.trim()) return false;
24
- return true;
25
- });
18
+ if (!slots.default) return false;
19
+
20
+ // Check if the slot has any non-empty content
21
+ return slots.default({}).some((vnode: VNode) => {
22
+ if (vnode.type === Comment) return false;
23
+ if (vnode.type === Text && typeof vnode.children === 'string' && !vnode.children.trim()) return false;
24
+ return true;
25
+ });
26
26
  });
27
27
 
28
28
  // Get size classes based on size prop
29
29
  const getSizeClasses = (size: string) => {
30
- const baseClasses = 'font-semibold tracking-tight text-foreground';
31
-
32
- // Return classes based on size
33
- switch (size) {
34
- case 'small':
35
- return `${baseClasses} text-base md:text-xl`;
36
- case 'medium':
37
- return `${baseClasses} text-lg md:text-2xl`;
38
- case 'large':
39
- default:
40
- return `${baseClasses} text-xl md:text-3xl`;
41
- }
30
+ const baseClasses = 'font-semibold tracking-tight text-foreground';
31
+
32
+ // Return classes based on size
33
+ switch (size) {
34
+ case 'small':
35
+ return `${baseClasses} text-base md:text-xl`;
36
+ case 'medium':
37
+ return `${baseClasses} text-lg md:text-2xl`;
38
+ case 'large':
39
+ default:
40
+ return `${baseClasses} text-xl md:text-3xl`;
41
+ }
42
42
  };
43
43
  </script>
44
44
 
45
45
  <template>
46
- <div class="flex flex-col gap-3 mb-6 sm:flex-row sm:justify-between sm:items-center sm:min-h-12 sm:gap-0">
47
- <!-- Title -->
48
- <component :is="`h${headingLevel}`" :class="getSizeClasses(props.size)">{{ props.title }}</component>
49
-
50
- <!-- Right section -->
51
- <div v-if="hasSlotContent" class="w-full sm:w-auto">
52
- <slot />
53
- </div>
54
- </div>
46
+ <div class="flex flex-col gap-3 mb-6 sm:flex-row sm:justify-between sm:items-center sm:min-h-12 sm:gap-0">
47
+ <!-- Title -->
48
+ <component :is="`h${headingLevel}`" :class="getSizeClasses(props.size)">{{ props.title }}</component>
49
+
50
+ <!-- Right section -->
51
+ <div v-if="hasSlotContent" class="w-full sm:w-auto">
52
+ <slot />
53
+ </div>
54
+ </div>
55
55
  </template>
@@ -4,14 +4,14 @@ import { Progress } from '../ui/progress';
4
4
 
5
5
  // Props
6
6
  const props = withDefaults(defineProps<{
7
- title: string;
8
- bottomLeftLabel?: string;
9
- bottomRightLabel?: string;
10
- value: number;
11
- max: number;
7
+ title: string;
8
+ bottomLeftLabel?: string;
9
+ bottomRightLabel?: string;
10
+ value: number;
11
+ max: number;
12
12
  }>(), {
13
- bottomLeftLabel: '',
14
- bottomRightLabel: ''
13
+ bottomLeftLabel: '',
14
+ bottomRightLabel: ''
15
15
  });
16
16
 
17
17
  // Name the progress bar after the visible title
@@ -19,34 +19,34 @@ const titleId = useId();
19
19
  </script>
20
20
 
21
21
  <template>
22
- <div class="space-y-3">
23
- <!-- Header with label and value -->
24
- <div class="flex items-center justify-between">
25
- <!-- Title of the progress bar -->
26
- <span :id="titleId" class="text-sm font-semibold text-foreground">
27
- {{ props.title }}
28
- </span>
22
+ <div class="space-y-3">
23
+ <!-- Header with label and value -->
24
+ <div class="flex items-center justify-between">
25
+ <!-- Title of the progress bar -->
26
+ <span :id="titleId" class="text-sm font-semibold text-foreground">
27
+ {{ props.title }}
28
+ </span>
29
29
 
30
- <!-- Current value / max -->
31
- <span class="text-sm font-semibold text-foreground">
32
- {{ props.value }} / {{ props.max }}
33
- </span>
34
- </div>
30
+ <!-- Current value / max -->
31
+ <span class="text-sm font-semibold text-foreground">
32
+ {{ props.value }} / {{ props.max }}
33
+ </span>
34
+ </div>
35
35
 
36
- <!-- Progress bar -->
37
- <Progress :model-value="props.value" :max="props.max" :aria-labelledby="titleId" />
36
+ <!-- Progress bar -->
37
+ <Progress :model-value="props.value" :max="props.max" :aria-labelledby="titleId" />
38
38
 
39
- <!-- Bottom labels -->
40
- <div v-if="props.bottomLeftLabel || props.bottomRightLabel" class="flex items-center justify-between text-xs">
41
- <!-- Bottom left label -->
42
- <span v-if="props.bottomLeftLabel" class="text-muted-foreground">
43
- {{ props.bottomLeftLabel }}
44
- </span>
39
+ <!-- Bottom labels -->
40
+ <div v-if="props.bottomLeftLabel || props.bottomRightLabel" class="flex items-center justify-between text-xs">
41
+ <!-- Bottom left label -->
42
+ <span v-if="props.bottomLeftLabel" class="text-muted-foreground">
43
+ {{ props.bottomLeftLabel }}
44
+ </span>
45
45
 
46
- <!-- Bottom right label -->
47
- <span v-if="props.bottomRightLabel" class="text-muted-foreground">
48
- {{ props.bottomRightLabel }}
49
- </span>
50
- </div>
51
- </div>
46
+ <!-- Bottom right label -->
47
+ <span v-if="props.bottomRightLabel" class="text-muted-foreground">
48
+ {{ props.bottomRightLabel }}
49
+ </span>
50
+ </div>
51
+ </div>
52
52
  </template>
@@ -11,37 +11,37 @@ import type { HugeiconsIconDefinition } from '../../lib/common-types';
11
11
 
12
12
  // Props
13
13
  const props = withDefaults(defineProps<{
14
- value: string | number;
15
- label: string;
16
- icon: HugeiconsIconDefinition;
17
- valueColor?: 'default' | 'green' | 'red' | 'gray';
18
- trend?: number | null;
19
- trendLabel?: string;
20
- description?: string;
21
- animate?: boolean;
22
- formatOptions?: Intl.NumberFormatOptions;
23
- class?: HTMLAttributes['class'];
14
+ value: string | number;
15
+ label: string;
16
+ icon: HugeiconsIconDefinition;
17
+ valueColor?: 'default' | 'green' | 'red' | 'gray';
18
+ trend?: number | null;
19
+ trendLabel?: string;
20
+ description?: string;
21
+ animate?: boolean;
22
+ formatOptions?: Intl.NumberFormatOptions;
23
+ class?: HTMLAttributes['class'];
24
24
  }>(), {
25
- valueColor: 'default',
26
- trend: null,
27
- trendLabel: '',
28
- description: '',
29
- animate: true,
30
- formatOptions: undefined
25
+ valueColor: 'default',
26
+ trend: null,
27
+ trendLabel: '',
28
+ description: '',
29
+ animate: true,
30
+ formatOptions: undefined
31
31
  });
32
32
 
33
33
  // Value classes
34
34
  const valueClass = computed(() => {
35
- switch (props.valueColor) {
36
- case 'green':
37
- return 'text-success';
38
- case 'red':
39
- return 'text-destructive';
40
- case 'gray':
41
- return 'text-muted-foreground';
42
- default:
43
- return 'text-foreground';
44
- }
35
+ switch (props.valueColor) {
36
+ case 'green':
37
+ return 'text-success';
38
+ case 'red':
39
+ return 'text-destructive';
40
+ case 'gray':
41
+ return 'text-muted-foreground';
42
+ default:
43
+ return 'text-foreground';
44
+ }
45
45
  });
46
46
 
47
47
  // Trend badge presentation
@@ -53,37 +53,37 @@ const staticValue = computed(() => typeof props.value === 'number' && props.form
53
53
  </script>
54
54
 
55
55
  <template>
56
- <Card :class="cn('gap-0! p-4!', props.class)">
57
- <!-- Label and icon -->
58
- <div class="flex items-start justify-between gap-3">
59
- <span class="min-w-0 text-[11px] font-semibold leading-5 tracking-wider text-muted-foreground uppercase">
60
- {{ props.label }}
61
- </span>
62
- <span aria-hidden="true" class="flex size-8 shrink-0 items-center justify-center rounded border border-primary/30 text-primary">
63
- <HugeiconsIcon :icon="props.icon" class="size-4" />
64
- </span>
65
- </div>
56
+ <Card :class="cn('gap-0! p-4!', props.class)">
57
+ <!-- Label and icon -->
58
+ <div class="flex items-start justify-between gap-3">
59
+ <span class="min-w-0 text-[11px] font-semibold leading-5 tracking-wider text-muted-foreground uppercase">
60
+ {{ props.label }}
61
+ </span>
62
+ <span aria-hidden="true" class="flex size-8 shrink-0 items-center justify-center rounded border border-primary/30 text-primary">
63
+ <HugeiconsIcon :icon="props.icon" class="size-4" />
64
+ </span>
65
+ </div>
66
66
 
67
- <!-- Value and trend -->
68
- <div class="mt-1 flex flex-wrap items-baseline gap-x-2 gap-y-1">
69
- <span :class="['text-2xl font-semibold tracking-tight tabular-nums', valueClass]">
70
- <AnimatedNumber v-if="props.animate && typeof props.value === 'number'" :value="props.value" :format-options="props.formatOptions" />
71
- <template v-else>{{ staticValue }}</template>
72
- </span>
67
+ <!-- Value and trend -->
68
+ <div class="mt-1 flex flex-wrap items-baseline gap-x-2 gap-y-1">
69
+ <span :class="['text-2xl font-semibold tracking-tight tabular-nums', valueClass]">
70
+ <AnimatedNumber v-if="props.animate && typeof props.value === 'number'" :value="props.value" :format-options="props.formatOptions" />
71
+ <template v-else>{{ staticValue }}</template>
72
+ </span>
73
73
 
74
- <!-- Trend badge -->
75
- <span v-if="props.trend !== null" :class="cn('inline-flex items-center gap-0.5 rounded-sm px-1 py-0.5 text-[11px] font-semibold tabular-nums', trendIsPositive ? 'bg-success/10 text-success' : 'bg-destructive/10 text-destructive')">
76
- <HugeiconsIcon :icon="trendIsPositive ? ArrowUpRight01Icon : ArrowDownRight01Icon" class="size-3" />
77
- {{ formattedTrend }}
78
- </span>
79
- <span v-if="props.trend !== null && props.trendLabel" class="text-[11px] text-muted-foreground">
80
- {{ props.trendLabel }}
81
- </span>
82
- </div>
74
+ <!-- Trend badge -->
75
+ <span v-if="props.trend !== null" :class="cn('inline-flex items-center gap-0.5 rounded-sm px-1 py-0.5 text-[11px] font-semibold tabular-nums', trendIsPositive ? 'bg-success/10 text-success' : 'bg-destructive/10 text-destructive')">
76
+ <HugeiconsIcon :icon="trendIsPositive ? ArrowUpRight01Icon : ArrowDownRight01Icon" class="size-3" />
77
+ {{ formattedTrend }}
78
+ </span>
79
+ <span v-if="props.trend !== null && props.trendLabel" class="text-[11px] text-muted-foreground">
80
+ {{ props.trendLabel }}
81
+ </span>
82
+ </div>
83
83
 
84
- <!-- Description -->
85
- <span v-if="props.description" class="mt-1 text-xs leading-5 text-muted-foreground">
86
- {{ props.description }}
87
- </span>
88
- </Card>
89
- </template>
84
+ <!-- Description -->
85
+ <span v-if="props.description" class="mt-1 text-xs leading-5 text-muted-foreground">
86
+ {{ props.description }}
87
+ </span>
88
+ </Card>
89
+ </template>