@brumaombra/ui-vintage 0.8.2 → 0.9.1

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 (152) hide show
  1. package/AGENTS.md +41 -0
  2. package/COMPONENTS.md +89 -18
  3. package/README.md +296 -262
  4. package/module.mjs +5 -11
  5. package/package.json +30 -12
  6. package/src/components/blog/BlogContentRenderer.vue +1 -1
  7. package/src/components/blog/BlogFAQSection.vue +1 -1
  8. package/src/components/blog/BlogHeaderSection.vue +93 -19
  9. package/src/components/blog/BlogInfoSection.vue +42 -37
  10. package/src/components/blog/BlogPostHeader.vue +181 -0
  11. package/src/components/blog/BlogProgressBar.vue +3 -5
  12. package/src/components/blog/BlogSectionTitle.vue +8 -6
  13. package/src/components/blog/BlogTagsSection.vue +16 -7
  14. package/src/components/blog/CategoryCard.vue +19 -23
  15. package/src/components/blog/HeaderCarousel.vue +17 -7
  16. package/src/components/blog/PostCard.vue +14 -21
  17. package/src/components/blog/SocialShareSidebar.vue +32 -15
  18. package/src/components/blog/TableOfContents.vue +64 -29
  19. package/src/components/blog/index.ts +1 -0
  20. package/src/components/card-grid/CardGrid.vue +3 -3
  21. package/src/components/chip/Chip.vue +1 -1
  22. package/src/components/confirm-dialog/ConfirmDialog.vue +6 -1
  23. package/src/components/confirm-dialog/confirm-dialog-state.ts +22 -22
  24. package/src/components/content/BlogList.vue +29 -52
  25. package/src/components/content/BlogTable.vue +26 -30
  26. package/src/components/content/CodeBlock.vue +99 -23
  27. package/src/components/content/Flow.vue +29 -35
  28. package/src/components/content/ProseHr.vue +6 -6
  29. package/src/components/content/ProsePre.vue +9 -4
  30. package/src/components/content/Terminal.vue +45 -21
  31. package/src/components/cookie-consent/CookieConsent.vue +1 -1
  32. package/src/components/dashboard-shell/DashboardShell.vue +24 -7
  33. package/src/components/empty-state-card/EmptyStateCard.vue +3 -3
  34. package/src/components/error-page/ErrorPage.vue +4 -4
  35. package/src/components/info-card/InfoCard.vue +4 -4
  36. package/src/components/landing/landing-footer/LandingFooter.vue +17 -12
  37. package/src/components/landing/landing-navbar/LandingNavbar.vue +22 -6
  38. package/src/components/landing/landing-shell/LandingShell.vue +2 -7
  39. package/src/components/language-flag/index.ts +1 -0
  40. package/src/components/language-selector/LanguageSelector.vue +19 -11
  41. package/src/components/load-more-button/LoadMoreButton.vue +9 -13
  42. package/src/components/loading-state-card/LoadingStateCard.vue +3 -3
  43. package/src/components/message-dialog/MessageDialog.vue +14 -12
  44. package/src/components/message-dialog/message-dialog-state.ts +1 -4
  45. package/src/components/message-toast/MessageToast.vue +28 -10
  46. package/src/components/message-toast/message-toast-state.ts +20 -0
  47. package/src/components/page-header/PageHeader.vue +1 -1
  48. package/src/components/progress-component/ProgressComponent.vue +7 -3
  49. package/src/components/single-value-card/SingleValueCard.vue +39 -40
  50. package/src/components/slider-form-component/SliderFormComponent.vue +1 -1
  51. package/src/components/stat-strip/StatStrip.vue +36 -0
  52. package/src/components/stat-strip/index.ts +2 -0
  53. package/src/components/switch-form-component/SwitchFormComponent.vue +5 -5
  54. package/src/components/text-link/TextLink.vue +1 -1
  55. package/src/components/theme-selector/ThemeSelector.vue +6 -3
  56. package/src/components/theme-selector/theme-transition.ts +15 -3
  57. package/src/components/ui/accordion/Accordion.vue +19 -19
  58. package/src/components/ui/alert/AlertTitle.vue +1 -1
  59. package/src/components/ui/alert/index.ts +1 -1
  60. package/src/components/ui/avatar/AvatarFallback.vue +2 -1
  61. package/src/components/ui/avatar/AvatarGroup.vue +13 -3
  62. package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +3 -3
  63. package/src/components/ui/busy/Busy.vue +5 -7
  64. package/src/components/ui/button/Button.vue +4 -2
  65. package/src/components/ui/button/index.ts +1 -4
  66. package/src/components/ui/calendar/Calendar.vue +12 -7
  67. package/src/components/ui/calendar/CalendarCell.vue +1 -1
  68. package/src/components/ui/calendar/CalendarCellTrigger.vue +1 -1
  69. package/src/components/ui/calendar/CalendarHeadCell.vue +1 -1
  70. package/src/components/ui/calendar/CalendarNextButton.vue +2 -2
  71. package/src/components/ui/calendar/CalendarPrevButton.vue +2 -2
  72. package/src/components/ui/card/Card.vue +5 -15
  73. package/src/components/ui/checkbox/Checkbox.vue +5 -1
  74. package/src/components/ui/combobox/ComboboxInput.vue +5 -1
  75. package/src/components/ui/combobox/ComboboxItem.vue +1 -1
  76. package/src/components/ui/combobox/ComboboxSelect.vue +2 -1
  77. package/src/components/ui/combobox/ComboboxTrigger.vue +1 -1
  78. package/src/components/ui/command/CommandGroup.vue +17 -3
  79. package/src/components/ui/command/CommandInput.vue +2 -2
  80. package/src/components/ui/command/CommandList.vue +5 -1
  81. package/src/components/ui/data-table/DataTable.vue +13 -4
  82. package/src/components/ui/date-picker/DatePicker.vue +8 -2
  83. package/src/components/ui/date-time-picker/DateTimePicker.vue +5 -1
  84. package/src/components/ui/dialog/DialogContent.vue +1 -1
  85. package/src/components/ui/dialog/DialogScrollContent.vue +1 -1
  86. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +1 -1
  87. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +1 -1
  88. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +2 -2
  89. package/src/components/ui/dropdown-menu/classes.ts +2 -0
  90. package/src/components/ui/field/Field.vue +4 -0
  91. package/src/components/ui/field/FieldLabel.vue +6 -2
  92. package/src/components/ui/field/field-context.ts +62 -0
  93. package/src/components/ui/field/index.ts +1 -0
  94. package/src/components/ui/file-dropzone/FileDropzone.vue +14 -5
  95. package/src/components/ui/input/Input.vue +5 -1
  96. package/src/components/ui/native-select/NativeSelect.vue +7 -3
  97. package/src/components/ui/number-field/NumberField.vue +7 -2
  98. package/src/components/ui/pagination/PaginationEllipsis.vue +1 -1
  99. package/src/components/ui/pagination/PaginationFirst.vue +1 -1
  100. package/src/components/ui/pagination/PaginationItem.vue +1 -1
  101. package/src/components/ui/pagination/PaginationLast.vue +1 -1
  102. package/src/components/ui/pagination/PaginationNext.vue +1 -1
  103. package/src/components/ui/pagination/PaginationPrevious.vue +1 -1
  104. package/src/components/ui/pin-input/PinInputInput.vue +2 -2
  105. package/src/components/ui/progress/Progress.vue +2 -2
  106. package/src/components/ui/radio-group/RadioGroupCard.vue +1 -1
  107. package/src/components/ui/select/SelectItem.vue +2 -2
  108. package/src/components/ui/select/SelectItemContent.vue +1 -1
  109. package/src/components/ui/select/SelectScrollDownButton.vue +1 -1
  110. package/src/components/ui/select/SelectScrollUpButton.vue +1 -1
  111. package/src/components/ui/select/SelectTrigger.vue +6 -2
  112. package/src/components/ui/sidebar/Sidebar.vue +1 -1
  113. package/src/components/ui/sidebar/SidebarGroupAction.vue +1 -1
  114. package/src/components/ui/sidebar/SidebarGroupLabel.vue +1 -1
  115. package/src/components/ui/sidebar/SidebarInset.vue +1 -1
  116. package/src/components/ui/sidebar/SidebarMenuAction.vue +1 -1
  117. package/src/components/ui/sidebar/SidebarMenuBadge.vue +1 -1
  118. package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +2 -2
  119. package/src/components/ui/sidebar/SidebarMenuSubButton.vue +1 -1
  120. package/src/components/ui/sidebar/SidebarProvider.vue +17 -6
  121. package/src/components/ui/sidebar/SidebarTrigger.vue +1 -1
  122. package/src/components/ui/sidebar/index.ts +2 -2
  123. package/src/components/ui/sidebar/utils.ts +1 -1
  124. package/src/components/ui/slider/Slider.vue +5 -4
  125. package/src/components/ui/spinner/Spinner.vue +3 -2
  126. package/src/components/ui/stepper/SimpleStepper.vue +1 -1
  127. package/src/components/ui/stepper/StepperDescription.vue +5 -3
  128. package/src/components/ui/stepper/StepperIndicator.vue +3 -3
  129. package/src/components/ui/stepper/StepperTitle.vue +5 -3
  130. package/src/components/ui/switch/Switch.vue +6 -2
  131. package/src/components/ui/tabs/TabsList.vue +1 -1
  132. package/src/components/ui/tabs/TabsTrigger.vue +1 -1
  133. package/src/components/ui/tags-input/TagsInputItemDelete.vue +1 -1
  134. package/src/components/ui/textarea/Textarea.vue +5 -1
  135. package/src/components/ui/time-picker/TimePicker.vue +2 -2
  136. package/src/components/ui/toggle-group/ToggleGroup.vue +1 -1
  137. package/src/components/ui/tooltip/TooltipContent.vue +1 -1
  138. package/src/i18n/de.json +16 -6
  139. package/src/i18n/en.json +16 -6
  140. package/src/i18n/es.json +16 -6
  141. package/src/i18n/fr.json +16 -6
  142. package/src/i18n/it.json +16 -6
  143. package/src/i18n/ja.json +16 -6
  144. package/src/i18n/pt.json +16 -6
  145. package/src/i18n/ru.json +16 -6
  146. package/src/i18n/zh.json +16 -6
  147. package/src/lib/color-tokens.ts +1 -1
  148. package/src/lib/i18n.ts +32 -4
  149. package/src/lib/utils.ts +21 -1
  150. package/src/runtime/ui-vintage-i18n-plugin.ts +11 -1
  151. package/src/styles.css +12 -16
  152. package/skills/ui-vintage/SKILL.md +0 -42
