@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
@@ -11,15 +11,15 @@ import { formatDateLongItalyTimezone } from '../../lib/utils';
11
11
 
12
12
  // Props
13
13
  const props = withDefaults(defineProps<{
14
- author: string;
15
- authorUrl: string;
16
- authorImageUrl: string;
17
- authorBio?: string;
18
- datePublished: string;
19
- dateModified?: string | null;
14
+ author: string;
15
+ authorUrl: string;
16
+ authorImageUrl: string;
17
+ authorBio?: string;
18
+ datePublished: string;
19
+ dateModified?: string | null;
20
20
  }>(), {
21
- authorBio: '',
22
- dateModified: null
21
+ authorBio: '',
22
+ dateModified: null
23
23
  });
24
24
 
25
25
  const { t, locale } = useI18n();
@@ -33,46 +33,46 @@ const showModifiedDate = computed(() => Boolean(props.dateModified) && formatted
33
33
  </script>
34
34
 
35
35
  <template>
36
- <!-- Author and date information -->
37
- <Card data-aos="blur-up" class="gap-0! overflow-hidden p-0!">
38
- <!-- Author -->
39
- <div :class="['flex gap-3 px-5 py-4', props.authorBio ? 'items-start' : 'items-center']">
40
- <!-- Author image -->
41
- <NuxtLink :to="props.authorUrl" target="_blank" rel="noopener noreferrer" class="shrink-0 rounded outline-none focus-visible:ring-[3px] focus-visible:ring-ring/45">
42
- <NuxtImg :src="props.authorImageUrl" :alt="props.author" height="44" width="44" format="avif" quality="40" :sizes="{ 480: '44px', 1280: '44px' }" loading="lazy" decoding="async" class="size-11 rounded border border-border object-cover" />
43
- </NuxtLink>
36
+ <!-- Author and date information -->
37
+ <Card data-aos="blur-up" class="gap-0! overflow-hidden p-0!">
38
+ <!-- Author -->
39
+ <div :class="['flex gap-3 px-5 py-4', props.authorBio ? 'items-start' : 'items-center']">
40
+ <!-- Author image -->
41
+ <NuxtLink :to="props.authorUrl" target="_blank" rel="noopener noreferrer" class="shrink-0 rounded outline-none focus-visible:ring-[3px] focus-visible:ring-ring/45">
42
+ <NuxtImg :src="props.authorImageUrl" :alt="props.author" height="44" width="44" format="avif" quality="40" :sizes="{ 480: '44px', 1280: '44px' }" loading="lazy" decoding="async" class="size-11 rounded border border-border object-cover" />
43
+ </NuxtLink>
44
44
 
45
- <!-- Author name and bio -->
46
- <div class="min-w-0 flex-1">
47
- <p class="text-[11px] font-semibold tracking-wider text-muted-foreground uppercase">{{ t('uiVintage.blog.author') }}</p>
48
- <NuxtLink :to="props.authorUrl" target="_blank" rel="noopener noreferrer" class="group/link inline-flex items-center gap-1 text-sm font-semibold text-foreground outline-none transition-colors hover:text-primary focus-visible:underline md:text-base">
49
- {{ props.author }}
50
- <HugeiconsIcon :icon="ArrowUpRight01Icon" class="size-4 text-muted-foreground transition-[translate,color] duration-300 ease-spring group-hover/link:translate-x-0.5 group-hover/link:-translate-y-0.5 group-hover/link:text-primary" />
51
- </NuxtLink>
52
- <p v-if="props.authorBio" class="mt-1.5 text-xs leading-relaxed text-muted-foreground md:text-sm">
53
- {{ props.authorBio }}
54
- </p>
55
- </div>
56
- </div>
45
+ <!-- Author name and bio -->
46
+ <div class="min-w-0 flex-1">
47
+ <p class="text-[11px] font-semibold tracking-wider text-muted-foreground uppercase">{{ t('uiVintage.blog.author') }}</p>
48
+ <NuxtLink :to="props.authorUrl" target="_blank" rel="noopener noreferrer" class="group/link inline-flex items-center gap-1 text-sm font-semibold text-foreground outline-none transition-colors hover:text-primary focus-visible:underline md:text-base">
49
+ {{ props.author }}
50
+ <HugeiconsIcon :icon="ArrowUpRight01Icon" class="size-4 text-muted-foreground transition-[translate,color] duration-300 ease-spring group-hover/link:translate-x-0.5 group-hover/link:-translate-y-0.5 group-hover/link:text-primary" />
51
+ </NuxtLink>
52
+ <p v-if="props.authorBio" class="mt-1.5 text-xs leading-relaxed text-muted-foreground md:text-sm">
53
+ {{ props.authorBio }}
54
+ </p>
55
+ </div>
56
+ </div>
57
57
 
58
- <!-- Date information -->
59
- <div v-if="props.datePublished || showModifiedDate" class="flex flex-wrap items-center gap-x-5 gap-y-2 border-t border-border bg-surface px-5 py-2.5 text-xs text-muted-foreground">
60
- <!-- Published date -->
61
- <span v-if="props.datePublished" class="inline-flex items-center gap-2">
62
- <HugeiconsIcon :icon="Calendar03Icon" class="size-3.5 shrink-0 text-primary" />
63
- {{ t('uiVintage.blog.publishedDate') }}
64
- <time :datetime="props.datePublished" class="text-foreground">{{ formattedPublishedDate }}</time>
65
- </span>
58
+ <!-- Date information -->
59
+ <div v-if="props.datePublished || showModifiedDate" class="flex flex-wrap items-center gap-x-5 gap-y-2 border-t border-border bg-surface px-5 py-2.5 text-xs text-muted-foreground">
60
+ <!-- Published date -->
61
+ <span v-if="props.datePublished" class="inline-flex items-center gap-2">
62
+ <HugeiconsIcon :icon="Calendar03Icon" class="size-3.5 shrink-0 text-primary" />
63
+ {{ t('uiVintage.blog.publishedDate') }}
64
+ <time :datetime="props.datePublished" class="text-foreground">{{ formattedPublishedDate }}</time>
65
+ </span>
66
66
 
67
- <!-- Divider between the dates (hidden when they wrap on small screens) -->
68
- <span v-if="props.datePublished && showModifiedDate" aria-hidden="true" class="hidden h-3.5 w-px bg-border sm:block" />
67
+ <!-- Divider between the dates (hidden when they wrap on small screens) -->
68
+ <span v-if="props.datePublished && showModifiedDate" aria-hidden="true" class="hidden h-3.5 w-px bg-border sm:block" />
69
69
 
70
- <!-- Last updated date -->
71
- <span v-if="showModifiedDate" class="inline-flex items-center gap-2">
72
- <HugeiconsIcon :icon="RefreshIcon" class="size-3.5 shrink-0 text-primary" />
73
- {{ t('uiVintage.blog.lastUpdatedDate') }}
74
- <time :datetime="props.dateModified ?? undefined" class="text-foreground">{{ formattedModifiedDate }}</time>
75
- </span>
76
- </div>
77
- </Card>
78
- </template>
70
+ <!-- Last updated date -->
71
+ <span v-if="showModifiedDate" class="inline-flex items-center gap-2">
72
+ <HugeiconsIcon :icon="RefreshIcon" class="size-3.5 shrink-0 text-primary" />
73
+ {{ t('uiVintage.blog.lastUpdatedDate') }}
74
+ <time :datetime="props.dateModified ?? undefined" class="text-foreground">{{ formattedModifiedDate }}</time>
75
+ </span>
76
+ </div>
77
+ </Card>
78
+ </template>
@@ -8,36 +8,36 @@ import { formatDateLongItalyTimezone, getReadingMinutes } from '../../lib/utils'
8
8
 
9
9
  // Props
10
10
  const props = withDefaults(defineProps<{
11
- title: string;
12
- description?: string;
13
- image?: string;
14
- author?: string;
15
- authorImageUrl?: string;
16
- datePublished?: string;
17
- categoryText?: string;
18
- categorySlug?: string;
19
- tags?: Array<{
20
- name: string;
21
- slug: string;
22
- }>;
23
- body?: unknown;
24
- readingMinutes?: number | null;
25
- blogPath?: string;
26
- blogLabel?: string;
27
- animated?: boolean;
11
+ title: string;
12
+ description?: string;
13
+ image?: string;
14
+ author?: string;
15
+ authorImageUrl?: string;
16
+ datePublished?: string;
17
+ categoryText?: string;
18
+ categorySlug?: string;
19
+ tags?: Array<{
20
+ name: string;
21
+ slug: string;
22
+ }>;
23
+ body?: unknown;
24
+ readingMinutes?: number | null;
25
+ blogPath?: string;
26
+ blogLabel?: string;
27
+ animated?: boolean;
28
28
  }>(), {
29
- description: '',
30
- image: '',
31
- author: '',
32
- authorImageUrl: '',
33
- datePublished: '',
34
- categoryText: '',
35
- categorySlug: '',
36
- tags: () => [],
37
- readingMinutes: null,
38
- blogPath: '/blog',
39
- blogLabel: '',
40
- animated: true
29
+ description: '',
30
+ image: '',
31
+ author: '',
32
+ authorImageUrl: '',
33
+ datePublished: '',
34
+ categoryText: '',
35
+ categorySlug: '',
36
+ tags: () => [],
37
+ readingMinutes: null,
38
+ blogPath: '/blog',
39
+ blogLabel: '',
40
+ animated: true
41
41
  });
42
42
 
43
43
  const { t, locale } = useI18n();
@@ -50,8 +50,8 @@ const formattedDate = computed(() => formatDateLongItalyTimezone(props.datePubli
50
50
 
51
51
  // Explicit reading time wins, otherwise estimate it from the body
52
52
  const resolvedReadingMinutes = computed(() => {
53
- if (props.readingMinutes) return props.readingMinutes;
54
- return props.body ? getReadingMinutes(props.body) : null;
53
+ if (props.readingMinutes) return props.readingMinutes;
54
+ return props.body ? getReadingMinutes(props.body) : null;
55
55
  });
56
56
 
57
57
  // Links built from the blog base path
@@ -75,107 +75,107 @@ const detailLabelClasses = 'text-[11px] font-semibold tracking-wider text-muted-
75
75
  </script>
76
76
 
77
77
  <template>
78
- <header class="relative isolate mb-10 md:mb-14">
79
- <!-- Breadcrumbs -->
80
- <Breadcrumb :class="enter('animate-uv-fade-up')">
81
- <BreadcrumbList>
82
- <BreadcrumbItem>
83
- <BreadcrumbLink as-child>
84
- <NuxtLinkLocale :to="props.blogPath">
85
- {{ props.blogLabel || t('uiVintage.blog.breadcrumbBlog') }}
86
- </NuxtLinkLocale>
87
- </BreadcrumbLink>
88
- </BreadcrumbItem>
89
- <BreadcrumbSeparator />
90
- <template v-if="hasCategory">
91
- <BreadcrumbItem>
92
- <BreadcrumbLink as-child>
93
- <NuxtLinkLocale :to="categoryPath">
94
- {{ props.categoryText }}
95
- </NuxtLinkLocale>
96
- </BreadcrumbLink>
97
- </BreadcrumbItem>
98
- <BreadcrumbSeparator />
99
- </template>
100
- <BreadcrumbItem class="min-w-0">
101
- <BreadcrumbPage class="truncate">
102
- {{ props.title }}
103
- </BreadcrumbPage>
104
- </BreadcrumbItem>
105
- </BreadcrumbList>
106
- </Breadcrumb>
107
-
108
- <!-- Title and lede, closed by a rule with a primary segment -->
109
- <div class="relative mt-8 border-b border-border pb-8">
110
- <span aria-hidden="true" :class="['absolute -bottom-px left-0 h-0.5 w-20 origin-left bg-primary', enter('animate-uv-grow-x')]" :style="props.animated ? { animationDelay: '500ms' } : undefined" />
111
-
112
- <!-- Title (each word rises in) -->
113
- <h1 class="text-3xl leading-[1.08] font-semibold tracking-tight text-foreground sm:text-4xl md:text-5xl">
114
- <template v-for="(word, index) in titleWords" :key="`${word}-${index}`">
115
- <span :class="['inline-block', enter('animate-uv-word-in')]" :style="props.animated ? { animationDelay: `${120 + Math.min(index, 12) * 50}ms` } : undefined">{{ word }}</span>{{ index < titleWords.length - 1 ? ' ' : '' }}
116
- </template>
117
- </h1>
118
-
119
- <!-- Lede -->
120
- <p v-if="props.description" :class="['mt-5 max-w-3xl text-sm leading-relaxed text-muted-foreground md:text-lg', enter('animate-uv-fade-up [animation-delay:450ms]')]">
121
- {{ props.description }}
122
- </p>
123
- </div>
124
-
125
- <!-- Labelled details (columns without data are left out; the meta slot adds more) -->
126
- <div v-if="hasDetails || $slots.meta" :class="['overflow-hidden border-b border-border', enter('animate-uv-fade-up [animation-delay:550ms]')]">
127
- <dl class="-mt-px -ml-[calc(1rem+1px)] grid grid-cols-2 md:grid-flow-col md:auto-cols-fr md:grid-cols-none">
128
- <!-- Author -->
129
- <div v-if="props.author" :class="detailCellClasses">
130
- <dt :class="detailLabelClasses">{{ t('uiVintage.blog.author') }}</dt>
131
- <dd class="mt-2 flex min-w-0 items-center gap-2 text-sm font-semibold text-foreground">
132
- <NuxtImg v-if="props.authorImageUrl" :src="props.authorImageUrl" :alt="props.author" width="24" height="24" format="avif" quality="40" class="size-6 shrink-0 rounded border border-border object-cover" />
133
- <span class="truncate">{{ props.author }}</span>
134
- </dd>
135
- </div>
136
-
137
- <!-- Publication date -->
138
- <div v-if="formattedDate" :class="detailCellClasses">
139
- <dt :class="detailLabelClasses">{{ t('uiVintage.blog.publishedDate') }}</dt>
140
- <dd class="mt-2 text-sm text-foreground">
141
- <time :datetime="props.datePublished">{{ formattedDate }}</time>
142
- </dd>
143
- </div>
144
-
145
- <!-- Reading time -->
146
- <div v-if="resolvedReadingMinutes" :class="detailCellClasses">
147
- <dt :class="detailLabelClasses">{{ t('uiVintage.blog.readingTime') }}</dt>
148
- <dd class="mt-2 text-sm text-foreground">{{ t('uiVintage.blog.readingTimeValue', { minutes: resolvedReadingMinutes }) }}</dd>
149
- </div>
150
-
151
- <!-- Category -->
152
- <div v-if="hasCategory" :class="detailCellClasses">
153
- <dt :class="detailLabelClasses">{{ t('uiVintage.blog.category') }}</dt>
154
- <dd class="mt-1.5">
155
- <NuxtLinkLocale :to="categoryPath" :class="['inline-flex', badgeLinkClasses]">
156
- <Badge color="yellow" :text="props.categoryText" pulse />
157
- </NuxtLinkLocale>
158
- </dd>
159
- </div>
160
-
161
- <!-- Extra columns from the app (use the same cell structure: a div with a dt and a dd) -->
162
- <slot name="meta" :cell-classes="detailCellClasses" :label-classes="detailLabelClasses" />
163
- </dl>
164
- </div>
165
-
166
- <!-- Tags -->
167
- <div v-if="props.tags.length > 0" :class="['mt-4 flex flex-wrap items-center gap-2', enter('animate-uv-fade-up [animation-delay:600ms]')]">
168
- <NuxtLinkLocale v-for="tag in props.tags" :key="tag.slug" :to="tagPath(tag.slug)" :class="badgeLinkClasses">
169
- <Badge :text="`#${tag.name}`" />
170
- </NuxtLinkLocale>
171
- </div>
172
-
173
- <!-- Featured image (replaceable through the media slot) -->
174
- <slot name="media">
175
- <div v-if="props.image" :class="['relative mt-8 aspect-video w-full overflow-hidden rounded border border-border shadow-elevated-xl', enter('animate-uv-fade-up [animation-delay:650ms]')]">
176
- <NuxtImg :src="props.image" :alt="props.title" format="avif" quality="50" :sizes="{ 480: '480px', 1536: '896px' }" loading="eager" fetchpriority="high" preload :class="['size-full object-cover', enter('animate-uv-ken-burns')]" />
177
- <div aria-hidden="true" class="pointer-events-none absolute inset-0 bg-linear-to-t from-black/20 to-transparent" />
178
- </div>
179
- </slot>
180
- </header>
181
- </template>
78
+ <header class="relative isolate mb-10 md:mb-14">
79
+ <!-- Breadcrumbs -->
80
+ <Breadcrumb :class="enter('animate-uv-fade-up')">
81
+ <BreadcrumbList>
82
+ <BreadcrumbItem>
83
+ <BreadcrumbLink as-child>
84
+ <NuxtLinkLocale :to="props.blogPath">
85
+ {{ props.blogLabel || t('uiVintage.blog.breadcrumbBlog') }}
86
+ </NuxtLinkLocale>
87
+ </BreadcrumbLink>
88
+ </BreadcrumbItem>
89
+ <BreadcrumbSeparator />
90
+ <template v-if="hasCategory">
91
+ <BreadcrumbItem>
92
+ <BreadcrumbLink as-child>
93
+ <NuxtLinkLocale :to="categoryPath">
94
+ {{ props.categoryText }}
95
+ </NuxtLinkLocale>
96
+ </BreadcrumbLink>
97
+ </BreadcrumbItem>
98
+ <BreadcrumbSeparator />
99
+ </template>
100
+ <BreadcrumbItem class="min-w-0">
101
+ <BreadcrumbPage class="truncate">
102
+ {{ props.title }}
103
+ </BreadcrumbPage>
104
+ </BreadcrumbItem>
105
+ </BreadcrumbList>
106
+ </Breadcrumb>
107
+
108
+ <!-- Title and lede, closed by a rule with a primary segment -->
109
+ <div class="relative mt-8 border-b border-border pb-8">
110
+ <span aria-hidden="true" :class="['absolute -bottom-px left-0 h-0.5 w-20 origin-left bg-primary', enter('animate-uv-grow-x')]" :style="props.animated ? { animationDelay: '500ms' } : undefined" />
111
+
112
+ <!-- Title (each word rises in) -->
113
+ <h1 class="text-3xl leading-[1.08] font-semibold tracking-tight text-foreground sm:text-4xl md:text-5xl">
114
+ <template v-for="(word, index) in titleWords" :key="`${word}-${index}`">
115
+ <span :class="['inline-block', enter('animate-uv-word-in')]" :style="props.animated ? { animationDelay: `${120 + Math.min(index, 12) * 50}ms` } : undefined">{{ word }}</span>{{ index < titleWords.length - 1 ? ' ' : '' }}
116
+ </template>
117
+ </h1>
118
+
119
+ <!-- Lede -->
120
+ <p v-if="props.description" :class="['mt-5 max-w-3xl text-sm leading-relaxed text-muted-foreground md:text-lg', enter('animate-uv-fade-up [animation-delay:450ms]')]">
121
+ {{ props.description }}
122
+ </p>
123
+ </div>
124
+
125
+ <!-- Labelled details (columns without data are left out; the meta slot adds more) -->
126
+ <div v-if="hasDetails || $slots.meta" :class="['overflow-hidden border-b border-border', enter('animate-uv-fade-up [animation-delay:550ms]')]">
127
+ <dl class="-mt-px -ml-[calc(1rem+1px)] grid grid-cols-2 md:grid-flow-col md:auto-cols-fr md:grid-cols-none">
128
+ <!-- Author -->
129
+ <div v-if="props.author" :class="detailCellClasses">
130
+ <dt :class="detailLabelClasses">{{ t('uiVintage.blog.author') }}</dt>
131
+ <dd class="mt-2 flex min-w-0 items-center gap-2 text-sm font-semibold text-foreground">
132
+ <NuxtImg v-if="props.authorImageUrl" :src="props.authorImageUrl" :alt="props.author" width="24" height="24" format="avif" quality="40" class="size-6 shrink-0 rounded border border-border object-cover" />
133
+ <span class="truncate">{{ props.author }}</span>
134
+ </dd>
135
+ </div>
136
+
137
+ <!-- Publication date -->
138
+ <div v-if="formattedDate" :class="detailCellClasses">
139
+ <dt :class="detailLabelClasses">{{ t('uiVintage.blog.publishedDate') }}</dt>
140
+ <dd class="mt-2 text-sm text-foreground">
141
+ <time :datetime="props.datePublished">{{ formattedDate }}</time>
142
+ </dd>
143
+ </div>
144
+
145
+ <!-- Reading time -->
146
+ <div v-if="resolvedReadingMinutes" :class="detailCellClasses">
147
+ <dt :class="detailLabelClasses">{{ t('uiVintage.blog.readingTime') }}</dt>
148
+ <dd class="mt-2 text-sm text-foreground">{{ t('uiVintage.blog.readingTimeValue', { minutes: resolvedReadingMinutes }) }}</dd>
149
+ </div>
150
+
151
+ <!-- Category -->
152
+ <div v-if="hasCategory" :class="detailCellClasses">
153
+ <dt :class="detailLabelClasses">{{ t('uiVintage.blog.category') }}</dt>
154
+ <dd class="mt-1.5">
155
+ <NuxtLinkLocale :to="categoryPath" :class="['inline-flex', badgeLinkClasses]">
156
+ <Badge color="yellow" :text="props.categoryText" pulse />
157
+ </NuxtLinkLocale>
158
+ </dd>
159
+ </div>
160
+
161
+ <!-- Extra columns from the app (use the same cell structure: a div with a dt and a dd) -->
162
+ <slot name="meta" :cell-classes="detailCellClasses" :label-classes="detailLabelClasses" />
163
+ </dl>
164
+ </div>
165
+
166
+ <!-- Tags -->
167
+ <div v-if="props.tags.length > 0" :class="['mt-4 flex flex-wrap items-center gap-2', enter('animate-uv-fade-up [animation-delay:600ms]')]">
168
+ <NuxtLinkLocale v-for="tag in props.tags" :key="tag.slug" :to="tagPath(tag.slug)" :class="badgeLinkClasses">
169
+ <Badge :text="`#${tag.name}`" />
170
+ </NuxtLinkLocale>
171
+ </div>
172
+
173
+ <!-- Featured image (replaceable through the media slot) -->
174
+ <slot name="media">
175
+ <div v-if="props.image" :class="['relative mt-8 aspect-video w-full overflow-hidden rounded border border-border shadow-elevated-xl', enter('animate-uv-fade-up [animation-delay:650ms]')]">
176
+ <NuxtImg :src="props.image" :alt="props.title" format="avif" quality="50" :sizes="{ 480: '480px', 1536: '896px' }" loading="eager" fetchpriority="high" preload :class="['size-full object-cover', enter('animate-uv-ken-burns')]" />
177
+ <div aria-hidden="true" class="pointer-events-none absolute inset-0 bg-linear-to-t from-black/20 to-transparent" />
178
+ </div>
179
+ </slot>
180
+ </header>
181
+ </template>
@@ -6,8 +6,8 @@ import { cn } from '../../lib/utils';
6
6
 
7
7
  // Props
8
8
  const props = defineProps<{
9
- class?: HTMLAttributes['class'];
10
- ariaLabel?: string;
9
+ class?: HTMLAttributes['class'];
10
+ ariaLabel?: string;
11
11
  }>();
12
12
 
13
13
  const { t } = useI18n();
@@ -17,63 +17,63 @@ let animationFrame = 0;
17
17
 
18
18
  // Update progress based on scroll position
19
19
  const updateProgress = () => {
20
- const documentHeight = document.documentElement.scrollHeight - window.innerHeight;
21
- progress.value = documentHeight > 0 ? Math.min(100, Math.max(0, (window.scrollY / documentHeight) * 100)) : 100;
20
+ const documentHeight = document.documentElement.scrollHeight - window.innerHeight;
21
+ progress.value = documentHeight > 0 ? Math.min(100, Math.max(0, (window.scrollY / documentHeight) * 100)) : 100;
22
22
  };
23
23
 
24
24
  // Handle scroll event with requestAnimationFrame for performance
25
25
  const handleScroll = () => {
26
- cancelAnimationFrame(animationFrame);
27
- animationFrame = requestAnimationFrame(updateProgress);
26
+ cancelAnimationFrame(animationFrame);
27
+ animationFrame = requestAnimationFrame(updateProgress);
28
28
  };
29
29
 
30
30
  // On component mounted
31
31
  onMounted(() => {
32
- updateProgress();
33
- window.addEventListener('scroll', handleScroll, { passive: true });
34
- window.addEventListener('resize', updateProgress);
32
+ updateProgress();
33
+ window.addEventListener('scroll', handleScroll, { passive: true });
34
+ window.addEventListener('resize', updateProgress);
35
35
  });
36
36
 
37
37
  // On component unmounted
38
38
  onUnmounted(() => {
39
- cancelAnimationFrame(animationFrame);
40
- window.removeEventListener('scroll', handleScroll);
41
- window.removeEventListener('resize', updateProgress);
39
+ cancelAnimationFrame(animationFrame);
40
+ window.removeEventListener('scroll', handleScroll);
41
+ window.removeEventListener('resize', updateProgress);
42
42
  });
43
43
  </script>
44
44
 
45
45
  <template>
46
- <div :class="cn('h-0.5 w-full bg-border/60 landing-navbar-progress', props.class)"
47
- role="progressbar"
48
- :aria-label="resolvedAriaLabel"
49
- aria-valuemin="0"
50
- aria-valuemax="100"
51
- :aria-valuenow="Math.round(progress)">
52
- <!-- Solid fill -->
53
- <div class="h-full bg-primary transition-[width] duration-150 ease-out" :style="{ width: `${progress}%` }" />
54
- </div>
46
+ <div :class="cn('h-0.5 w-full bg-border/60 landing-navbar-progress', props.class)"
47
+ role="progressbar"
48
+ :aria-label="resolvedAriaLabel"
49
+ aria-valuemin="0"
50
+ aria-valuemax="100"
51
+ :aria-valuenow="Math.round(progress)">
52
+ <!-- Solid fill -->
53
+ <div class="h-full bg-primary transition-[width] duration-150 ease-out" :style="{ width: `${progress}%` }" />
54
+ </div>
55
55
  </template>
56
56
 
57
57
  <style scoped>
58
58
  .landing-navbar-progress {
59
- animation: landing-navbar-progress-fade linear both;
60
- animation-range: 0 160px;
61
- animation-timeline: scroll(root);
59
+ animation: landing-navbar-progress-fade linear both;
60
+ animation-range: 0 160px;
61
+ animation-timeline: scroll(root);
62
62
  }
63
63
 
64
64
  @keyframes landing-navbar-progress-fade {
65
- from {
66
- opacity: 0;
67
- }
65
+ from {
66
+ opacity: 0;
67
+ }
68
68
 
69
- to {
70
- opacity: 1;
71
- }
69
+ to {
70
+ opacity: 1;
71
+ }
72
72
  }
73
73
 
74
74
  @supports not (animation-timeline: scroll()) {
75
- .landing-navbar-progress {
76
- opacity: 1;
77
- }
75
+ .landing-navbar-progress {
76
+ opacity: 1;
77
+ }
78
78
  }
79
79
  </style>
@@ -1,33 +1,33 @@
1
1
  <script setup lang="ts">
2
2
  // Props
3
3
  const props = withDefaults(defineProps<{
4
- title: string;
5
- description?: string;
4
+ title: string;
5
+ description?: string;
6
6
  }>(), {
7
- description: ''
7
+ description: ''
8
8
  });
9
9
  </script>
10
10
 
11
11
  <template>
12
- <div data-aos="blur-up" class="relative mb-6 flex flex-col gap-3 border-b border-border pb-4 sm:flex-row sm:items-end sm:justify-between md:mb-8">
13
- <!-- Primary segment at the start of the rule -->
14
- <span aria-hidden="true" class="absolute -bottom-px left-0 h-0.5 w-12 bg-primary" />
12
+ <div data-aos="blur-up" class="relative mb-6 flex flex-col gap-3 border-b border-border pb-4 sm:flex-row sm:items-end sm:justify-between md:mb-8">
13
+ <!-- Primary segment at the start of the rule -->
14
+ <span aria-hidden="true" class="absolute -bottom-px left-0 h-0.5 w-12 bg-primary" />
15
15
 
16
- <div class="min-w-0">
17
- <!-- Title -->
18
- <h2 class="text-xl font-semibold tracking-tight text-foreground md:text-2xl">
19
- {{ props.title }}
20
- </h2>
16
+ <div class="min-w-0">
17
+ <!-- Title -->
18
+ <h2 class="text-xl font-semibold tracking-tight text-foreground md:text-2xl">
19
+ {{ props.title }}
20
+ </h2>
21
21
 
22
- <!-- Description -->
23
- <p v-if="props.description" class="mt-1 max-w-2xl text-xs leading-6 text-muted-foreground md:text-sm">
24
- {{ props.description }}
25
- </p>
26
- </div>
22
+ <!-- Description -->
23
+ <p v-if="props.description" class="mt-1 max-w-2xl text-xs leading-6 text-muted-foreground md:text-sm">
24
+ {{ props.description }}
25
+ </p>
26
+ </div>
27
27
 
28
- <!-- Optional trailing action (for example a "View all" link) -->
29
- <div v-if="$slots.action" class="shrink-0">
30
- <slot name="action" />
31
- </div>
32
- </div>
33
- </template>
28
+ <!-- Optional trailing action (for example a "View all" link) -->
29
+ <div v-if="$slots.action" class="shrink-0">
30
+ <slot name="action" />
31
+ </div>
32
+ </div>
33
+ </template>
@@ -1,34 +1,34 @@
1
1
  <script setup lang="ts">
2
2
  // Props
3
3
  const props = withDefaults(defineProps<{
4
- tags?: Array<{
5
- name: string;
6
- slug: string;
7
- count: number;
8
- }>;
9
- blogPath?: string;
4
+ tags?: Array<{
5
+ name: string;
6
+ slug: string;
7
+ count: number;
8
+ }>;
9
+ blogPath?: string;
10
10
  }>(), {
11
- tags: () => [],
12
- blogPath: '/blog'
11
+ tags: () => [],
12
+ blogPath: '/blog'
13
13
  });
14
14
  </script>
15
15
 
16
16
  <template>
17
- <div v-if="props.tags.length" class="flex flex-wrap gap-2">
18
- <!-- Tag chip -->
19
- <span v-for="(tag, index) in props.tags" :key="tag.slug" data-aos="blur-up" :data-aos-delay="Math.min(index * 40, 400)" class="inline-flex">
20
- <NuxtLinkLocale :to="`${props.blogPath}/tags/${tag.slug}`" class="group/tag inline-flex items-stretch overflow-hidden rounded border border-border text-xs shadow-elevated-sm outline-none transition-colors duration-150 hover:border-primary/40 focus-visible:ring-[3px] focus-visible:ring-ring/45 sm:text-sm">
21
- <!-- Name -->
22
- <span class="inline-flex items-center gap-1.5 bg-card px-3 py-1.5 font-medium text-foreground transition-colors duration-150 group-hover/tag:bg-primary/10 group-hover/tag:text-primary">
23
- <span aria-hidden="true" class="text-primary">#</span>
24
- {{ tag.name }}
25
- </span>
17
+ <div v-if="props.tags.length" class="flex flex-wrap gap-2">
18
+ <!-- Tag chip -->
19
+ <span v-for="(tag, index) in props.tags" :key="tag.slug" data-aos="blur-up" :data-aos-delay="Math.min(index * 40, 400)" class="inline-flex">
20
+ <NuxtLinkLocale :to="`${props.blogPath}/tags/${tag.slug}`" class="group/tag inline-flex items-stretch overflow-hidden rounded border border-border text-xs shadow-elevated-sm outline-none transition-colors duration-150 hover:border-primary/40 focus-visible:ring-[3px] focus-visible:ring-ring/45 sm:text-sm">
21
+ <!-- Name -->
22
+ <span class="inline-flex items-center gap-1.5 bg-card px-3 py-1.5 font-medium text-foreground transition-colors duration-150 group-hover/tag:bg-primary/10 group-hover/tag:text-primary">
23
+ <span aria-hidden="true" class="text-primary">#</span>
24
+ {{ tag.name }}
25
+ </span>
26
26
 
27
- <!-- Post count -->
28
- <span class="inline-flex items-center border-l border-border bg-surface px-2 text-[11px] font-semibold text-muted-foreground tabular-nums transition-colors duration-150 group-hover/tag:border-primary/40 group-hover/tag:bg-primary/10 group-hover/tag:text-primary">
29
- {{ tag.count }}
30
- </span>
31
- </NuxtLinkLocale>
32
- </span>
33
- </div>
34
- </template>
27
+ <!-- Post count -->
28
+ <span class="inline-flex items-center border-l border-border bg-surface px-2 text-[11px] font-semibold text-muted-foreground tabular-nums transition-colors duration-150 group-hover/tag:border-primary/40 group-hover/tag:bg-primary/10 group-hover/tag:text-primary">
29
+ {{ tag.count }}
30
+ </span>
31
+ </NuxtLinkLocale>
32
+ </span>
33
+ </div>
34
+ </template>