@brumaombra/ui-vintage 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +41 -0
- package/COMPONENTS.md +91 -17
- package/README.md +296 -262
- package/module.mjs +5 -11
- package/package.json +31 -13
- package/src/components/blog/AllPostsSection.vue +1 -2
- package/src/components/blog/BlogContentRenderer.vue +144 -49
- package/src/components/blog/BlogFAQSection.vue +13 -15
- package/src/components/blog/BlogHeaderSection.vue +103 -11
- package/src/components/blog/BlogInfoSection.vue +46 -42
- package/src/components/blog/BlogPostHeader.vue +181 -0
- package/src/components/blog/BlogProgressBar.vue +3 -2
- package/src/components/blog/BlogSectionTitle.vue +27 -6
- package/src/components/blog/BlogTagsSection.vue +20 -8
- package/src/components/blog/CategoriesList.vue +2 -2
- package/src/components/blog/CategoryCard.vue +23 -19
- package/src/components/blog/HeaderCarousel.vue +117 -145
- package/src/components/blog/PostCard.vue +25 -33
- package/src/components/blog/PostsList.vue +3 -2
- package/src/components/blog/SocialShareSidebar.vue +62 -42
- package/src/components/blog/TableOfContents.vue +71 -34
- package/src/components/blog/index.ts +1 -0
- package/src/components/card-grid/CardGrid.vue +2 -2
- package/src/components/confirm-dialog/ConfirmDialog.vue +5 -0
- package/src/components/confirm-dialog/confirm-dialog-state.ts +22 -22
- package/src/components/content/BlogList.vue +30 -42
- package/src/components/content/BlogTable.vue +26 -30
- package/src/components/content/CodeBlock.vue +96 -22
- package/src/components/content/Flow.vue +30 -36
- package/src/components/content/ProseHr.vue +6 -6
- package/src/components/content/ProsePre.vue +9 -4
- package/src/components/content/Terminal.vue +42 -14
- package/src/components/cookie-consent/CookieConsent.vue +1 -1
- package/src/components/dashboard-shell/DashboardShell.vue +24 -7
- package/src/components/empty-state-card/EmptyStateCard.vue +2 -2
- package/src/components/error-page/ErrorPage.vue +3 -3
- package/src/components/info-card/InfoCard.vue +4 -4
- package/src/components/landing/landing-footer/LandingFooter.vue +16 -6
- package/src/components/landing/landing-navbar/LandingNavbar.vue +63 -51
- package/src/components/language-flag/index.ts +1 -0
- package/src/components/language-selector/LanguageSelector.vue +18 -10
- package/src/components/load-more-button/LoadMoreButton.vue +7 -12
- package/src/components/loading-state-card/LoadingStateCard.vue +2 -2
- package/src/components/message-dialog/MessageDialog.vue +11 -11
- package/src/components/message-dialog/message-dialog-state.ts +1 -4
- package/src/components/message-toast/MessageToast.vue +24 -9
- package/src/components/message-toast/message-toast-state.ts +20 -0
- package/src/components/page-header/PageHeader.vue +1 -1
- package/src/components/progress-component/ProgressComponent.vue +7 -3
- package/src/components/single-value-card/SingleValueCard.vue +37 -39
- package/src/components/slider-form-component/SliderFormComponent.vue +1 -1
- package/src/components/stat-strip/StatStrip.vue +36 -0
- package/src/components/stat-strip/index.ts +2 -0
- package/src/components/switch-form-component/SwitchFormComponent.vue +5 -5
- package/src/components/text-link/TextLink.vue +1 -1
- package/src/components/theme-selector/ThemeSelector.vue +2 -2
- package/src/components/theme-selector/theme-transition.ts +15 -3
- package/src/components/ui/accordion/Accordion.vue +18 -18
- package/src/components/ui/alert/AlertTitle.vue +1 -1
- package/src/components/ui/alert/index.ts +1 -1
- package/src/components/ui/avatar/AvatarFallback.vue +2 -1
- package/src/components/ui/avatar/AvatarGroup.vue +13 -3
- package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +2 -2
- package/src/components/ui/breadcrumb/BreadcrumbLink.vue +1 -1
- package/src/components/ui/breadcrumb/BreadcrumbList.vue +1 -1
- package/src/components/ui/breadcrumb/BreadcrumbPage.vue +1 -1
- package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +2 -6
- package/src/components/ui/busy/Busy.vue +5 -7
- package/src/components/ui/button/Button.vue +4 -2
- package/src/components/ui/button/index.ts +1 -4
- package/src/components/ui/calendar/Calendar.vue +12 -7
- package/src/components/ui/calendar/CalendarCell.vue +1 -1
- package/src/components/ui/calendar/CalendarCellTrigger.vue +1 -1
- package/src/components/ui/calendar/CalendarHeadCell.vue +1 -1
- package/src/components/ui/calendar/CalendarNextButton.vue +1 -1
- package/src/components/ui/calendar/CalendarPrevButton.vue +1 -1
- package/src/components/ui/card/Card.vue +5 -15
- package/src/components/ui/checkbox/Checkbox.vue +5 -1
- package/src/components/ui/combobox/ComboboxInput.vue +5 -1
- package/src/components/ui/command/CommandGroup.vue +17 -3
- package/src/components/ui/command/CommandInput.vue +1 -1
- package/src/components/ui/command/CommandItem.vue +2 -2
- package/src/components/ui/command/CommandList.vue +5 -1
- package/src/components/ui/data-table/DataTable.vue +11 -3
- package/src/components/ui/date-picker/DatePicker.vue +7 -1
- package/src/components/ui/date-time-picker/DateTimePicker.vue +5 -1
- package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +1 -1
- package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +1 -1
- package/src/components/ui/dropdown-menu/classes.ts +2 -0
- package/src/components/ui/field/Field.vue +4 -0
- package/src/components/ui/field/FieldLabel.vue +6 -2
- package/src/components/ui/field/field-context.ts +62 -0
- package/src/components/ui/field/index.ts +1 -0
- package/src/components/ui/file-dropzone/FileDropzone.vue +4 -4
- package/src/components/ui/input/Input.vue +5 -1
- package/src/components/ui/native-select/NativeSelect.vue +6 -2
- package/src/components/ui/number-field/NumberField.vue +5 -1
- package/src/components/ui/pagination/PaginationItem.vue +1 -1
- package/src/components/ui/pin-input/PinInputInput.vue +2 -2
- package/src/components/ui/progress/Progress.vue +2 -2
- package/src/components/ui/radio-group/RadioGroupCard.vue +1 -1
- package/src/components/ui/select/SelectItem.vue +1 -1
- package/src/components/ui/select/SelectItemContent.vue +1 -1
- package/src/components/ui/select/SelectTrigger.vue +5 -1
- package/src/components/ui/sidebar/Sidebar.vue +1 -1
- package/src/components/ui/sidebar/SidebarGroupAction.vue +1 -1
- package/src/components/ui/sidebar/SidebarGroupLabel.vue +1 -1
- package/src/components/ui/sidebar/SidebarInset.vue +1 -1
- package/src/components/ui/sidebar/SidebarMenuAction.vue +1 -1
- package/src/components/ui/sidebar/SidebarMenuBadge.vue +1 -1
- package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +2 -2
- package/src/components/ui/sidebar/SidebarMenuSubButton.vue +1 -1
- package/src/components/ui/sidebar/SidebarProvider.vue +17 -6
- package/src/components/ui/sidebar/index.ts +2 -2
- package/src/components/ui/sidebar/utils.ts +1 -1
- package/src/components/ui/slider/Slider.vue +5 -4
- package/src/components/ui/spinner/Spinner.vue +3 -2
- package/src/components/ui/stepper/StepperDescription.vue +5 -3
- package/src/components/ui/stepper/StepperIndicator.vue +2 -2
- package/src/components/ui/stepper/StepperTitle.vue +5 -3
- package/src/components/ui/switch/Switch.vue +6 -2
- package/src/components/ui/tabs/TabsList.vue +1 -1
- package/src/components/ui/tabs/TabsTrigger.vue +1 -1
- package/src/components/ui/textarea/Textarea.vue +5 -1
- package/src/components/ui/time-picker/TimePicker.vue +2 -2
- package/src/components/ui/toggle-group/ToggleGroup.vue +1 -1
- package/src/components/ui/tooltip/TooltipContent.vue +1 -1
- package/src/i18n/de.json +19 -7
- package/src/i18n/en.json +19 -7
- package/src/i18n/es.json +19 -7
- package/src/i18n/fr.json +19 -7
- package/src/i18n/it.json +19 -7
- package/src/i18n/ja.json +19 -7
- package/src/i18n/pt.json +19 -7
- package/src/i18n/ru.json +19 -7
- package/src/i18n/zh.json +19 -7
- package/src/lib/color-tokens.ts +1 -1
- package/src/lib/i18n.ts +32 -4
- package/src/lib/utils.ts +21 -1
- package/src/runtime/ui-vintage-i18n-plugin.ts +11 -1
- package/src/styles.css +52 -16
- package/skills/ui-vintage/SKILL.md +0 -42
package/README.md
CHANGED
|
@@ -1,212 +1,152 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<a href="https://github.com/brumaombra/ui-vintage">
|
|
4
|
+
<picture>
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/banner-dark.webp">
|
|
6
|
+
<img alt="UI Vintage: source-published Nuxt 4 components with a retro soul" src="docs/images/banner-light.webp" width="100%">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
`@brumaombra/ui-vintage` is a Nuxt 4 component library and runtime module for building consistent dashboards, forms, landing pages, overlays, and content experiences. It combines reusable Vue components, shared theme tokens, localization, and Nuxt integrations in one package that is compiled by the consuming application.
|
|
10
|
+
<p><b>84 explicit entry points</b> · <b>light and dark themes</b> · <b>9 built-in locales</b> · <b>accessible primitives on Reka UI</b></p>
|
|
8
11
|
|
|
9
12
|
<p>
|
|
10
|
-
<a href="https://
|
|
11
|
-
<img alt="
|
|
12
|
-
<img alt="
|
|
13
|
-
<img alt="
|
|
14
|
-
<img alt="
|
|
13
|
+
<a href="https://www.npmjs.com/package/@brumaombra/ui-vintage"><img alt="npm version" src="https://img.shields.io/npm/v/@brumaombra/ui-vintage?style=flat-square&color=F7931E&label=npm"></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@brumaombra/ui-vintage"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@brumaombra/ui-vintage?style=flat-square&color=1C2029"></a>
|
|
15
|
+
<img alt="Nuxt 4" src="https://img.shields.io/badge/Nuxt-4-00DC82?style=flat-square&logo=nuxt&logoColor=white">
|
|
16
|
+
<img alt="Vue 3.5" src="https://img.shields.io/badge/Vue-3.5-42B883?style=flat-square&logo=vue.js&logoColor=white">
|
|
17
|
+
<img alt="Tailwind CSS v4" src="https://img.shields.io/badge/Tailwind_CSS-v4-38BDF8?style=flat-square&logo=tailwindcss&logoColor=white">
|
|
18
|
+
<a href="LICENSE"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-1C2029?style=flat-square"></a>
|
|
15
19
|
</p>
|
|
16
20
|
|
|
17
21
|
<p>
|
|
18
|
-
|
|
22
|
+
<a href="#installation"><strong>Installation</strong></a> ·
|
|
23
|
+
<a href="#usage"><strong>Usage</strong></a> ·
|
|
24
|
+
<a href="#showcase"><strong>Showcase</strong></a> ·
|
|
25
|
+
<a href="#components"><strong>Components</strong></a> ·
|
|
26
|
+
<a href="#theming"><strong>Theming</strong></a> ·
|
|
27
|
+
<a href="COMPONENTS.md"><strong>Component catalog</strong></a> ·
|
|
28
|
+
<a href="#demo-app"><strong>Demo app</strong></a>
|
|
19
29
|
</p>
|
|
20
30
|
|
|
21
|
-
<p>
|
|
22
|
-
<a href="#overview"><strong>Overview</strong></a> •
|
|
23
|
-
<a href="#images"><strong>Images</strong></a> •
|
|
24
|
-
<a href="#features"><strong>Features</strong></a> •
|
|
25
|
-
<a href="#architecture"><strong>Architecture</strong></a> •
|
|
26
|
-
<a href="#quick-start"><strong>Quick Start</strong></a> •
|
|
27
|
-
<a href="#usage"><strong>Usage</strong></a> •
|
|
28
|
-
<a href="#components"><strong>Components</strong></a> •
|
|
29
|
-
<a href="#demo-app"><strong>Demo App</strong></a> •
|
|
30
|
-
<a href="#configuration"><strong>Configuration</strong></a> •
|
|
31
|
-
<a href="#publishing"><strong>Publishing</strong></a> •
|
|
32
|
-
<a href="#troubleshooting"><strong>Troubleshooting</strong></a> •
|
|
33
|
-
<a href="#license"><strong>License</strong></a>
|
|
34
|
-
</p>
|
|
35
|
-
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<a id="overview"></a>
|
|
39
|
-
## 📘 Overview
|
|
40
|
-
|
|
41
|
-
UI Vintage is designed for Nuxt applications that need a coherent interface without rebuilding the same primitives for every project. The package provides low-level controls such as buttons, inputs, selects, dialogs, tabs, switches, and sidebars alongside higher-level building blocks such as dashboard shells, landing layouts, cards, data lists, and message flows.
|
|
42
|
-
|
|
43
|
-
The package is intentionally published as source. The consuming Nuxt application compiles the library together with its own runtime, which keeps Nuxt-specific integrations available and avoids maintaining a separate framework-agnostic build artifact.
|
|
44
|
-
|
|
45
|
-
This is a Nuxt library, not a generic Vue component bundle. Components rely on Nuxt runtime features including `#components`, `NuxtImg`, and module lifecycle hooks.
|
|
46
|
-
|
|
47
|
-
<a id="images"></a>
|
|
48
|
-
## 🖼️ Images
|
|
49
|
-
|
|
50
|
-
### Screenshots
|
|
51
|
-
|
|
52
|
-
<div align="center">
|
|
53
|
-
<table width="100%" style="max-width: 768px;">
|
|
54
|
-
<tr>
|
|
55
|
-
<td align="center" valign="top">
|
|
56
|
-
<img src="https://raw.githubusercontent.com/brumaombra/ui-vintage/main/docs/images/screen-1.png" alt="UI Vintage component demo controls and primary actions" width="100%">
|
|
57
|
-
</td>
|
|
58
|
-
<td align="center" valign="top">
|
|
59
|
-
<img src="https://raw.githubusercontent.com/brumaombra/ui-vintage/main/docs/images/screen-2.png" alt="UI Vintage select, accordion, tabs, and component previews" width="100%">
|
|
60
|
-
</td>
|
|
61
|
-
</tr>
|
|
62
|
-
<tr>
|
|
63
|
-
<td align="center" valign="top">
|
|
64
|
-
<img src="https://raw.githubusercontent.com/brumaombra/ui-vintage/main/docs/images/screen-3.png" alt="UI Vintage surface variants, badges, dialogs, and feedback previews" width="100%">
|
|
65
|
-
</td>
|
|
66
|
-
<td align="center" valign="top">
|
|
67
|
-
<img src="https://raw.githubusercontent.com/brumaombra/ui-vintage/main/docs/images/screen-4.png" alt="UI Vintage loading, toast, and current state previews" width="100%">
|
|
68
|
-
</td>
|
|
69
|
-
</tr>
|
|
70
|
-
</table>
|
|
71
|
-
<p>
|
|
72
|
-
<img src="https://raw.githubusercontent.com/brumaombra/ui-vintage/main/docs/images/blog.png" alt="UI Vintage landing and blog showcase" width="100%" style="max-width: 768px;">
|
|
73
|
-
</p>
|
|
74
|
-
<p>
|
|
75
|
-
<sub>Component showcase, interactive states, landing surface, and full-width blog showcase</sub>
|
|
76
|
-
</p>
|
|
77
31
|
</div>
|
|
78
32
|
|
|
79
|
-
<
|
|
80
|
-
## ✨ Features
|
|
81
|
-
|
|
82
|
-
- Nuxt 4 module with automatic runtime integration.
|
|
83
|
-
- Shared stylesheet and design tokens injected from `src/styles.css`.
|
|
84
|
-
- Explicit subpath imports that keep application dependencies clear.
|
|
85
|
-
- Vue 3 components built with Composition API and TypeScript source.
|
|
86
|
-
- Primitive UI controls based on Reka UI where accessible behavior is required.
|
|
87
|
-
- Reusable dashboard, landing, blog, card, field, and data-display components.
|
|
88
|
-
- Built-in busy, confirm-dialog, message-dialog, and stacked, swipeable message-toast flows.
|
|
89
|
-
- A spring-based motion system (pure CSS `linear()` easings) that respects `prefers-reduced-motion`.
|
|
90
|
-
- Theme selector with light, dark, and automatic modes and a circular View Transitions reveal.
|
|
91
|
-
- Library locale messages merged into an existing Vue I18n instance when available.
|
|
92
|
-
- Automatic `@nuxt/image` installation for components that use `NuxtImg`.
|
|
93
|
-
- Source publishing with no required library build step before installation.
|
|
94
|
-
|
|
95
|
-
<a id="architecture"></a>
|
|
96
|
-
## 🏗️ Architecture
|
|
33
|
+
<br>
|
|
97
34
|
|
|
98
|
-
|
|
35
|
+
<picture>
|
|
36
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/hero-dark.webp">
|
|
37
|
+
<img alt="The UI Vintage demo app: dashboard shell, hero with animated highlight, stat cards, and live preview" src="docs/images/hero-light.webp" width="100%">
|
|
38
|
+
</picture>
|
|
99
39
|
|
|
100
|
-
|
|
101
|
-
- 🎨 **Styles and helpers** in `src/styles.css` and `src/lib/` provide theme tokens, class utilities, and shared behavior.
|
|
102
|
-
- 🔌 **Nuxt runtime** in `module.mjs` and `src/runtime/` integrates the package with the consuming app.
|
|
40
|
+
## Why UI Vintage
|
|
103
41
|
|
|
104
|
-
|
|
42
|
+
UI Vintage is a Nuxt 4 module and component library for dashboards, forms, landing pages, overlays, and blogs that should look and feel like one product. It gives you low-level primitives (buttons, inputs, selects, dialogs, tabs) and complete building blocks (dashboard and landing shells, stat cards, data tables, a full blog) that share one set of theme tokens and one motion vocabulary.
|
|
105
43
|
|
|
106
|
-
|
|
44
|
+
- **Source-published.** The package ships its Vue and TypeScript source. Your Nuxt app compiles it together with your own code, so there is no separate build artifact and every Nuxt integration (`NuxtImg`, `#components`, module hooks) keeps working.
|
|
45
|
+
- **Explicit imports.** Every component lives behind its own subpath, such as `@brumaombra/ui-vintage/button`. Nothing is auto-registered, so your dependencies stay obvious and tree-shakeable.
|
|
46
|
+
- **Accessible by default.** Interactive primitives are built on [Reka UI](https://reka-ui.com), with keyboard support, focus management, and ARIA wiring included.
|
|
47
|
+
- **Motion that respects people.** Springs are pure CSS `linear()` easings, and every animation collapses when the user prefers reduced motion.
|
|
107
48
|
|
|
108
|
-
|
|
109
|
-
2. Adds the published `src/` directory to Nuxt transpilation.
|
|
110
|
-
3. Installs `@nuxt/image` when the consuming app has not already registered it.
|
|
111
|
-
4. Registers the library i18n plugin.
|
|
112
|
-
5. Merges the library’s locale messages into the app’s Vue I18n composer when Vue I18n is present.
|
|
49
|
+
## Features
|
|
113
50
|
|
|
114
|
-
|
|
51
|
+
- **Nuxt 4 module** that injects the stylesheet, transpiles the source, installs `@nuxt/image` when needed, and merges the library locale messages into Vue I18n.
|
|
52
|
+
- **Shared design tokens** for colors, borders, and elevation, with light, dark, and automatic themes and a circular View Transitions reveal when switching.
|
|
53
|
+
- **Primitives on Reka UI:** select, combobox, dialog, sheet, popover, tooltip, tabs, stepper, slider, calendar, date and time pickers, PIN input, tags input, and more.
|
|
54
|
+
- **Composite building blocks:** dashboard and landing shells, page headers, stat cards and stat strips, data tables with animated sorting, card grids with empty and loading states.
|
|
55
|
+
- **Promise-based flows:** `showConfirmDialog`, `showMessageDialog`, stacked and swipeable `showMessageToast`, and a shared busy overlay with `setBusy`.
|
|
56
|
+
- **A complete blog** for Nuxt Content: hero header, featured carousel, post header, table of contents, share sidebar, FAQ, reading progress, and VS Code-style code blocks.
|
|
57
|
+
- **Localization** in English, Italian, French, Spanish, German, Portuguese, Chinese, Japanese, and Russian.
|
|
58
|
+
- **Ready for AI coding agents:** a generated component catalog ([`COMPONENTS.md`](COMPONENTS.md)) and agent instructions ([`AGENTS.md`](AGENTS.md)) ship inside the package.
|
|
115
59
|
|
|
116
|
-
|
|
60
|
+
## Installation
|
|
117
61
|
|
|
118
|
-
|
|
119
|
-
src/
|
|
120
|
-
components/ # Public components and UI primitives
|
|
121
|
-
i18n/ # Library locale messages
|
|
122
|
-
lib/ # Shared helpers and token utilities
|
|
123
|
-
runtime/ # Nuxt runtime plugins
|
|
124
|
-
styles.css # Shared design tokens and component styles
|
|
125
|
-
module.mjs # Nuxt module entrypoint
|
|
126
|
-
demo-app/ # Private Nuxt showcase and manual verification app
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
<a id="quick-start"></a>
|
|
130
|
-
## 🚀 Quick Start
|
|
131
|
-
|
|
132
|
-
### 📦 Install the package
|
|
133
|
-
|
|
134
|
-
Install the UI Vintage library and the peer integrations used by the package in an existing Nuxt 4 application:
|
|
62
|
+
Install the package with its peer integrations in an existing Nuxt 4 app. The stylesheet is built with Tailwind CSS v4, the components use Vue I18n for their labels, and icons come from Hugeicons:
|
|
135
63
|
|
|
136
64
|
```bash
|
|
137
|
-
npm install @brumaombra/ui-vintage @nuxt/image vue
|
|
65
|
+
npm install @brumaombra/ui-vintage @nuxt/image @nuxtjs/i18n tailwindcss @tailwindcss/vite @hugeicons/core-free-icons @hugeicons/vue
|
|
138
66
|
```
|
|
139
67
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
Add the module to `nuxt.config.js`:
|
|
68
|
+
Register the module, Nuxt I18n, and the Tailwind Vite plugin in `nuxt.config`:
|
|
143
69
|
|
|
144
70
|
```js
|
|
71
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
72
|
+
|
|
145
73
|
export default defineNuxtConfig({
|
|
146
74
|
modules: [
|
|
147
|
-
'@brumaombra/ui-vintage'
|
|
148
|
-
|
|
75
|
+
'@brumaombra/ui-vintage',
|
|
76
|
+
'@nuxtjs/i18n'
|
|
77
|
+
],
|
|
78
|
+
|
|
79
|
+
vite: {
|
|
80
|
+
plugins: [
|
|
81
|
+
tailwindcss()
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
i18n: {
|
|
86
|
+
defaultLocale: 'en',
|
|
87
|
+
locales: [{ code: 'en', language: 'en-US' }]
|
|
88
|
+
}
|
|
149
89
|
});
|
|
150
90
|
```
|
|
151
91
|
|
|
152
|
-
|
|
92
|
+
That's it: the module injects the shared stylesheet, adds the source to Nuxt transpilation, installs `@nuxt/image` when your app has not registered it, and merges the library messages into your i18n setup. The components call `useI18n()`, so an i18n setup is required even for a single-language app. Using the blog or content components? Install `@nuxt/content` too.
|
|
153
93
|
|
|
154
|
-
|
|
155
|
-
## 🧪 Usage
|
|
94
|
+
## Usage
|
|
156
95
|
|
|
157
|
-
###
|
|
96
|
+
### Use a component
|
|
158
97
|
|
|
159
|
-
|
|
98
|
+
Import components from their public subpath:
|
|
160
99
|
|
|
161
100
|
```vue
|
|
162
101
|
<script setup>
|
|
163
102
|
import { Button } from '@brumaombra/ui-vintage/button';
|
|
164
|
-
import {
|
|
103
|
+
import { SingleValueCard } from '@brumaombra/ui-vintage/single-value-card';
|
|
104
|
+
import { Money03Icon } from '@hugeicons/core-free-icons';
|
|
165
105
|
</script>
|
|
166
106
|
|
|
167
107
|
<template>
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
<!-- For example, the Button component accepts variants such as primary, secondary, gray, and ghost -->
|
|
173
|
-
<Button variant="primary">Save changes</Button>
|
|
174
|
-
</CardContent>
|
|
175
|
-
</Card>
|
|
108
|
+
<SingleValueCard label="Revenue" :value="48290" :icon="Money03Icon" :trend="12.4" trend-label="vs last month"
|
|
109
|
+
:format-options="{ style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }" />
|
|
110
|
+
|
|
111
|
+
<Button variant="primary">Save changes</Button>
|
|
176
112
|
</template>
|
|
177
113
|
```
|
|
178
114
|
|
|
179
|
-
###
|
|
115
|
+
### Ask, confirm, and notify
|
|
180
116
|
|
|
181
|
-
|
|
117
|
+
Dialogs, toasts, and the busy overlay mount themselves on first use, so you never place them in a layout:
|
|
182
118
|
|
|
183
119
|
```js
|
|
184
120
|
import { showConfirmDialog } from '@brumaombra/ui-vintage/confirm-dialog';
|
|
121
|
+
import { showMessageToast } from '@brumaombra/ui-vintage/message-toast';
|
|
185
122
|
import { setBusy } from '@brumaombra/ui-vintage/busy-indicator';
|
|
186
123
|
|
|
187
|
-
//
|
|
124
|
+
// Resolves true or false with the user's choice
|
|
188
125
|
const confirmed = await showConfirmDialog({
|
|
189
126
|
title: 'Delete project?',
|
|
190
|
-
message: 'This action cannot be undone.'
|
|
127
|
+
message: 'This action cannot be undone.',
|
|
128
|
+
confirmButtonType: 'red'
|
|
191
129
|
});
|
|
192
130
|
|
|
193
131
|
if (confirmed) {
|
|
194
|
-
// Keep the shared loading overlay visible while the request
|
|
132
|
+
// Keep the shared loading overlay visible while the request runs
|
|
195
133
|
setBusy(true, { label: 'Deleting project...' });
|
|
196
134
|
await deleteProject();
|
|
197
135
|
setBusy(false);
|
|
136
|
+
|
|
137
|
+
showMessageToast({ type: 'success', title: 'Project deleted', message: 'Everything was removed.' });
|
|
198
138
|
}
|
|
199
139
|
```
|
|
200
140
|
|
|
201
|
-
###
|
|
141
|
+
### Build a layout
|
|
202
142
|
|
|
203
|
-
|
|
143
|
+
Shells own the layout and responsive behavior; your app owns the navigation data and the content:
|
|
204
144
|
|
|
205
145
|
```vue
|
|
206
146
|
<script setup>
|
|
207
147
|
import { DashboardShell } from '@brumaombra/ui-vintage/dashboard-shell';
|
|
208
148
|
|
|
209
|
-
//
|
|
149
|
+
// Sidebar sections and their links
|
|
210
150
|
const sidebarSections = [{
|
|
211
151
|
id: 'workspace',
|
|
212
152
|
label: 'Workspace',
|
|
@@ -218,168 +158,262 @@ const sidebarSections = [{
|
|
|
218
158
|
</script>
|
|
219
159
|
|
|
220
160
|
<template>
|
|
221
|
-
<DashboardShell :sidebar-sections="sidebarSections">
|
|
161
|
+
<DashboardShell app-name="Acme" app-logo="/logo.svg" app-logo-dark="/logo-dark.svg" :sidebar-sections="sidebarSections">
|
|
222
162
|
<slot />
|
|
223
163
|
</DashboardShell>
|
|
224
164
|
</template>
|
|
225
165
|
```
|
|
226
166
|
|
|
227
|
-
<a id="
|
|
228
|
-
##
|
|
229
|
-
|
|
230
|
-
|
|
167
|
+
<a id="showcase"></a>
|
|
168
|
+
## Showcase
|
|
169
|
+
|
|
170
|
+
Every screenshot comes from the [demo app](#demo-app), and each one follows your GitHub theme (light or dark).
|
|
171
|
+
|
|
172
|
+
<table>
|
|
173
|
+
<tr>
|
|
174
|
+
<td width="50%" valign="top">
|
|
175
|
+
<picture>
|
|
176
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/buttons-dark.webp">
|
|
177
|
+
<img alt="Buttons in primary, secondary, ghost, link, and tone variants, with sizes, icon buttons, and a disabled state" src="docs/images/buttons-light.webp" width="100%">
|
|
178
|
+
</picture>
|
|
179
|
+
<p align="center"><b>Buttons</b><br><sub>Variants, tones, sizes, icon buttons, and states</sub></p>
|
|
180
|
+
</td>
|
|
181
|
+
<td width="50%" valign="top">
|
|
182
|
+
<picture>
|
|
183
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/forms-dark.webp">
|
|
184
|
+
<img alt="Text fields with validation, a textarea with a counter, and date and time pickers" src="docs/images/forms-light.webp" width="100%">
|
|
185
|
+
</picture>
|
|
186
|
+
<p align="center"><b>Forms</b><br><sub>Fields with validation, counters, and date and time pickers</sub></p>
|
|
187
|
+
</td>
|
|
188
|
+
</tr>
|
|
189
|
+
<tr>
|
|
190
|
+
<td width="50%" valign="top">
|
|
191
|
+
<picture>
|
|
192
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/data-table-dark.webp">
|
|
193
|
+
<img alt="Data table with selection, status badges, sorting, and pagination" src="docs/images/data-table-light.webp" width="100%">
|
|
194
|
+
</picture>
|
|
195
|
+
<p align="center"><b>Data table</b><br><sub>Typed columns, selection, animated sorting, and pagination</sub></p>
|
|
196
|
+
</td>
|
|
197
|
+
<td width="50%" valign="top">
|
|
198
|
+
<picture>
|
|
199
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/stats-dark.webp">
|
|
200
|
+
<img alt="Stat cards with trends, a stat strip, and an animated total" src="docs/images/stats-light.webp" width="100%">
|
|
201
|
+
</picture>
|
|
202
|
+
<p align="center"><b>Stats and numbers</b><br><sub>Stat cards, the compact stat strip, and numbers that count up</sub></p>
|
|
203
|
+
</td>
|
|
204
|
+
</tr>
|
|
205
|
+
<tr>
|
|
206
|
+
<td width="50%" valign="top">
|
|
207
|
+
<picture>
|
|
208
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/navigation-dark.webp">
|
|
209
|
+
<img alt="Horizontal and vertical tabs above horizontal and vertical steppers" src="docs/images/navigation-light.webp" width="100%">
|
|
210
|
+
</picture>
|
|
211
|
+
<p align="center"><b>Navigation</b><br><sub>Tabs with a gliding indicator and horizontal or vertical steppers</sub></p>
|
|
212
|
+
</td>
|
|
213
|
+
<td width="50%" valign="top">
|
|
214
|
+
<picture>
|
|
215
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/alerts-dark.webp">
|
|
216
|
+
<img alt="Alerts in neutral, success, warning, and error tones" src="docs/images/alerts-light.webp" width="100%">
|
|
217
|
+
</picture>
|
|
218
|
+
<p align="center"><b>Alerts</b><br><sub>Tone surfaces for neutral, success, warning, and error messages</sub></p>
|
|
219
|
+
</td>
|
|
220
|
+
</tr>
|
|
221
|
+
<tr>
|
|
222
|
+
<td width="50%" valign="top">
|
|
223
|
+
<picture>
|
|
224
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/toasts-dark.webp">
|
|
225
|
+
<img alt="A stack of success, info, and warning toasts fanned out in the corner" src="docs/images/toasts-light.webp" width="100%">
|
|
226
|
+
</picture>
|
|
227
|
+
<p align="center"><b>Toasts</b><br><sub>Stacked toasts that fan out on hover and can be swiped away</sub></p>
|
|
228
|
+
</td>
|
|
229
|
+
<td width="50%" valign="top">
|
|
230
|
+
<picture>
|
|
231
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/dialog-dark.webp">
|
|
232
|
+
<img alt="A destructive confirm dialog asking to delete three invoices" src="docs/images/dialog-light.webp" width="100%">
|
|
233
|
+
</picture>
|
|
234
|
+
<p align="center"><b>Confirm dialog</b><br><sub>Promise-based dialogs with async handlers</sub></p>
|
|
235
|
+
</td>
|
|
236
|
+
</tr>
|
|
237
|
+
<tr>
|
|
238
|
+
<td width="50%" valign="top">
|
|
239
|
+
<picture>
|
|
240
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/palette-dark.webp">
|
|
241
|
+
<img alt="The command palette searching the demo sections" src="docs/images/palette-light.webp" width="100%">
|
|
242
|
+
</picture>
|
|
243
|
+
<p align="center"><b>Command palette</b><br><sub>Searchable command menu with keyboard navigation</sub></p>
|
|
244
|
+
</td>
|
|
245
|
+
<td width="50%" valign="top">
|
|
246
|
+
<picture>
|
|
247
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/live-preview-dark.webp">
|
|
248
|
+
<img alt="A small dashboard built only with UI Vintage: stat cards, goals, and activity" src="docs/images/live-preview-light.webp" width="100%">
|
|
249
|
+
</picture>
|
|
250
|
+
<p align="center"><b>Built with UI Vintage</b><br><sub>A small dashboard made only from library components</sub></p>
|
|
251
|
+
</td>
|
|
252
|
+
</tr>
|
|
253
|
+
<tr>
|
|
254
|
+
<td width="50%" valign="top">
|
|
255
|
+
<picture>
|
|
256
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/blog-dark.webp">
|
|
257
|
+
<img alt="The blog home with an announcement, a highlighted title, stats, and the featured carousel" src="docs/images/blog-light.webp" width="100%">
|
|
258
|
+
</picture>
|
|
259
|
+
<p align="center"><b>Blog home</b><br><sub>Hero header with stats and a featured carousel</sub></p>
|
|
260
|
+
</td>
|
|
261
|
+
<td width="50%" valign="top">
|
|
262
|
+
<picture>
|
|
263
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/post-dark.webp">
|
|
264
|
+
<img alt="A blog post header with breadcrumbs, labelled details, tags, and the cover image" src="docs/images/post-light.webp" width="100%">
|
|
265
|
+
</picture>
|
|
266
|
+
<p align="center"><b>Blog post</b><br><sub>Post header with labelled details, tags, and the share sidebar</sub></p>
|
|
267
|
+
</td>
|
|
268
|
+
</tr>
|
|
269
|
+
</table>
|
|
270
|
+
|
|
271
|
+
## Components
|
|
272
|
+
|
|
273
|
+
84 entry points, grouped as in the catalog. Each name is also its import subpath, for example `@brumaombra/ui-vintage/data-table`.
|
|
274
|
+
|
|
275
|
+
| Category | Entry points |
|
|
276
|
+
| --- | --- |
|
|
277
|
+
| **Actions** | `button`, `dropdown-menu`, `kbd`, `load-more-button`, `text-link`, `toggle-group` |
|
|
278
|
+
| **Forms** | `calendar`, `checkbox`, `combobox`, `date-picker`, `date-time-picker`, `field`, `file-dropzone`, `input`, `label`, `native-select`, `number-field`, `pin-input`, `radio-group`, `select`, `slider`, `slider-form-component`, `switch`, `switch-form-component`, `tags-input`, `textarea`, `time-picker` |
|
|
279
|
+
| **Data display** | `animated-number`, `avatar`, `badge`, `card`, `card-grid`, `chip`, `data-list`, `data-table`, `info-card`, `progress`, `progress-component`, `scroll-area`, `separator`, `single-value-card`, `skeleton`, `stat-strip`, `table` |
|
|
280
|
+
| **Navigation** | `accordion`, `breadcrumb`, `collapsible`, `pagination`, `sidebar`, `stepper`, `tabs` |
|
|
281
|
+
| **Overlays** | `alert-dialog`, `command`, `dialog`, `hover-card`, `popover`, `sheet`, `tooltip` |
|
|
282
|
+
| **Feedback** | `alert`, `busy`, `busy-indicator`, `confirm-dialog`, `cookie-consent`, `empty-state-card`, `loading-state-card`, `message-dialog`, `message-toast`, `spinner` |
|
|
283
|
+
| **Layouts and app shell** | `background-grid`, `dashboard-shell`, `error-page`, `landing`, `landing-content`, `landing-footer`, `landing-navbar`, `landing-shell`, `language-flag`, `language-selector`, `page-header`, `theme-selector` |
|
|
284
|
+
| **Content and blog** | `blog`, `content` |
|
|
285
|
+
| **Utilities and types** | `common-types`, `utils` |
|
|
286
|
+
|
|
287
|
+
### Component catalog
|
|
288
|
+
|
|
289
|
+
[`COMPONENTS.md`](COMPONENTS.md) documents every entry point: its import line, props and defaults, events, slots, helpers, and examples. It is generated from the source and ships inside the package, so your app can always read the version it installed at `node_modules/@brumaombra/ui-vintage/COMPONENTS.md`.
|
|
290
|
+
|
|
291
|
+
### Using UI Vintage with AI coding agents
|
|
292
|
+
|
|
293
|
+
The package ships [`AGENTS.md`](AGENTS.md), a short set of instructions that teaches coding agents to reuse UI Vintage: read the catalog before writing UI, pick the right component, follow the library conventions, and check the result.
|
|
294
|
+
|
|
295
|
+
Point your agent to it from your app's own instructions file, so it always reads the version you installed:
|
|
296
|
+
|
|
297
|
+
- **Codex, Cursor, GitHub Copilot, Gemini, and other tools that read `AGENTS.md`:** add this line to the `AGENTS.md` at the root of your app:
|
|
298
|
+
|
|
299
|
+
```md
|
|
300
|
+
Before writing UI, read and follow node_modules/@brumaombra/ui-vintage/AGENTS.md.
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- **Claude Code:** import it in your app's `CLAUDE.md`:
|
|
304
|
+
|
|
305
|
+
```md
|
|
306
|
+
@node_modules/@brumaombra/ui-vintage/AGENTS.md
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Both the instructions and the catalog update with the package, so you never need to copy them again.
|
|
310
|
+
|
|
311
|
+
## Theming
|
|
312
|
+
|
|
313
|
+
### Tokens and dark mode
|
|
314
|
+
|
|
315
|
+
The stylesheet defines semantic tokens (`background`, `foreground`, `card`, `primary`, `muted`, `border`, and more) for both themes. Dark mode follows the `.dark` class on `<html>`; `ThemeSelector` sets it for you, with light, dark, and automatic modes. Extend the existing CSS custom properties in your app stylesheet instead of creating a second token system.
|
|
316
|
+
|
|
317
|
+
The module injects the stylesheet automatically. Import it explicitly only when you need to control the loading order:
|
|
231
318
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
319
|
+
```js
|
|
320
|
+
import '@brumaombra/ui-vintage/style.css';
|
|
321
|
+
```
|
|
235
322
|
|
|
236
|
-
|
|
323
|
+
`LandingNavbar`, `LandingFooter`, and `DashboardShell` accept `app-logo` and `app-logo-dark`, so your logo can follow the theme too.
|
|
237
324
|
|
|
238
|
-
|
|
325
|
+
### Motion
|
|
239
326
|
|
|
240
|
-
|
|
327
|
+
Every component uses the same small vocabulary, and your app can reuse it:
|
|
241
328
|
|
|
242
|
-
|
|
329
|
+
- **Easings:** `ease-spring`, `ease-bounce`, `ease-out-expo`, and `ease-snappy`.
|
|
330
|
+
- **Surfaces:** `uv-floating-motion` (popovers, menus, tooltips), `uv-modal-motion`, `uv-overlay-motion`, `uv-collapsible-motion`, and `uv-field` (focus ring and invalid states for inputs).
|
|
331
|
+
- **Animations:** `animate-uv-pop`, `animate-uv-fade-up`, `animate-uv-shake`, `animate-uv-shimmer`, `animate-uv-float`, `animate-uv-ping-soft`, `animate-uv-word-in`, `animate-uv-grow-x`, and `animate-uv-draw`.
|
|
332
|
+
- **Elevation:** `shadow-elevated-sm` through `shadow-elevated-xl`.
|
|
243
333
|
|
|
244
|
-
|
|
334
|
+
All durations collapse when the user prefers reduced motion. Tailwind v4 animates `scale`, `rotate`, and `translate` as separate properties, so name them (not `transform`) in custom transitions.
|
|
245
335
|
|
|
246
|
-
|
|
336
|
+
### Localization
|
|
247
337
|
|
|
248
|
-
|
|
338
|
+
Library strings live under the `uiVintage` namespace and are available in English, Italian, French, Spanish, German, Portuguese, Chinese, Japanese, and Russian. With `@nuxtjs/i18n` or Vue I18n configured, the runtime plugin merges them into your existing composer without replacing your messages.
|
|
249
339
|
|
|
250
|
-
|
|
251
|
-
# Rewrite COMPONENTS.md from the source
|
|
252
|
-
npm run docs:components
|
|
253
|
-
|
|
254
|
-
# Fail when COMPONENTS.md is out of date (runs in the publish workflow)
|
|
255
|
-
npm run docs:components:check
|
|
256
|
-
```
|
|
340
|
+
## How it works
|
|
257
341
|
|
|
258
|
-
|
|
342
|
+
When the module is registered, it:
|
|
259
343
|
|
|
260
|
-
|
|
344
|
+
1. Injects `src/styles.css` into the app once.
|
|
345
|
+
2. Adds the published `src/` directory to Nuxt transpilation.
|
|
346
|
+
3. Installs `@nuxt/image` when the app has not registered it.
|
|
347
|
+
4. Registers the library i18n plugin, which merges the locale messages when Vue I18n is present.
|
|
261
348
|
|
|
262
|
-
The
|
|
349
|
+
The module does not auto-register components. Always import from a public subpath; files under `src/components/` are implementation details and may change between versions.
|
|
263
350
|
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
351
|
+
```text
|
|
352
|
+
src/
|
|
353
|
+
components/ Public components and UI primitives
|
|
354
|
+
i18n/ Library locale messages
|
|
355
|
+
lib/ Shared helpers and token utilities
|
|
356
|
+
runtime/ Nuxt runtime plugin
|
|
357
|
+
styles.css Design tokens, motion, and component styles
|
|
358
|
+
module.mjs Nuxt module entry point
|
|
359
|
+
demo-app/ Private showcase app (not published)
|
|
268
360
|
```
|
|
269
361
|
|
|
270
|
-
The skill only points to `COMPONENTS.md`, so it stays valid when you update the package. Copy it again only when the skill itself changes.
|
|
271
|
-
|
|
272
|
-
### 🎬 Motion system
|
|
273
|
-
|
|
274
|
-
`src/styles.css` ships a small motion vocabulary that every component uses and that apps can reuse:
|
|
275
|
-
|
|
276
|
-
- Easing utilities: `ease-spring`, `ease-bounce`, `ease-out-expo`, and `ease-snappy`.
|
|
277
|
-
- Surface utilities: `uv-floating-motion` (popovers, menus, tooltips), `uv-modal-motion`, `uv-overlay-motion`, `uv-collapsible-motion`, and `uv-field` (focus glow and invalid states for inputs).
|
|
278
|
-
- Animations: `animate-uv-pop`, `animate-uv-fade-up`, `animate-uv-shake`, `animate-uv-shimmer`, `animate-uv-float`, and `animate-uv-ping-soft`.
|
|
279
|
-
- Elevation: `shadow-elevated-sm` through `shadow-elevated-xl`, plus `shadow-glow`.
|
|
280
|
-
|
|
281
|
-
All durations collapse automatically when the user prefers reduced motion. Tailwind v4 animates `scale`, `rotate`, and `translate` as individual properties, so list those names (not `transform`) in custom transitions.
|
|
282
|
-
|
|
283
362
|
<a id="demo-app"></a>
|
|
284
|
-
##
|
|
363
|
+
## Demo app
|
|
285
364
|
|
|
286
|
-
|
|
365
|
+
`demo-app/` is a documentation-style Nuxt 4 app that shows every component with a live preview and a copyable code tab, a live mini-app on the overview page, a complete blog built with Nuxt Content, and a command palette (`Ctrl/⌘ + K`) to jump to any section. It imports the package through `file:..`, so it runs the same source that is published to npm.
|
|
287
366
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
### ▶️ Run the showcase locally
|
|
291
|
-
|
|
292
|
-
From the repository root:
|
|
367
|
+
It needs Node.js 22.19 or newer, because Nuxt Content uses the built-in `node:sqlite` module instead of a native SQLite build.
|
|
293
368
|
|
|
294
369
|
```bash
|
|
295
|
-
# Install
|
|
370
|
+
# Install and start the demo
|
|
296
371
|
npm --prefix demo-app install
|
|
297
|
-
|
|
298
|
-
# Start the Nuxt development server
|
|
299
372
|
npm --prefix demo-app run dev
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
Open the local URL printed by Nuxt. To create a production build of the showcase:
|
|
303
373
|
|
|
304
|
-
|
|
305
|
-
# Build the private verification app
|
|
374
|
+
# Production build
|
|
306
375
|
npm --prefix demo-app run build
|
|
307
376
|
```
|
|
308
377
|
|
|
309
|
-
|
|
310
|
-
## ⚙️ Configuration
|
|
311
|
-
|
|
312
|
-
### 🎨 Styles
|
|
378
|
+
## Development
|
|
313
379
|
|
|
314
|
-
The
|
|
380
|
+
The tests live in `demo-app/tests`: `unit` covers the helpers, the dialog and toast state, theme storage, and the locale files in plain Node, while `app` mounts the components inside the demo Nuxt app with `@nuxt/test-utils`.
|
|
315
381
|
|
|
316
|
-
|
|
317
|
-
// Import the shared tokens and component styles explicitly when needed
|
|
318
|
-
import '@brumaombra/ui-vintage/style.css';
|
|
319
|
-
```
|
|
382
|
+
There is no build step: the published files are `module.mjs`, `src/`, `COMPONENTS.md`, and `AGENTS.md`. When a version tag is pushed, the GitHub Actions workflow runs the type check, the catalog check, and the tests, and publishes to npm only if they pass. Before opening a pull request or publishing, run the same checks locally:
|
|
320
383
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
The package includes English, Italian, French, Spanish, German, Portuguese, Chinese, Japanese, and Russian library messages. When `@nuxtjs/i18n` or Vue I18n is configured, the runtime plugin merges these messages into the existing composer without replacing application messages.
|
|
326
|
-
|
|
327
|
-
Application-specific translations remain owned by the consuming app. The library only contributes messages under its own `uiVintage` namespace.
|
|
328
|
-
|
|
329
|
-
### 🧭 Imports
|
|
330
|
-
|
|
331
|
-
Use explicit subpaths for public imports:
|
|
332
|
-
|
|
333
|
-
```js
|
|
334
|
-
// Import a component from its stable public entrypoint
|
|
335
|
-
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@brumaombra/ui-vintage/tabs';
|
|
336
|
-
|
|
337
|
-
// Import shared helper behavior from its dedicated entrypoint
|
|
338
|
-
import { showMessageToast } from '@brumaombra/ui-vintage/message-toast';
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
Do not import internal files from `src/components/` in application code. Internal paths are implementation details and may change independently of public entrypoints.
|
|
342
|
-
|
|
343
|
-
<a id="publishing"></a>
|
|
344
|
-
## 📦 Publishing Model
|
|
345
|
-
|
|
346
|
-
UI Vintage publishes the Nuxt module entrypoint and source files directly:
|
|
384
|
+
```bash
|
|
385
|
+
# Type-check the published TypeScript and Vue source
|
|
386
|
+
npm run typecheck
|
|
347
387
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
- `package.json` defines the public component subpath exports.
|
|
351
|
-
- `COMPONENTS.md` and `skills/` ship the generated component catalog and the AI assistant skill.
|
|
352
|
-
- `dist/` is generated repository output and is not the source of truth for consumers.
|
|
388
|
+
# Run the tests (unit tests in Node, component tests inside the demo Nuxt app)
|
|
389
|
+
npm test
|
|
353
390
|
|
|
354
|
-
|
|
391
|
+
# Regenerate the component catalog after changing a public API
|
|
392
|
+
npm run docs:components
|
|
355
393
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
npm run typecheck
|
|
394
|
+
# Fail when COMPONENTS.md is out of date
|
|
395
|
+
npm run docs:components:check
|
|
359
396
|
```
|
|
360
397
|
|
|
361
|
-
|
|
398
|
+
New entry points need an export in `package.json` and a description and category in `scripts/components-meta.mjs`; the catalog generator fails until they have one. The release process is described in [`.claude/skills/publish-npm/SKILL.md`](.claude/skills/publish-npm/SKILL.md).
|
|
362
399
|
|
|
363
|
-
|
|
364
|
-
## 🧰 Requirements
|
|
400
|
+
## Requirements
|
|
365
401
|
|
|
366
|
-
-
|
|
367
|
-
-
|
|
368
|
-
-
|
|
369
|
-
-
|
|
370
|
-
- `
|
|
402
|
+
- Nuxt 4 and Vue 3.5 or newer.
|
|
403
|
+
- Tailwind CSS v4 with `@tailwindcss/vite` registered in `vite.plugins`.
|
|
404
|
+
- `@hugeicons/core-free-icons` 4 and `@hugeicons/vue` 1 (the icons you pass to `:icon` props, and the ones the components render).
|
|
405
|
+
- `vue-i18n` 9, 10, or 11 with an i18n setup, such as `@nuxtjs/i18n` (the components call `useI18n()`).
|
|
406
|
+
- `@nuxt/image` 2 for image components (the module installs it when needed).
|
|
407
|
+
- `@nuxt/content` 3, only for the `blog` and `content` components.
|
|
371
408
|
|
|
372
|
-
|
|
373
|
-
## 🛠️ Troubleshooting
|
|
409
|
+
## Troubleshooting
|
|
374
410
|
|
|
375
|
-
- **Components
|
|
376
|
-
- **Styles are missing:**
|
|
377
|
-
- **`NuxtImg` is unavailable:** install `@nuxt/image
|
|
378
|
-
-
|
|
379
|
-
- **
|
|
380
|
-
- **The demo app does not start:** run `npm --prefix demo-app install` from the repository root, then retry `npm --prefix demo-app run dev`.
|
|
411
|
+
- **Components can't resolve Nuxt imports:** check that the app runs Nuxt 4 and that `@brumaombra/ui-vintage` is registered in `nuxt.config`.
|
|
412
|
+
- **Styles are missing:** register the module once, add `tailwindcss()` from `@tailwindcss/vite` to `vite.plugins`, and restart the dev server after changing `nuxt.config`.
|
|
413
|
+
- **`NuxtImg` is unavailable:** install `@nuxt/image`, or let the module install it during setup.
|
|
414
|
+
- **`useI18n` errors or missing translations:** register `@nuxtjs/i18n` (or install Vue I18n yourself); the components need an i18n composer, and the library messages are merged into it.
|
|
415
|
+
- **An import fails:** use the public subpath from `package.json`, such as `@brumaombra/ui-vintage/button`, never an internal `src/` path.
|
|
381
416
|
|
|
382
|
-
|
|
383
|
-
## 📄 License
|
|
417
|
+
## License
|
|
384
418
|
|
|
385
|
-
|
|
419
|
+
[MIT](LICENSE) © Mauro Brambilla
|