package/AGENTS.md ADDED
@@ -0,0 +1,41 @@
1
+ # UI Vintage: instructions for AI agents
2
+
3
+ These instructions are for agents that build UI in an app that depends on `@brumaombra/ui-vintage`, a Nuxt 4 component library with its own design tokens, motion system, and runtime flows. Reuse the library instead of building UI from scratch.
4
+
5
+ ## 1. Read the catalog first
6
+
7
+ The complete API reference matching the installed version ships with the package:
8
+
9
+ `node_modules/@brumaombra/ui-vintage/COMPONENTS.md`
10
+
11
+ Search it (for example for `` ### `@brumaombra/ui-vintage/ ``, a component name, or a prop) instead of reading it top to bottom. It lists every entry point with its import line, components, props and defaults, events, slots, helpers, and examples. Never guess prop names: check them there.
12
+
13
+ ## 2. Choose the component
14
+
15
+ Before writing a custom component, check the catalog's contents list. Common mappings:
16
+
17
+ - Searchable select → `combobox` (`ComboboxSelect`); plain select → `select`.
18
+ - Table with sorting or selection → `data-table`; KPI tiles → `single-value-card`; a compact row of numbers → `stat-strip`.
19
+ - Confirmation → `showConfirmDialog` (`confirm-dialog`); notification → `showMessageToast` (`message-toast`); blocking load → `setBusy` (`busy-indicator`). These mount themselves, so don't add them to a template.
20
+ - App layout with a sidebar → `dashboard-shell`; marketing or blog layout → `landing`; page title row → `page-header`.
21
+ - Empty and loading placeholders → `empty-state-card`, `loading-state-card`, `skeleton`.
22
+ - Blog pages with Nuxt Content → `blog` (`BlogHeaderSection`, `BlogPostHeader`, `PostsList`, `TableOfContents`, `BlogContentRenderer`, ...).
23
+
24
+ Only build something new when no entry point fits, and compose it from library primitives (`card`, `button`, `field`, ...).
25
+
26
+ ## 3. Follow the library conventions
27
+
28
+ - Import from explicit subpaths: `import { Button } from '@brumaombra/ui-vintage/button'`. Never import from `@brumaombra/ui-vintage/src/...`.
29
+ - Style with the semantic tokens (`bg-background`, `bg-card`, `bg-surface`, `bg-accent`, `bg-primary`, `text-foreground`, `text-muted-foreground`, `border-border`, `border-border-strong`, ...). They adapt to dark mode, so don't write `dark:` color variants or hard-coded colors for surfaces and text.
30
+ - Customize components through their props and the `class` prop (merged with tailwind-merge) rather than wrapping them in extra styled elements.
31
+ - Keep corners at `rounded` (the library's square look) and use `shadow-elevated-sm|md|lg|xl` for elevation, without glows or gradients.
32
+ - For motion, reuse the library utilities (`ease-spring`, `ease-out-expo`, `animate-uv-fade-up`, `animate-uv-pop`, `uv-floating-motion`). In custom transitions, name `scale`, `rotate`, and `translate` explicitly; Tailwind v4 doesn't animate them through `transform`.
33
+ - Icons are Hugeicons definitions: import each one from its own module (`import Rocket01Icon from '@hugeicons/core-free-icons/Rocket01Icon'`, never the `@hugeicons/core-free-icons` barrel, which makes the build parse the whole icon set) and pass them to `:icon` props, or render them with `HugeiconsIcon` from `@hugeicons/vue`. Both packages are peer dependencies, so the app must list them in its own `package.json`.
34
+ - Form controls use `v-model`. Mark invalid fields with `aria-invalid` and show messages with `FieldError`.
35
+ - Library strings are translated through vue-i18n (`uiVintage.*` keys). App copy belongs in the app's own locale files.
36
+
37
+ ## 4. Check your work
38
+
39
+ - Every import path you used appears as an entry point in `COMPONENTS.md`.
40
+ - Every prop and event you used appears in that component's table.
41
+ - No new CSS reimplements something a component or token already provides.
package/COMPONENTS.md CHANGED
@@ -9,15 +9,15 @@ This file lists every public entry point of the package with its components, pro
9
9
  - Register the Nuxt module once in `nuxt.config`: `modules: ['@brumaombra/ui-vintage']`. It injects the stylesheet, installs `@nuxt/image`, and merges the library translations into vue-i18n.
10
10
  - Import from explicit subpaths only (for example `@brumaombra/ui-vintage/button`). There is no root barrel, and `src/` paths are internal.
11
11
  - Style with the semantic Tailwind tokens: `bg-background`, `bg-card`, `bg-surface`, `bg-accent`, `bg-primary`, `hover:bg-primary-hover`, `text-foreground`, `text-muted-foreground`, `border-border`, `border-border-strong`, `text-destructive`, `text-success`, `text-warning`, `text-info`. They switch automatically in dark mode, so do not add `dark:` color overrides.
12
- - Reuse the motion utilities from the stylesheet instead of custom animations: `ease-spring`, `ease-bounce`, `ease-out-expo`, `ease-snappy`, `uv-floating-motion`, `uv-modal-motion`, `uv-overlay-motion`, `uv-collapsible-motion`, `uv-field`, `animate-uv-pop`, `animate-uv-fade-up`, `animate-uv-shake`, `animate-uv-shimmer`, `animate-uv-float`, `animate-uv-ping-soft`, and elevation via `shadow-elevated-sm|md|lg|xl` and `shadow-glow`. Tailwind v4 animates `scale`, `rotate`, and `translate` as separate properties, so name them (not `transform`) in custom transitions.
13
- - Icons are Hugeicons definitions passed as values: `import { Rocket01Icon } from '@hugeicons/core-free-icons'` then `:icon="Rocket01Icon"`, or render one with `<HugeiconsIcon :icon="Rocket01Icon" />` from `@hugeicons/vue`.
12
+ - Reuse the motion utilities from the stylesheet instead of custom animations: `ease-spring`, `ease-bounce`, `ease-out-expo`, `ease-snappy`, `uv-floating-motion`, `uv-modal-motion`, `uv-overlay-motion`, `uv-collapsible-motion`, `uv-field`, `animate-uv-pop`, `animate-uv-fade-up`, `animate-uv-shake`, `animate-uv-shimmer`, `animate-uv-float`, `animate-uv-ping-soft`, and elevation via `shadow-elevated-sm|md|lg|xl`. Tailwind v4 animates `scale`, `rotate`, and `translate` as separate properties, so name them (not `transform`) in custom transitions.
13
+ - Icons are Hugeicons definitions passed as values, each imported from its own module: `import Rocket01Icon from '@hugeicons/core-free-icons/Rocket01Icon'` then `:icon="Rocket01Icon"`, or render one with `<HugeiconsIcon :icon="Rocket01Icon" />` from `@hugeicons/vue`.
14
14
  - Every component accepts `class`, merged with `tailwind-merge`, so utility overrides win over the defaults.
15
15
 
16
16
  ## Contents
17
17
 
18
18
  - **Actions:** [button](#brumaombraui-vintagebutton), [dropdown-menu](#brumaombraui-vintagedropdown-menu), [kbd](#brumaombraui-vintagekbd), [load-more-button](#brumaombraui-vintageload-more-button), [text-link](#brumaombraui-vintagetext-link), [toggle-group](#brumaombraui-vintagetoggle-group)
19
19
  - **Forms:** [calendar](#brumaombraui-vintagecalendar), [checkbox](#brumaombraui-vintagecheckbox), [combobox](#brumaombraui-vintagecombobox), [date-picker](#brumaombraui-vintagedate-picker), [date-time-picker](#brumaombraui-vintagedate-time-picker), [field](#brumaombraui-vintagefield), [file-dropzone](#brumaombraui-vintagefile-dropzone), [input](#brumaombraui-vintageinput), [label](#brumaombraui-vintagelabel), [native-select](#brumaombraui-vintagenative-select), [number-field](#brumaombraui-vintagenumber-field), [pin-input](#brumaombraui-vintagepin-input), [radio-group](#brumaombraui-vintageradio-group), [select](#brumaombraui-vintageselect), [slider](#brumaombraui-vintageslider), [slider-form-component](#brumaombraui-vintageslider-form-component), [switch](#brumaombraui-vintageswitch), [switch-form-component](#brumaombraui-vintageswitch-form-component), [tags-input](#brumaombraui-vintagetags-input), [textarea](#brumaombraui-vintagetextarea), [time-picker](#brumaombraui-vintagetime-picker)
20
- - **Data display:** [animated-number](#brumaombraui-vintageanimated-number), [avatar](#brumaombraui-vintageavatar), [badge](#brumaombraui-vintagebadge), [card](#brumaombraui-vintagecard), [card-grid](#brumaombraui-vintagecard-grid), [chip](#brumaombraui-vintagechip), [data-list](#brumaombraui-vintagedata-list), [data-table](#brumaombraui-vintagedata-table), [info-card](#brumaombraui-vintageinfo-card), [progress](#brumaombraui-vintageprogress), [progress-component](#brumaombraui-vintageprogress-component), [scroll-area](#brumaombraui-vintagescroll-area), [separator](#brumaombraui-vintageseparator), [single-value-card](#brumaombraui-vintagesingle-value-card), [skeleton](#brumaombraui-vintageskeleton), [table](#brumaombraui-vintagetable)
20
+ - **Data display:** [animated-number](#brumaombraui-vintageanimated-number), [avatar](#brumaombraui-vintageavatar), [badge](#brumaombraui-vintagebadge), [card](#brumaombraui-vintagecard), [card-grid](#brumaombraui-vintagecard-grid), [chip](#brumaombraui-vintagechip), [data-list](#brumaombraui-vintagedata-list), [data-table](#brumaombraui-vintagedata-table), [info-card](#brumaombraui-vintageinfo-card), [progress](#brumaombraui-vintageprogress), [progress-component](#brumaombraui-vintageprogress-component), [scroll-area](#brumaombraui-vintagescroll-area), [separator](#brumaombraui-vintageseparator), [single-value-card](#brumaombraui-vintagesingle-value-card), [skeleton](#brumaombraui-vintageskeleton), [stat-strip](#brumaombraui-vintagestat-strip), [table](#brumaombraui-vintagetable)
21
21
  - **Navigation:** [accordion](#brumaombraui-vintageaccordion), [breadcrumb](#brumaombraui-vintagebreadcrumb), [collapsible](#brumaombraui-vintagecollapsible), [pagination](#brumaombraui-vintagepagination), [sidebar](#brumaombraui-vintagesidebar), [stepper](#brumaombraui-vintagestepper), [tabs](#brumaombraui-vintagetabs)
22
22
  - **Overlays:** [alert-dialog](#brumaombraui-vintagealert-dialog), [command](#brumaombraui-vintagecommand), [dialog](#brumaombraui-vintagedialog), [hover-card](#brumaombraui-vintagehover-card), [popover](#brumaombraui-vintagepopover), [sheet](#brumaombraui-vintagesheet), [tooltip](#brumaombraui-vintagetooltip)
23
23
  - **Feedback:** [alert](#brumaombraui-vintagealert), [busy](#brumaombraui-vintagebusy), [busy-indicator](#brumaombraui-vintagebusy-indicator), [confirm-dialog](#brumaombraui-vintageconfirm-dialog), [cookie-consent](#brumaombraui-vintagecookie-consent), [empty-state-card](#brumaombraui-vintageempty-state-card), [loading-state-card](#brumaombraui-vintageloading-state-card), [message-dialog](#brumaombraui-vintagemessage-dialog), [message-toast](#brumaombraui-vintagemessage-toast), [spinner](#brumaombraui-vintagespinner)
@@ -31,7 +31,7 @@ Buttons, segmented controls, menus, and keyboard hints.
31
31
 
32
32
  ### `@brumaombra/ui-vintage/button`
33
33
 
34
- Button with solid, outline, ghost, link, and tone variants. Spring press feedback, a sheen on primary buttons, and a `loading` state that keeps the width stable. Use `as-child` to render a link.
34
+ Button with primary, secondary, ghost, link, and tone variants. Spring press feedback and a `loading` state that keeps the width stable. Use `as-child` to render a link.
35
35
 
36
36
  ```ts
37
37
  import { Button, buttonVariants } from '@brumaombra/ui-vintage/button';
@@ -56,6 +56,7 @@ import type { ButtonVariants } from '@brumaombra/ui-vintage/button';
56
56
  | `variant` | `ButtonVariants['variant']` | |
57
57
  | `size` | `ButtonVariants['size']` | |
58
58
  | `loading` | `boolean` | `false` |
59
+ | `disabled` | `boolean` | `false` |
59
60
  | `class` | `HTMLAttributes['class']` | |
60
61
 
61
62
  - **Also accepts** all props of Reka `PrimitiveProps`.
@@ -334,7 +335,7 @@ const toggleGroupContextKey: InjectionKey<{ size: Ref<ToggleGroupSize>; indicato
334
335
 
335
336
  ## Forms
336
337
 
337
- Inputs, pickers, and form layout. Text-like controls share the `uv-field` focus glow and shake on `aria-invalid`.
338
+ Inputs, pickers, and form layout. Text-like controls share the `uv-field` focus ring and shake on `aria-invalid`.
338
339
 
339
340
  ### `@brumaombra/ui-vintage/calendar`
340
341
 
@@ -625,7 +626,7 @@ import { DateTimePicker } from '@brumaombra/ui-vintage/date-time-picker';
625
626
  Form layout primitives: label, description, error list, groups, and fieldsets. `FieldError` accepts strings or `{ message }` objects and hides itself when empty.
626
627
 
627
628
  ```ts
628
- import { fieldVariants, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle } from '@brumaombra/ui-vintage/field';
629
+ import { fieldVariants, useFieldControlId, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle } from '@brumaombra/ui-vintage/field';
629
630
  import type { FieldVariants } from '@brumaombra/ui-vintage/field';
630
631
  ```
631
632
 
@@ -707,6 +708,7 @@ import type { FieldVariants } from '@brumaombra/ui-vintage/field';
707
708
  ```ts
708
709
  type FieldVariants = { orientation?: 'vertical' | 'horizontal' | 'responsive' | null | undefined }
709
710
  const fieldVariants: (props?: FieldVariants & ClassProp) => string
711
+ function useFieldControlId(explicitId?: () => string | undefined)
710
712
  ```
711
713
 
712
714
  ---
@@ -1049,7 +1051,11 @@ import { Slider } from '@brumaombra/ui-vintage/slider';
1049
1051
 
1050
1052
  #### `Slider`
1051
1053
 
1052
- - **Props:** `class`.
1054
+ | Prop | Type | Default |
1055
+ | --- | --- | --- |
1056
+ | `thumbLabel` | `string` | |
1057
+ | `class` | `HTMLAttributes['class']` | |
1058
+
1053
1059
  - **Also accepts** all props of Reka `SliderRootProps`.
1054
1060
  - **Emits:** all events of Reka `SliderRootEmits`.
1055
1061
 
@@ -1201,7 +1207,7 @@ import { TimePicker } from '@brumaombra/ui-vintage/time-picker';
1201
1207
  | --- | --- | --- |
1202
1208
  | `defaultValue` | `string` | `''` |
1203
1209
  | `modelValue` | `string` | |
1204
- | `step` | `string \| number` | `1` |
1210
+ | `step` | `string \| number` | `60` |
1205
1211
  | `min` | `string` | |
1206
1212
  | `max` | `string` | |
1207
1213
  | `disabled` | `boolean` | `false` |
@@ -1334,7 +1340,7 @@ import { Badge } from '@brumaombra/ui-vintage/badge';
1334
1340
 
1335
1341
  ### `@brumaombra/ui-vintage/card`
1336
1342
 
1337
- Surface container with header, title, description, content, footer, and action slots. `interactive` adds a hover lift and pointer spotlight; `color` switches to a tone surface.
1343
+ Surface container with header, title, description, content, footer, and action slots. `interactive` adds a gentle hover lift with a stronger shadow; `color` switches to a tone surface.
1338
1344
 
1339
1345
  ```ts
1340
1346
  import { Card, CardAction, CardContent, CardText, CardDescription, CardFooter, CardHeader, CardTitle } from '@brumaombra/ui-vintage/card';
@@ -1516,7 +1522,7 @@ import type { DataTableSortDirection, DataTableSort, DataTableColumn } from '@br
1516
1522
  | `stickyHeader` | `boolean` | `false` |
1517
1523
  | `class` | `HTMLAttributes['class']` | |
1518
1524
 
1519
- - **Emits:** `update:selected` (value: PropertyKey[]), `update:sort` (value: DataTableSort \| null), `row-click` (row: T, event: MouseEvent).
1525
+ - **Emits:** `update:selected` (value: PropertyKey[]), `update:sort` (value: DataTableSort \| null), `row-click` (row: T, event: MouseEvent \| KeyboardEvent).
1520
1526
  - **Slots:** `cell-${string}`, `header-${string}`, `empty`.
1521
1527
 
1522
1528
  #### Functions, constants, and types
@@ -1682,6 +1688,32 @@ import { Skeleton } from '@brumaombra/ui-vintage/skeleton';
1682
1688
 
1683
1689
  ---
1684
1690
 
1691
+ ### `@brumaombra/ui-vintage/stat-strip`
1692
+
1693
+ Compact row of stats in one bordered strip, each with an optional icon. Numeric values count up like `AnimatedNumber`.
1694
+
1695
+ ```ts
1696
+ import { StatStrip } from '@brumaombra/ui-vintage/stat-strip';
1697
+ ```
1698
+
1699
+ ```vue
1700
+ <StatStrip :items="[
1701
+ { icon: News01Icon, value: 6, label: 'posts' },
1702
+ { icon: FolderLibraryIcon, value: 5, label: 'categories' },
1703
+ { icon: Tag01Icon, value: 11, label: 'tags' }
1704
+ ]" />
1705
+ ```
1706
+
1707
+ #### `StatStrip`
1708
+
1709
+ | Prop | Type | Default |
1710
+ | --- | --- | --- |
1711
+ | `items` *(required)* | `Array<{ label: string; value: string \| number; icon?: HugeiconsIconDefinition; formatOptions?: Intl.NumberFormatOptions }>` | |
1712
+ | `animate` | `boolean` | `true` |
1713
+ | `class` | `HTMLAttributes['class']` | |
1714
+
1715
+ ---
1716
+
1685
1717
  ### `@brumaombra/ui-vintage/table`
1686
1718
 
1687
1719
  Low-level table parts (header, body, row, cell, caption, footer, empty row) for fully custom tables.
@@ -1769,7 +1801,7 @@ import { Accordion } from '@brumaombra/ui-vintage/accordion';
1769
1801
  | `class` | `HTMLAttributes['class']` | |
1770
1802
 
1771
1803
  - **Emits:** `update:open` (value: boolean).
1772
- - **Slots:** `default`.
1804
+ - **Slots:** `trailing`, `default`.
1773
1805
 
1774
1806
  ---
1775
1807
 
@@ -2081,7 +2113,7 @@ import type { SidebarProps, SidebarMenuButtonVariants } from '@brumaombra/ui-vin
2081
2113
 
2082
2114
  | Prop | Type | Default |
2083
2115
  | --- | --- | --- |
2084
- | `defaultOpen` | `boolean` | `!defaultDocument?.cookie.includes(`${SIDEBAR_COOKIE_NAME}=false`)` |
2116
+ | `defaultOpen` | `boolean` | `undefined` |
2085
2117
  | `open` | `boolean` | `undefined` |
2086
2118
  | `compact` | `boolean` | `false` |
2087
2119
  | `class` | `HTMLAttributes['class']` | |
@@ -2357,6 +2389,7 @@ import { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, Comma
2357
2389
  | --- | --- | --- |
2358
2390
  | `class` | `HTMLAttributes['class']` | |
2359
2391
  | `heading` | `string` | |
2392
+ | `stagger` | `boolean` | |
2360
2393
 
2361
2394
  - **Also accepts** all props of Reka `ListboxGroupProps`.
2362
2395
  - **Slots:** `default`.
@@ -3045,6 +3078,7 @@ import { DashboardShell } from '@brumaombra/ui-vintage/dashboard-shell';
3045
3078
  | --- | --- | --- |
3046
3079
  | `appName` | `string` | `''` |
3047
3080
  | `appLogo` | `string` | `''` |
3081
+ | `appLogoDark` | `string` | `''` |
3048
3082
  | `appLinkTo` | `string` | `'/'` |
3049
3083
  | `title` | `string` | `''` |
3050
3084
  | `description` | `string` | `''` |
@@ -3122,6 +3156,7 @@ import type { LandingFooterLink, LandingFooterSection } from '@brumaombra/ui-vin
3122
3156
  | --- | --- | --- |
3123
3157
  | `appName` | `string` | `''` |
3124
3158
  | `appLogo` | `string` | `''` |
3159
+ | `appLogoDark` | `string` | `''` |
3125
3160
  | `appLinkTo` | `string` | `'/'` |
3126
3161
  | `logoClass` | `HTMLAttributes['class']` | |
3127
3162
  | `class` | `HTMLAttributes['class']` | |
@@ -3138,6 +3173,7 @@ import type { LandingFooterLink, LandingFooterSection } from '@brumaombra/ui-vin
3138
3173
  | --- | --- | --- |
3139
3174
  | `appName` *(required)* | `string` | |
3140
3175
  | `appLogo` | `string` | |
3176
+ | `appLogoDark` | `string` | |
3141
3177
  | `appLinkTo` | `string` | `'/'` |
3142
3178
  | `logoClass` | `HTMLAttributes['class']` | |
3143
3179
  | `appDescription` | `string` | `''` |
@@ -3147,7 +3183,7 @@ import type { LandingFooterLink, LandingFooterSection } from '@brumaombra/ui-vin
3147
3183
  | `authorLink` | `string` | `''` |
3148
3184
  | `year` | `number` | `new Date().getFullYear()` |
3149
3185
  | `showBottomBar` | `boolean` | `true` |
3150
- | `level` | `HeadingLevel` | `3` |
3186
+ | `level` | `HeadingLevel` | `2` |
3151
3187
  | `class` | `HTMLAttributes['class']` | |
3152
3188
  | `containerClass` | `HTMLAttributes['class']` | |
3153
3189
  | `brandClass` | `HTMLAttributes['class']` | |
@@ -3203,6 +3239,7 @@ import type { LandingFooterLink, LandingFooterSection } from '@brumaombra/ui-vin
3203
3239
  | --- | --- | --- |
3204
3240
  | `appName` *(required)* | `string` | |
3205
3241
  | `appLogo` | `string` | |
3242
+ | `appLogoDark` | `string` | |
3206
3243
  | `appLinkTo` | `string` | `'/'` |
3207
3244
  | `logoClass` | `HTMLAttributes['class']` | |
3208
3245
  | `appDescription` | `string` | `''` |
@@ -3212,7 +3249,7 @@ import type { LandingFooterLink, LandingFooterSection } from '@brumaombra/ui-vin
3212
3249
  | `authorLink` | `string` | `''` |
3213
3250
  | `year` | `number` | `new Date().getFullYear()` |
3214
3251
  | `showBottomBar` | `boolean` | `true` |
3215
- | `level` | `HeadingLevel` | `3` |
3252
+ | `level` | `HeadingLevel` | `2` |
3216
3253
  | `class` | `HTMLAttributes['class']` | |
3217
3254
  | `containerClass` | `HTMLAttributes['class']` | |
3218
3255
  | `brandClass` | `HTMLAttributes['class']` | |
@@ -3252,6 +3289,7 @@ import { LandingNavbar } from '@brumaombra/ui-vintage/landing-navbar';
3252
3289
  | --- | --- | --- |
3253
3290
  | `appName` | `string` | `''` |
3254
3291
  | `appLogo` | `string` | `''` |
3292
+ | `appLogoDark` | `string` | `''` |
3255
3293
  | `appLinkTo` | `string` | `'/'` |
3256
3294
  | `logoClass` | `HTMLAttributes['class']` | |
3257
3295
  | `class` | `HTMLAttributes['class']` | |
@@ -3291,7 +3329,7 @@ import { LandingShell } from '@brumaombra/ui-vintage/landing-shell';
3291
3329
  Flag icons for the supported locales.
3292
3330
 
3293
3331
  ```ts
3294
- import { LanguageFlag, EnglishFlag, FrenchFlag, GermanFlag, ItalianFlag, ChineseFlag, JapaneseFlag, RussianFlag, SpanishFlag } from '@brumaombra/ui-vintage/language-flag';
3332
+ import { LanguageFlag, EnglishFlag, FrenchFlag, GermanFlag, ItalianFlag, ChineseFlag, JapaneseFlag, PortugueseFlag, RussianFlag, SpanishFlag } from '@brumaombra/ui-vintage/language-flag';
3295
3333
  import type { SupportedLanguageCode } from '@brumaombra/ui-vintage/language-flag';
3296
3334
  ```
3297
3335
 
@@ -3325,6 +3363,10 @@ import type { SupportedLanguageCode } from '@brumaombra/ui-vintage/language-flag
3325
3363
 
3326
3364
  - **Props:** none.
3327
3365
 
3366
+ #### `PortugueseFlag`
3367
+
3368
+ - **Props:** none.
3369
+
3328
3370
  #### `RussianFlag`
3329
3371
 
3330
3372
  - **Props:** none.
@@ -3424,10 +3466,10 @@ Components for Nuxt Content pages and a complete blog.
3424
3466
 
3425
3467
  ### `@brumaombra/ui-vintage/blog`
3426
3468
 
3427
- Blog building blocks: an animated hero header, a full-bleed featured carousel, post and category cards, tags, table of contents, reading progress, FAQ, share sidebar, and the content renderer. Scroll entrances use AOS: install `aos` in the app and initialize it (the components carry `data-aos="blur-up"`, and the library stylesheet defines that animation). Without AOS the content simply renders without entrances.
3469
+ Blog building blocks: an animated hero header, a post header (breadcrumbs, category and tags, title, author line, and featured image), a full-bleed featured carousel, post and category cards, tags, table of contents, reading progress, FAQ, share sidebar, and the content renderer. Scroll entrances use AOS: install `aos` in the app and initialize it (the components carry `data-aos="blur-up"`, and the library stylesheet defines that animation). Without AOS the content simply renders without entrances.
3428
3470
 
3429
3471
  ```ts
3430
- import { AllPostsSection, BlogContentRenderer, BlogFAQSection, BlogInfoSection, BlogHeaderSection, BlogSectionTitle, BlogTagsSection, CategoriesList, CategoriesSection, CategoryCard, HeaderCarousel, PostCard, PostsList, SocialShareSidebar, TableOfContents } from '@brumaombra/ui-vintage/blog';
3472
+ import { AllPostsSection, BlogContentRenderer, BlogFAQSection, BlogInfoSection, BlogPostHeader, BlogHeaderSection, BlogSectionTitle, BlogTagsSection, CategoriesList, CategoriesSection, CategoryCard, HeaderCarousel, PostCard, PostsList, SocialShareSidebar, TableOfContents } from '@brumaombra/ui-vintage/blog';
3431
3473
  ```
3432
3474
 
3433
3475
  #### `AllPostsSection`
@@ -3462,16 +3504,42 @@ import { AllPostsSection, BlogContentRenderer, BlogFAQSection, BlogInfoSection,
3462
3504
  | `author` *(required)* | `string` | |
3463
3505
  | `authorUrl` *(required)* | `string` | |
3464
3506
  | `authorImageUrl` *(required)* | `string` | |
3507
+ | `authorBio` | `string` | `''` |
3465
3508
  | `datePublished` *(required)* | `string` | |
3466
3509
  | `dateModified` | `string \| null` | `null` |
3467
3510
 
3511
+ #### `BlogPostHeader`
3512
+
3513
+ | Prop | Type | Default |
3514
+ | --- | --- | --- |
3515
+ | `title` *(required)* | `string` | |
3516
+ | `description` | `string` | `''` |
3517
+ | `image` | `string` | `''` |
3518
+ | `author` | `string` | `''` |
3519
+ | `authorImageUrl` | `string` | `''` |
3520
+ | `datePublished` | `string` | `''` |
3521
+ | `categoryText` | `string` | `''` |
3522
+ | `categorySlug` | `string` | `''` |
3523
+ | `tags` | `Array<{ name: string; slug: string }>` | `[]` |
3524
+ | `body` | `unknown` | |
3525
+ | `readingMinutes` | `number \| null` | `null` |
3526
+ | `blogPath` | `string` | `'/blog'` |
3527
+ | `blogLabel` | `string` | `''` |
3528
+ | `animated` | `boolean` | `true` |
3529
+
3530
+ - **Slots:** `meta`, `media`.
3531
+
3468
3532
  #### `BlogHeaderSection`
3469
3533
 
3470
3534
  | Prop | Type | Default |
3471
3535
  | --- | --- | --- |
3472
3536
  | `badges` | `Array<{ color: ToneColor; text: string }>` | `[]` |
3537
+ | `announcement` | `{ text: string; to: string; label?: string } \| null` | `null` |
3473
3538
  | `title` *(required)* | `string` | |
3539
+ | `highlight` | `string` | `''` |
3474
3540
  | `description` *(required)* | `string` | |
3541
+ | `stats` | `Array<{ label: string; value: string \| number; icon?: HugeiconsIconDefinition }>` | `[]` |
3542
+ | `align` | `'left' \| 'center' \| 'right'` | `'center'` |
3475
3543
 
3476
3544
  #### `BlogSectionTitle`
3477
3545
 
@@ -3487,6 +3555,7 @@ import { AllPostsSection, BlogContentRenderer, BlogFAQSection, BlogInfoSection,
3487
3555
  | Prop | Type | Default |
3488
3556
  | --- | --- | --- |
3489
3557
  | `tags` | `Array<{ name: string; slug: string; count: number }>` | `[]` |
3558
+ | `blogPath` | `string` | `'/blog'` |
3490
3559
 
3491
3560
  #### `CategoriesList`
3492
3561
 
@@ -3576,6 +3645,7 @@ import { Terminal, CodeBlock, ProsePre, BlogList, BlogTable, Flow, ProseHr } fro
3576
3645
  | --- | --- | --- |
3577
3646
  | `code` | `string` | `''` |
3578
3647
  | `language` | `string` | `''` |
3648
+ | `filename` | `string` | `''` |
3579
3649
 
3580
3650
  - **Slots:** `default`.
3581
3651
 
@@ -3635,7 +3705,7 @@ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6
3635
3705
  Class merging (`cn`) and formatting helpers.
3636
3706
 
3637
3707
  ```ts
3638
- import { cn, formatDateLongItalyTimezone } from '@brumaombra/ui-vintage/utils';
3708
+ import { cn, formatDateLongItalyTimezone, getReadingMinutes } from '@brumaombra/ui-vintage/utils';
3639
3709
  ```
3640
3710
 
3641
3711
  #### Functions, constants, and types
@@ -3643,4 +3713,5 @@ import { cn, formatDateLongItalyTimezone } from '@brumaombra/ui-vintage/utils';
3643
3713
  ```ts
3644
3714
  function cn(...inputs: ClassValue[])
3645
3715
  function formatDateLongItalyTimezone(date: string | number | Date | null | undefined, locale: string)
3716
+ function getReadingMinutes(content: unknown, wordsPerMinute = 220)
3646
3717
  ```