@brumaombra/ui-vintage 0.7.7 → 0.7.9
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/README.md +308 -48
- package/module.mjs +1 -1
- package/package.json +2 -1
- package/src/components/background-grid/BackgroundGrid.vue +11 -2
- package/src/components/background-grid/index.ts +2 -2
- package/src/components/blog/AllPostsSection.vue +25 -9
- package/src/components/blog/BlogFAQSection.vue +8 -3
- package/src/components/blog/BlogHeaderSection.vue +14 -11
- package/src/components/blog/BlogInfoSection.vue +13 -11
- package/src/components/blog/BlogSectionTitle.vue +5 -5
- package/src/components/blog/CategoriesList.vue +11 -3
- package/src/components/blog/CategoriesSection.vue +11 -3
- package/src/components/blog/CategoryCard.vue +10 -8
- package/src/components/blog/HeaderCarousel.vue +24 -15
- package/src/components/blog/PostCard.vue +16 -11
- package/src/components/blog/PostsList.vue +12 -3
- package/src/components/blog/SocialShareSidebar.vue +11 -11
- package/src/components/blog/TableOfContents.vue +29 -13
- package/src/components/busy-indicator/BusyIndicator.vue +2 -2
- package/src/components/busy-indicator/busy-indicator-state.ts +11 -12
- package/src/components/busy-indicator/index.ts +3 -3
- package/src/components/card-grid/CardGrid.vue +25 -11
- package/src/components/chip/Chip.vue +15 -15
- package/src/components/chip/index.ts +2 -2
- package/src/components/confirm-dialog/ConfirmDialog.vue +9 -9
- package/src/components/confirm-dialog/confirm-dialog-state.ts +15 -14
- package/src/components/confirm-dialog/index.ts +3 -12
- package/src/components/content/BlogList.vue +11 -8
- package/src/components/content/BlogTable.vue +18 -14
- package/src/components/content/ProseHr.vue +10 -7
- package/src/components/content/Terminal.vue +70 -0
- package/src/components/content/index.ts +2 -1
- package/src/components/dashboard-shell/DashboardShell.vue +49 -65
- package/src/components/dashboard-shell/index.ts +2 -2
- package/src/components/data-list/DataList.vue +11 -13
- package/src/components/data-list/DataListItem.vue +9 -11
- package/src/components/data-list/DataListLabel.vue +9 -11
- package/src/components/data-list/DataListText.vue +9 -11
- package/src/components/data-list/DataListValue.vue +9 -11
- package/src/components/data-list/index.ts +5 -5
- package/src/components/empty-state-card/EmptyStateCard.vue +21 -11
- package/src/components/error-page/ErrorPage.vue +24 -27
- package/src/components/error-page/index.ts +2 -2
- package/src/components/info-card/InfoCard.vue +17 -11
- package/src/components/landing/index.ts +6 -6
- package/src/components/landing/landing-content/LandingContent.vue +5 -7
- package/src/components/landing/landing-content/index.ts +2 -2
- package/src/components/landing/landing-footer/LandingFooter.vue +26 -29
- package/src/components/landing/landing-footer/index.ts +3 -3
- package/src/components/landing/landing-navbar/LandingNavbar.vue +15 -17
- package/src/components/landing/landing-navbar/index.ts +2 -2
- package/src/components/landing/landing-shell/LandingShell.vue +10 -13
- package/src/components/landing/landing-shell/index.ts +2 -2
- package/src/components/language-flag/LanguageFlag.vue +6 -5
- package/src/components/language-flag/index.ts +1 -0
- package/src/components/language-selector/LanguageSelector.vue +20 -21
- package/src/components/load-more-button/LoadMoreButton.vue +18 -14
- package/src/components/loading-state-card/LoadingStateCard.vue +13 -9
- package/src/components/message-dialog/MessageDialog.vue +19 -19
- package/src/components/message-dialog/index.ts +3 -11
- package/src/components/message-dialog/message-dialog-state.ts +12 -11
- package/src/components/message-toast/MessageToast.vue +16 -16
- package/src/components/message-toast/index.ts +2 -9
- package/src/components/message-toast/message-toast-state.ts +9 -9
- package/src/components/page-header/PageHeader.vue +8 -5
- package/src/components/progress-component/ProgressComponent.vue +13 -10
- package/src/components/single-value-card/SingleValueCard.vue +22 -19
- package/src/components/slider-form-component/SliderFormComponent.vue +11 -20
- package/src/components/slider-form-component/index.ts +2 -2
- package/src/components/switch-form-component/SwitchFormComponent.vue +7 -9
- package/src/components/switch-form-component/index.ts +2 -2
- package/src/components/text-link/TextLink.vue +11 -7
- package/src/components/theme-selector/ThemeSelector.vue +4 -4
- package/src/components/ui/accordion/Accordion.vue +12 -15
- package/src/components/ui/accordion/index.ts +1 -1
- package/src/components/ui/alert/Alert.vue +11 -10
- package/src/components/ui/alert/AlertDescription.vue +9 -8
- package/src/components/ui/alert/AlertTitle.vue +9 -8
- package/src/components/ui/alert/index.ts +10 -10
- package/src/components/ui/alert-dialog/AlertDialog.vue +13 -9
- package/src/components/ui/alert-dialog/AlertDialogAction.vue +14 -12
- package/src/components/ui/alert-dialog/AlertDialogCancel.vue +14 -16
- package/src/components/ui/alert-dialog/AlertDialogContent.vue +24 -27
- package/src/components/ui/alert-dialog/AlertDialogDescription.vue +13 -13
- package/src/components/ui/alert-dialog/AlertDialogFooter.vue +9 -12
- package/src/components/ui/alert-dialog/AlertDialogHeader.vue +9 -8
- package/src/components/ui/alert-dialog/AlertDialogTitle.vue +13 -11
- package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +8 -7
- package/src/components/ui/alert-dialog/index.ts +9 -9
- package/src/components/ui/badge/Badge.vue +11 -12
- package/src/components/ui/badge/index.ts +1 -1
- package/src/components/ui/breadcrumb/Breadcrumb.vue +9 -12
- package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +15 -19
- package/src/components/ui/breadcrumb/BreadcrumbItem.vue +10 -12
- package/src/components/ui/breadcrumb/BreadcrumbLink.vue +13 -17
- package/src/components/ui/breadcrumb/BreadcrumbList.vue +10 -12
- package/src/components/ui/breadcrumb/BreadcrumbPage.vue +10 -15
- package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +14 -18
- package/src/components/ui/breadcrumb/index.ts +7 -7
- package/src/components/ui/busy/Busy.vue +36 -29
- package/src/components/ui/busy/index.ts +1 -1
- package/src/components/ui/button/Button.vue +18 -19
- package/src/components/ui/button/index.ts +54 -35
- package/src/components/ui/calendar/Calendar.vue +167 -121
- package/src/components/ui/calendar/CalendarCell.vue +18 -17
- package/src/components/ui/calendar/CalendarCellTrigger.vue +31 -33
- package/src/components/ui/calendar/CalendarGrid.vue +14 -17
- package/src/components/ui/calendar/CalendarGridBody.vue +9 -11
- package/src/components/ui/calendar/CalendarGridHead.vue +10 -12
- package/src/components/ui/calendar/CalendarGridRow.vue +14 -16
- package/src/components/ui/calendar/CalendarHeadCell.vue +18 -17
- package/src/components/ui/calendar/CalendarHeader.vue +18 -17
- package/src/components/ui/calendar/CalendarHeading.vue +18 -22
- package/src/components/ui/calendar/CalendarNextButton.vue +29 -26
- package/src/components/ui/calendar/CalendarPrevButton.vue +29 -26
- package/src/components/ui/calendar/index.ts +17 -13
- package/src/components/ui/card/Card.vue +21 -13
- package/src/components/ui/card/CardAction.vue +12 -7
- package/src/components/ui/card/CardContent.vue +8 -7
- package/src/components/ui/card/CardDescription.vue +16 -7
- package/src/components/ui/card/CardFooter.vue +8 -7
- package/src/components/ui/card/CardHeader.vue +12 -7
- package/src/components/ui/card/CardText.vue +12 -7
- package/src/components/ui/card/CardTitle.vue +9 -7
- package/src/components/ui/card/index.ts +8 -8
- package/src/components/ui/command/Command.vue +71 -61
- package/src/components/ui/command/CommandDialog.vue +33 -23
- package/src/components/ui/command/CommandEmpty.vue +19 -20
- package/src/components/ui/command/CommandGroup.vue +32 -35
- package/src/components/ui/command/CommandInput.vue +25 -21
- package/src/components/ui/command/CommandItem.vue +62 -59
- package/src/components/ui/command/CommandList.vue +21 -18
- package/src/components/ui/command/CommandSeparator.vue +13 -11
- package/src/components/ui/command/CommandShortcut.vue +13 -8
- package/src/components/ui/command/index.ts +24 -20
- package/src/components/ui/date-picker/DatePicker.vue +46 -37
- package/src/components/ui/date-picker/index.ts +2 -2
- package/src/components/ui/date-time-picker/DateTimePicker.vue +99 -95
- package/src/components/ui/date-time-picker/index.ts +2 -2
- package/src/components/ui/dialog/Dialog.vue +12 -9
- package/src/components/ui/dialog/DialogClose.vue +8 -10
- package/src/components/ui/dialog/DialogContent.vue +36 -42
- package/src/components/ui/dialog/DialogDescription.vue +16 -11
- package/src/components/ui/dialog/DialogFooter.vue +13 -12
- package/src/components/ui/dialog/DialogHeader.vue +9 -8
- package/src/components/ui/dialog/DialogOverlay.vue +16 -11
- package/src/components/ui/dialog/DialogScrollContent.vue +47 -45
- package/src/components/ui/dialog/DialogTitle.vue +13 -12
- package/src/components/ui/dialog/DialogTrigger.vue +8 -7
- package/src/components/ui/dialog/index.ts +10 -10
- package/src/components/ui/field/Field.vue +12 -14
- package/src/components/ui/field/FieldContent.vue +13 -11
- package/src/components/ui/field/FieldDescription.vue +15 -13
- package/src/components/ui/field/FieldError.vue +43 -40
- package/src/components/ui/field/FieldGroup.vue +13 -11
- package/src/components/ui/field/FieldLabel.vue +16 -14
- package/src/components/ui/field/FieldLegend.vue +16 -14
- package/src/components/ui/field/FieldSeparator.vue +17 -15
- package/src/components/ui/field/FieldSet.vue +14 -12
- package/src/components/ui/field/FieldTitle.vue +13 -11
- package/src/components/ui/field/index.ts +36 -36
- package/src/components/ui/input/Input.vue +23 -20
- package/src/components/ui/input/index.ts +1 -1
- package/src/components/ui/label/Label.vue +16 -15
- package/src/components/ui/label/index.ts +1 -1
- package/src/components/ui/native-select/NativeSelect.vue +31 -41
- package/src/components/ui/native-select/NativeSelectOptGroup.vue +8 -7
- package/src/components/ui/native-select/NativeSelectOption.vue +8 -7
- package/src/components/ui/native-select/index.ts +3 -3
- package/src/components/ui/popover/Popover.vue +12 -9
- package/src/components/ui/popover/PopoverAnchor.vue +8 -7
- package/src/components/ui/popover/PopoverContent.vue +27 -31
- package/src/components/ui/popover/PopoverTrigger.vue +8 -7
- package/src/components/ui/popover/index.ts +4 -4
- package/src/components/ui/progress/Progress.vue +18 -32
- package/src/components/ui/progress/index.ts +1 -1
- package/src/components/ui/scroll-area/ScrollArea.vue +23 -26
- package/src/components/ui/scroll-area/ScrollBar.vue +22 -26
- package/src/components/ui/scroll-area/index.ts +2 -2
- package/src/components/ui/select/Select.vue +12 -9
- package/src/components/ui/select/SelectContent.vue +39 -40
- package/src/components/ui/select/SelectGroup.vue +8 -7
- package/src/components/ui/select/SelectItem.vue +36 -41
- package/src/components/ui/select/SelectItemContent.vue +22 -15
- package/src/components/ui/select/SelectItemText.vue +8 -7
- package/src/components/ui/select/SelectLabel.vue +10 -9
- package/src/components/ui/select/SelectScrollDownButton.vue +21 -17
- package/src/components/ui/select/SelectScrollUpButton.vue +21 -17
- package/src/components/ui/select/SelectSeparator.vue +11 -9
- package/src/components/ui/select/SelectTrigger.vue +27 -25
- package/src/components/ui/select/SelectValue.vue +8 -7
- package/src/components/ui/select/SelectValueContent.vue +30 -18
- package/src/components/ui/select/index.ts +13 -13
- package/src/components/ui/separator/Separator.vue +17 -18
- package/src/components/ui/separator/index.ts +1 -1
- package/src/components/ui/sheet/Sheet.vue +12 -9
- package/src/components/ui/sheet/SheetClose.vue +8 -7
- package/src/components/ui/sheet/SheetContent.vue +36 -37
- package/src/components/ui/sheet/SheetDescription.vue +12 -11
- package/src/components/ui/sheet/SheetFooter.vue +8 -7
- package/src/components/ui/sheet/SheetHeader.vue +8 -7
- package/src/components/ui/sheet/SheetOverlay.vue +16 -11
- package/src/components/ui/sheet/SheetTitle.vue +12 -11
- package/src/components/ui/sheet/SheetTrigger.vue +8 -7
- package/src/components/ui/sheet/index.ts +8 -8
- package/src/components/ui/sidebar/Sidebar.vue +68 -61
- package/src/components/ui/sidebar/SidebarContent.vue +13 -8
- package/src/components/ui/sidebar/SidebarFooter.vue +13 -8
- package/src/components/ui/sidebar/SidebarGroup.vue +13 -8
- package/src/components/ui/sidebar/SidebarGroupAction.vue +16 -16
- package/src/components/ui/sidebar/SidebarGroupContent.vue +9 -8
- package/src/components/ui/sidebar/SidebarGroupLabel.vue +15 -14
- package/src/components/ui/sidebar/SidebarHeader.vue +13 -8
- package/src/components/ui/sidebar/SidebarInput.vue +14 -12
- package/src/components/ui/sidebar/SidebarInset.vue +14 -12
- package/src/components/ui/sidebar/SidebarMenu.vue +9 -8
- package/src/components/ui/sidebar/SidebarMenuAction.vue +25 -23
- package/src/components/ui/sidebar/SidebarMenuBadge.vue +19 -17
- package/src/components/ui/sidebar/SidebarMenuButton.vue +33 -32
- package/src/components/ui/sidebar/SidebarMenuButtonChild.vue +19 -18
- package/src/components/ui/sidebar/SidebarMenuItem.vue +9 -8
- package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +17 -12
- package/src/components/ui/sidebar/SidebarMenuSub.vue +14 -12
- package/src/components/ui/sidebar/SidebarMenuSubButton.vue +24 -21
- package/src/components/ui/sidebar/SidebarMenuSubItem.vue +9 -8
- package/src/components/ui/sidebar/SidebarProvider.vue +63 -53
- package/src/components/ui/sidebar/SidebarRail.vue +20 -18
- package/src/components/ui/sidebar/SidebarSeparator.vue +10 -9
- package/src/components/ui/sidebar/SidebarTrigger.vue +15 -14
- package/src/components/ui/sidebar/index.ts +62 -58
- package/src/components/ui/sidebar/utils.ts +16 -16
- package/src/components/ui/skeleton/Skeleton.vue +12 -9
- package/src/components/ui/skeleton/index.ts +1 -1
- package/src/components/ui/slider/Slider.vue +24 -19
- package/src/components/ui/slider/index.ts +1 -1
- package/src/components/ui/switch/Switch.vue +26 -23
- package/src/components/ui/switch/index.ts +1 -1
- package/src/components/ui/table/Table.vue +11 -10
- package/src/components/ui/table/TableBody.vue +9 -11
- package/src/components/ui/table/TableCaption.vue +9 -11
- package/src/components/ui/table/TableCell.vue +13 -16
- package/src/components/ui/table/TableEmpty.vue +22 -25
- package/src/components/ui/table/TableFooter.vue +13 -11
- package/src/components/ui/table/TableHead.vue +13 -11
- package/src/components/ui/table/TableHeader.vue +9 -11
- package/src/components/ui/table/TableRow.vue +13 -11
- package/src/components/ui/table/index.ts +9 -9
- package/src/components/ui/tabs/Tabs.vue +18 -18
- package/src/components/ui/tabs/TabsContent.vue +14 -15
- package/src/components/ui/tabs/TabsList.vue +18 -18
- package/src/components/ui/tabs/TabsTrigger.vue +19 -20
- package/src/components/ui/tabs/index.ts +4 -4
- package/src/components/ui/textarea/Textarea.vue +23 -20
- package/src/components/ui/textarea/index.ts +1 -1
- package/src/components/ui/time-picker/TimePicker.vue +33 -38
- package/src/components/ui/time-picker/index.ts +2 -2
- package/src/components/ui/tooltip/Tooltip.vue +12 -9
- package/src/components/ui/tooltip/TooltipContent.vue +28 -20
- package/src/components/ui/tooltip/TooltipProvider.vue +9 -8
- package/src/components/ui/tooltip/TooltipTrigger.vue +8 -7
- package/src/components/ui/tooltip/index.ts +4 -4
- package/src/i18n/de.json +5 -0
- package/src/i18n/en.json +5 -0
- package/src/i18n/es.json +5 -0
- package/src/i18n/fr.json +5 -0
- package/src/i18n/it.json +5 -0
- package/src/i18n/ja.json +5 -0
- package/src/i18n/pt.json +5 -0
- package/src/i18n/ru.json +5 -0
- package/src/i18n/zh.json +5 -0
- package/src/lib/common-types.ts +2 -0
- package/src/lib/i18n.ts +0 -5
- package/src/runtime/{ui-vintage-i18n-plugin.js → ui-vintage-i18n-plugin.ts} +30 -8
package/README.md
CHANGED
|
@@ -1,85 +1,345 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# 🎨 UI Vintage
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### A source-published Nuxt UI runtime for focused, reusable interfaces
|
|
6
6
|
|
|
7
|
-
- Nuxt module
|
|
8
|
-
- automatic stylesheet injection from `src/styles.css`
|
|
9
|
-
- explicit source-based subpath imports for components and helpers
|
|
10
|
-
- built-in locale merge for the library messages when `vue-i18n` is present
|
|
11
|
-
- real Nuxt integrations, including `@nuxt/image` components inside the shared source
|
|
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.
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
<p>
|
|
10
|
+
<a href="https://github.com/brumaombra/ui-vintage"><img alt="GitHub Repo" src="https://img.shields.io/badge/github-brumaombra%2Fui--vintage-111111?logo=github"></a>
|
|
11
|
+
<img alt="Nuxt 4" src="https://img.shields.io/badge/nuxt-4-00DC82?logo=nuxt&logoColor=white">
|
|
12
|
+
<img alt="Vue 3" src="https://img.shields.io/badge/vue-3-42B883?logo=vue.js&logoColor=white">
|
|
13
|
+
<img alt="npm" src="https://img.shields.io/npm/v/@brumaombra/ui-vintage?color=CB3837&logo=npm">
|
|
14
|
+
<img alt="License MIT" src="https://img.shields.io/badge/license-MIT-2563EB">
|
|
15
|
+
</p>
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
<p>
|
|
18
|
+
🧩 Reusable Vue components • 🎨 Shared theme tokens • 🌍 Built-in locale messages • 🖼️ Nuxt Image integration • ⚡ Source-based publishing
|
|
19
|
+
</p>
|
|
16
20
|
|
|
17
|
-
|
|
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
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<a id="features"></a>
|
|
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 message-toast flows.
|
|
89
|
+
- Theme selector with light, dark, and automatic system modes.
|
|
90
|
+
- Library locale messages merged into an existing Vue I18n instance when available.
|
|
91
|
+
- Automatic `@nuxt/image` installation for components that use `NuxtImg`.
|
|
92
|
+
- Source publishing with no required library build step before installation.
|
|
93
|
+
|
|
94
|
+
<a id="architecture"></a>
|
|
95
|
+
## 🏗️ Architecture
|
|
96
|
+
|
|
97
|
+
UI Vintage is split into three cooperating layers:
|
|
98
|
+
|
|
99
|
+
- 🧩 **Components** in `src/components/` contain the public Vue UI and composite layouts.
|
|
100
|
+
- 🎨 **Styles and helpers** in `src/styles.css` and `src/lib/` provide theme tokens, class utilities, and shared behavior.
|
|
101
|
+
- 🔌 **Nuxt runtime** in `module.mjs` and `src/runtime/` integrates the package with the consuming app.
|
|
102
|
+
|
|
103
|
+
### 🔄 Module Behavior
|
|
104
|
+
|
|
105
|
+
When the module is registered, it:
|
|
106
|
+
|
|
107
|
+
1. Injects `src/styles.css` into the Nuxt application once.
|
|
108
|
+
2. Adds the published `src/` directory to Nuxt transpilation.
|
|
109
|
+
3. Installs `@nuxt/image` when the consuming app has not already registered it.
|
|
110
|
+
4. Registers the library i18n plugin.
|
|
111
|
+
5. Merges the library’s locale messages into the app’s Vue I18n composer when Vue I18n is present.
|
|
112
|
+
|
|
113
|
+
The module does not auto-register every component. Import components and helpers explicitly from their public subpaths.
|
|
114
|
+
|
|
115
|
+
### 📁 Repository Layout
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
src/
|
|
119
|
+
components/ # Public components and UI primitives
|
|
120
|
+
i18n/ # Library locale messages
|
|
121
|
+
lib/ # Shared helpers and token utilities
|
|
122
|
+
runtime/ # Nuxt runtime plugins
|
|
123
|
+
styles.css # Shared design tokens and component styles
|
|
124
|
+
module.mjs # Nuxt module entrypoint
|
|
125
|
+
demo-app/ # Private Nuxt showcase and manual verification app
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
<a id="quick-start"></a>
|
|
129
|
+
## 🚀 Quick Start
|
|
130
|
+
|
|
131
|
+
### 📦 Install the package
|
|
132
|
+
|
|
133
|
+
Install the UI Vintage library and the peer integrations used by the package in an existing Nuxt 4 application:
|
|
18
134
|
|
|
19
135
|
```bash
|
|
20
136
|
npm install @brumaombra/ui-vintage @nuxt/image vue-i18n
|
|
21
137
|
```
|
|
22
138
|
|
|
23
|
-
Register the module
|
|
139
|
+
### 🔌 Register the module
|
|
140
|
+
|
|
141
|
+
Add the module to `nuxt.config.js`:
|
|
24
142
|
|
|
25
|
-
```
|
|
143
|
+
```js
|
|
26
144
|
export default defineNuxtConfig({
|
|
27
|
-
modules: [
|
|
28
|
-
|
|
145
|
+
modules: [
|
|
146
|
+
'@brumaombra/ui-vintage'
|
|
147
|
+
]
|
|
148
|
+
});
|
|
29
149
|
```
|
|
30
150
|
|
|
31
|
-
|
|
151
|
+
`@nuxt/image` is installed by the module when it is not already present in the app’s module list. Install it explicitly when your application also uses image components directly. Vue I18n is optional at runtime, but it is required for the library’s locale messages and translated components.
|
|
32
152
|
|
|
33
|
-
|
|
153
|
+
<a id="usage"></a>
|
|
154
|
+
## 🧪 Usage
|
|
34
155
|
|
|
35
|
-
|
|
156
|
+
### 🧱 Use a component
|
|
36
157
|
|
|
37
|
-
|
|
38
|
-
- components are imported from explicit subpaths such as `@brumaombra/ui-vintage/button`
|
|
39
|
-
- helpers are imported from explicit subpaths such as `@brumaombra/ui-vintage/message-dialog`
|
|
40
|
-
|
|
41
|
-
Example:
|
|
158
|
+
Components are imported from explicit package subpaths:
|
|
42
159
|
|
|
43
160
|
```vue
|
|
44
|
-
<script setup
|
|
45
|
-
import { Button } from '@brumaombra/ui-vintage/button'
|
|
46
|
-
import { Card, CardContent } from '@brumaombra/ui-vintage/card'
|
|
161
|
+
<script setup>
|
|
162
|
+
import { Button } from '@brumaombra/ui-vintage/button';
|
|
163
|
+
import { Card, CardContent } from '@brumaombra/ui-vintage/card';
|
|
47
164
|
</script>
|
|
48
165
|
|
|
49
166
|
<template>
|
|
50
|
-
<Button>Save</Button>
|
|
51
167
|
<Card>
|
|
52
|
-
<CardContent
|
|
168
|
+
<CardContent class="flex items-center justify-between gap-4">
|
|
169
|
+
<span>Workspace status</span>
|
|
170
|
+
|
|
171
|
+
<!-- For example, the Button component accepts variants such as primary, secondary, gray, and ghost -->
|
|
172
|
+
<Button variant="primary">Save changes</Button>
|
|
173
|
+
</CardContent>
|
|
53
174
|
</Card>
|
|
54
175
|
</template>
|
|
55
176
|
```
|
|
56
177
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
178
|
+
### 🔔 Use a message flow
|
|
179
|
+
|
|
180
|
+
The dialog and busy helpers can be imported directly from their subpaths:
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
import { showConfirmDialog } from '@brumaombra/ui-vintage/confirm-dialog';
|
|
184
|
+
import { setBusy } from '@brumaombra/ui-vintage/busy-indicator';
|
|
185
|
+
|
|
186
|
+
// Ask for confirmation before starting a destructive action
|
|
187
|
+
const confirmed = await showConfirmDialog({
|
|
188
|
+
title: 'Delete project?',
|
|
189
|
+
message: 'This action cannot be undone.'
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
if (confirmed) {
|
|
193
|
+
// Keep the shared loading state visible while the request is running
|
|
194
|
+
setBusy({
|
|
195
|
+
title: 'Deleting project',
|
|
196
|
+
description: 'Please wait while the project is removed.'
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 🧭 Use a layout component
|
|
202
|
+
|
|
203
|
+
Higher-level components accept slots so application navigation and content remain app-owned. The shell provides the layout; the application provides its navigation data:
|
|
204
|
+
|
|
205
|
+
```vue
|
|
206
|
+
<script setup>
|
|
207
|
+
import { DashboardShell } from '@brumaombra/ui-vintage/dashboard-shell';
|
|
208
|
+
|
|
209
|
+
// List of sections
|
|
210
|
+
const sidebarSections = [{
|
|
211
|
+
id: 'workspace',
|
|
212
|
+
label: 'Workspace',
|
|
213
|
+
items: [
|
|
214
|
+
{ id: 'overview', label: 'Overview', href: '/', active: true },
|
|
215
|
+
{ id: 'settings', label: 'Settings', href: '/settings' }
|
|
216
|
+
]
|
|
217
|
+
}];
|
|
218
|
+
</script>
|
|
219
|
+
|
|
220
|
+
<template>
|
|
221
|
+
<DashboardShell :sidebar-sections="sidebarSections">
|
|
222
|
+
<slot />
|
|
223
|
+
</DashboardShell>
|
|
224
|
+
</template>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
<a id="components"></a>
|
|
228
|
+
## 🧩 Components
|
|
229
|
+
|
|
230
|
+
The package exposes components through explicit subpaths. The complete public export map is maintained in `package.json`; common groups include:
|
|
231
|
+
|
|
232
|
+
### 🎛️ UI primitives
|
|
233
|
+
|
|
234
|
+
`alert`, `alert-dialog`, `accordion`, `badge`, `breadcrumb`, `button`, `calendar`, `card`, `command`, `dialog`, `field`, `input`, `label`, `popover`, `progress`, `scroll-area`, `select`, `separator`, `sheet`, `sidebar`, `skeleton`, `slider`, `switch`, `table`, `tabs`, `textarea`, `time-picker`, and `tooltip`.
|
|
235
|
+
|
|
236
|
+
### 🧱 Composite components
|
|
237
|
+
|
|
238
|
+
`background-grid`, `card-grid`, `chip`, `dashboard-shell`, `data-list`, `empty-state-card`, `error-page`, `info-card`, `landing`, `landing-content`, `landing-footer`, `landing-navbar`, `landing-shell`, `load-more-button`, `loading-state-card`, `page-header`, `progress-component`, `single-value-card`, `text-link`, and `theme-selector`.
|
|
239
|
+
|
|
240
|
+
### 💬 Runtime flows and integrations
|
|
241
|
+
|
|
242
|
+
`busy`, `busy-indicator`, `confirm-dialog`, `message-dialog`, `message-toast`, `language-flag`, `language-selector`, `blog`, `content`, and `utils`.
|
|
243
|
+
|
|
244
|
+
<a id="demo-app"></a>
|
|
245
|
+
## 🖥️ Demo App
|
|
246
|
+
|
|
247
|
+
The private `demo-app/` directory is a Nuxt 4 showcase for manual verification. It demonstrates the public components, shared theme behavior, responsive layouts, form states, dialogs, toasts, tabs, accordions, localization, and dashboard composition.
|
|
248
|
+
|
|
249
|
+
The demo app is not part of the published package and is not intended to be installed by consumers. It imports the package through `file:..`, so it exercises the same source that is published to npm.
|
|
60
250
|
|
|
61
|
-
|
|
62
|
-
title: 'Delete item?',
|
|
63
|
-
description: 'This action cannot be undone.'
|
|
64
|
-
})
|
|
251
|
+
### ▶️ Run the showcase locally
|
|
65
252
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
253
|
+
From the repository root:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Install dependencies for the demo app
|
|
257
|
+
npm --prefix demo-app install
|
|
258
|
+
|
|
259
|
+
# Start the Nuxt development server
|
|
260
|
+
npm --prefix demo-app run dev
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Open the local URL printed by Nuxt. To create a production build of the showcase:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Build the private verification app
|
|
267
|
+
npm --prefix demo-app run build
|
|
70
268
|
```
|
|
71
269
|
|
|
72
|
-
|
|
270
|
+
<a id="configuration"></a>
|
|
271
|
+
## ⚙️ Configuration
|
|
272
|
+
|
|
273
|
+
### 🎨 Styles
|
|
274
|
+
|
|
275
|
+
The module injects the shared stylesheet automatically. The stylesheet is also available as an explicit export when an app needs to control loading order:
|
|
276
|
+
|
|
277
|
+
```js
|
|
278
|
+
// Import the shared tokens and component styles explicitly when needed
|
|
279
|
+
import '@brumaombra/ui-vintage/style.css';
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Avoid creating a second theme-token system in the consuming app. Extend the existing CSS custom properties in your application stylesheet when a project needs additional brand values.
|
|
283
|
+
|
|
284
|
+
### 🌍 Localization
|
|
285
|
+
|
|
286
|
+
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.
|
|
287
|
+
|
|
288
|
+
Application-specific translations remain owned by the consuming app. The library only contributes messages under its own `uiVintage` namespace.
|
|
289
|
+
|
|
290
|
+
### 🧭 Imports
|
|
291
|
+
|
|
292
|
+
Use explicit subpaths for public imports:
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
// Import a component from its stable public entrypoint
|
|
296
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@brumaombra/ui-vintage/tabs';
|
|
297
|
+
|
|
298
|
+
// Import shared helper behavior from its dedicated entrypoint
|
|
299
|
+
import { showMessageToast } from '@brumaombra/ui-vintage/message-toast';
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Do not import internal files from `src/components/` in application code. Internal paths are implementation details and may change independently of public entrypoints.
|
|
303
|
+
|
|
304
|
+
<a id="publishing"></a>
|
|
305
|
+
## 📦 Publishing Model
|
|
306
|
+
|
|
307
|
+
UI Vintage publishes the Nuxt module entrypoint and source files directly:
|
|
308
|
+
|
|
309
|
+
- `module.mjs` is the package entrypoint registered by Nuxt.
|
|
310
|
+
- `src/` contains the published components, styles, helpers, locale messages, and runtime plugin.
|
|
311
|
+
- `package.json` defines the public component subpath exports.
|
|
312
|
+
- `dist/` is generated repository output and is not the source of truth for consumers.
|
|
313
|
+
|
|
314
|
+
There is no required library build step before publishing. The normal verification command is:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Check the published TypeScript and Vue source without generating dist output
|
|
318
|
+
npm run typecheck
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
For release details, see [NPM.md](NPM.md). The package is published under the public npm scope `@brumaombra/ui-vintage`.
|
|
322
|
+
|
|
323
|
+
<a id="requirements"></a>
|
|
324
|
+
## 🧰 Requirements
|
|
73
325
|
|
|
74
|
-
|
|
326
|
+
- Node.js compatible with the Nuxt 4 version used by the consuming app.
|
|
327
|
+
- Nuxt 4.
|
|
328
|
+
- Vue 3.5 or newer.
|
|
329
|
+
- `@nuxt/image` for image-enabled components. The module installs it when needed.
|
|
330
|
+
- `vue-i18n` when using the library’s localization integration.
|
|
75
331
|
|
|
76
|
-
|
|
332
|
+
<a id="troubleshooting"></a>
|
|
333
|
+
## 🛠️ Troubleshooting
|
|
77
334
|
|
|
78
|
-
- Nuxt 4
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
335
|
+
- **Components cannot resolve Nuxt imports:** confirm the app is Nuxt 4 and that `@brumaombra/ui-vintage` is registered in `nuxt.config.js`.
|
|
336
|
+
- **Styles are missing:** check that the module is registered once and restart the Nuxt dev server after changing `nuxt.config.js`.
|
|
337
|
+
- **`NuxtImg` is unavailable:** install `@nuxt/image` or allow the UI Vintage module to install it during Nuxt setup.
|
|
338
|
+
- **Translations do not appear:** configure Vue I18n or `@nuxtjs/i18n`; the runtime plugin merges messages only when an i18n composer is available.
|
|
339
|
+
- **A component import fails:** use the public subpath listed in `package.json`, such as `@brumaombra/ui-vintage/button`, rather than an internal `src/` path.
|
|
340
|
+
- **The demo app does not start:** run `npm --prefix demo-app install` from the repository root, then retry `npm --prefix demo-app run dev`.
|
|
82
341
|
|
|
83
|
-
|
|
342
|
+
<a id="license"></a>
|
|
343
|
+
## 📄 License
|
|
84
344
|
|
|
85
|
-
MIT
|
|
345
|
+
This project is released under the MIT License. See [LICENSE](LICENSE) for the full license text.
|
package/module.mjs
CHANGED
|
@@ -69,7 +69,7 @@ export default defineNuxtModule({
|
|
|
69
69
|
|
|
70
70
|
// Add the plugin to merge the library translations into the app i18n instance at runtime
|
|
71
71
|
addPlugin({
|
|
72
|
-
src: resolver.resolve('src/runtime/ui-vintage-i18n-plugin.
|
|
72
|
+
src: resolver.resolve('src/runtime/ui-vintage-i18n-plugin.ts')
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brumaombra/ui-vintage",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9",
|
|
4
4
|
"description": "Source-published Nuxt UI runtime with shared theme tokens and built-in Nuxt integrations.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Mauro Brambilla",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"./error-page": "./src/components/error-page/index.ts",
|
|
62
62
|
"./field": "./src/components/ui/field/index.ts",
|
|
63
63
|
"./info-card": "./src/components/info-card/index.ts",
|
|
64
|
+
"./common-types": "./src/lib/common-types.ts",
|
|
64
65
|
"./input": "./src/components/ui/input/index.ts",
|
|
65
66
|
"./label": "./src/components/ui/label/index.ts",
|
|
66
67
|
"./landing": "./src/components/landing/index.ts",
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
|
|
4
|
+
// Props
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes['class'];
|
|
7
|
+
}>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
1
10
|
<template>
|
|
2
|
-
<div class="pointer-events-none absolute inset-0 z-0 overflow-hidden">
|
|
3
|
-
<div class="absolute inset-0 bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[
|
|
11
|
+
<div :class="['pointer-events-none absolute inset-0 z-0 overflow-hidden', props.class]">
|
|
12
|
+
<div class="absolute inset-0 bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-size-[20px_20px] dark:bg-[linear-gradient(to_right,#ffffff0d_1px,transparent_1px),linear-gradient(to_bottom,#ffffff0d_1px,transparent_1px)]" />
|
|
4
13
|
</div>
|
|
5
14
|
</template>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as BackgroundGrid } from
|
|
1
|
+
export { default } from './BackgroundGrid.vue';
|
|
2
|
+
export { default as BackgroundGrid } from './BackgroundGrid.vue';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue';
|
|
3
3
|
import { useI18n } from 'vue-i18n';
|
|
4
4
|
import { LoadMoreButton } from '../load-more-button';
|
|
@@ -7,17 +7,33 @@ import PostsList from './PostsList.vue';
|
|
|
7
7
|
const { t } = useI18n();
|
|
8
8
|
|
|
9
9
|
// Props
|
|
10
|
-
const props = defineProps
|
|
11
|
-
posts
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
const props = withDefaults(defineProps<{
|
|
11
|
+
posts?: Array<{
|
|
12
|
+
path: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
image?: string;
|
|
16
|
+
categoryText?: string;
|
|
17
|
+
categoryPath?: string;
|
|
18
|
+
}>;
|
|
19
|
+
currentPage?: number;
|
|
20
|
+
postsPerPage?: number;
|
|
21
|
+
totalPosts?: number;
|
|
22
|
+
hasMorePosts?: boolean;
|
|
23
|
+
isLoading?: boolean;
|
|
24
|
+
}>(), {
|
|
25
|
+
posts: () => [],
|
|
26
|
+
currentPage: 1,
|
|
27
|
+
postsPerPage: 9,
|
|
28
|
+
totalPosts: 0,
|
|
29
|
+
hasMorePosts: false,
|
|
30
|
+
isLoading: false
|
|
17
31
|
});
|
|
18
32
|
|
|
19
33
|
// Emits
|
|
20
|
-
const emits = defineEmits
|
|
34
|
+
const emits = defineEmits<{
|
|
35
|
+
'load-more': [];
|
|
36
|
+
}>();
|
|
21
37
|
|
|
22
38
|
// Handle load more posts
|
|
23
39
|
const handleLoadMorePosts = () => {
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue';
|
|
3
3
|
import { useI18n } from 'vue-i18n';
|
|
4
4
|
import { Accordion } from '@brumaombra/ui-vintage/accordion';
|
|
5
5
|
import BlogSectionTitle from './BlogSectionTitle.vue';
|
|
6
6
|
|
|
7
7
|
// Props
|
|
8
|
-
const props = defineProps
|
|
9
|
-
faqs
|
|
8
|
+
const props = withDefaults(defineProps<{
|
|
9
|
+
faqs?: Array<{
|
|
10
|
+
question: string;
|
|
11
|
+
answer: string;
|
|
12
|
+
}>;
|
|
13
|
+
}>(), {
|
|
14
|
+
faqs: () => []
|
|
10
15
|
});
|
|
11
16
|
|
|
12
17
|
const { t } = useI18n();
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { ToneColor } from '../../lib/color-tokens';
|
|
2
3
|
import { Badge } from '../ui/badge';
|
|
3
4
|
|
|
4
5
|
// Props
|
|
5
|
-
const props = defineProps
|
|
6
|
-
badges
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
title:
|
|
11
|
-
description:
|
|
6
|
+
const props = withDefaults(defineProps<{
|
|
7
|
+
badges?: Array<{
|
|
8
|
+
color: ToneColor;
|
|
9
|
+
text: string;
|
|
10
|
+
}>;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
}>(), {
|
|
14
|
+
badges: () => []
|
|
12
15
|
});
|
|
13
16
|
</script>
|
|
14
17
|
|
|
15
18
|
<template>
|
|
16
|
-
<div class="flex flex-col space-y-6 md
|
|
19
|
+
<div class="flex flex-col space-y-6 md:space-y-8!">
|
|
17
20
|
<!-- Badges -->
|
|
18
21
|
<div v-if="props.badges.length > 0" class="flex flex-wrap gap-3 mb-6 md:mb-8">
|
|
19
22
|
<Badge v-for="badge in props.badges"
|
|
@@ -23,12 +26,12 @@ const props = defineProps({
|
|
|
23
26
|
</div>
|
|
24
27
|
|
|
25
28
|
<!-- Title -->
|
|
26
|
-
<h1 class="text-3xl md:text-6xl font-bold text-
|
|
29
|
+
<h1 class="text-3xl md:text-6xl font-bold text-(--text-primary-light) dark:text-(--text-primary-dark) leading-tight">
|
|
27
30
|
{{ props.title }}
|
|
28
31
|
</h1>
|
|
29
32
|
|
|
30
33
|
<!-- Description -->
|
|
31
|
-
<p class="text-sm md:text-xl text-
|
|
34
|
+
<p class="text-sm md:text-xl text-(--text-secondary-light) dark:text-(--text-secondary-dark) leading-relaxed">
|
|
32
35
|
{{ props.description }}
|
|
33
36
|
</p>
|
|
34
37
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { NuxtImg } from '#components';
|
|
3
3
|
import { computed } from 'vue';
|
|
4
4
|
import { useI18n } from 'vue-i18n';
|
|
@@ -6,12 +6,14 @@ import { Card, CardContent } from '../ui/card';
|
|
|
6
6
|
import { formatDateLongItalyTimezone } from '../../lib/utils';
|
|
7
7
|
|
|
8
8
|
// Props
|
|
9
|
-
const props = defineProps
|
|
10
|
-
author:
|
|
11
|
-
authorUrl:
|
|
12
|
-
authorImageUrl:
|
|
13
|
-
datePublished:
|
|
14
|
-
dateModified
|
|
9
|
+
const props = withDefaults(defineProps<{
|
|
10
|
+
author: string;
|
|
11
|
+
authorUrl: string;
|
|
12
|
+
authorImageUrl: string;
|
|
13
|
+
datePublished: string;
|
|
14
|
+
dateModified?: string | null;
|
|
15
|
+
}>(), {
|
|
16
|
+
dateModified: null
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
const { t, locale } = useI18n();
|
|
@@ -36,9 +38,9 @@ const formattedModifiedDate = computed(() => formatDateLongItalyTimezone(props.d
|
|
|
36
38
|
|
|
37
39
|
<!-- Author name -->
|
|
38
40
|
<div>
|
|
39
|
-
<p class="text-sm text-
|
|
40
|
-
<p class="font-bold text-
|
|
41
|
-
<NuxtLink :to="props.authorUrl" target="_blank" rel="noopener noreferrer" class="hover:text-
|
|
41
|
+
<p class="text-sm text-(--text-secondary-light) dark:text-(--text-secondary-dark)">{{ t('uiVintage.blog.author') }}</p>
|
|
42
|
+
<p class="font-bold text-(--text-primary-light) dark:text-(--text-primary-dark)">
|
|
43
|
+
<NuxtLink :to="props.authorUrl" target="_blank" rel="noopener noreferrer" class="hover:text-(--text-secondary-light) dark:hover:text-(--text-secondary-dark) transition-colors">
|
|
42
44
|
{{ props.author }}
|
|
43
45
|
</NuxtLink>
|
|
44
46
|
</p>
|
|
@@ -47,7 +49,7 @@ const formattedModifiedDate = computed(() => formatDateLongItalyTimezone(props.d
|
|
|
47
49
|
</div>
|
|
48
50
|
|
|
49
51
|
<!-- Date information -->
|
|
50
|
-
<div class="flex flex-col sm:items-end text-xs md:text-sm text-
|
|
52
|
+
<div class="flex flex-col sm:items-end text-xs md:text-sm text-(--text-secondary-light) dark:text-(--text-secondary-dark)">
|
|
51
53
|
<!-- Published date -->
|
|
52
54
|
<div v-if="props.datePublished" class="mb-1">
|
|
53
55
|
<span class="font-semibold">{{ t('uiVintage.blog.publishedDate') }}:</span>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
// Props
|
|
3
|
-
const props = defineProps
|
|
4
|
-
title:
|
|
5
|
-
});
|
|
3
|
+
const props = defineProps<{
|
|
4
|
+
title: string;
|
|
5
|
+
}>();
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<template>
|
|
9
|
-
<h2 class="text-xl md:text-2xl font-bold text-
|
|
9
|
+
<h2 class="text-xl md:text-2xl font-bold text-(--text-primary-light) dark:text-(--text-primary-dark) mb-5">
|
|
10
10
|
{{ props.title }}
|
|
11
11
|
</h2>
|
|
12
12
|
</template>
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import CategoryCard from './CategoryCard.vue';
|
|
3
3
|
|
|
4
4
|
// Props
|
|
5
|
-
const props = defineProps
|
|
6
|
-
categories
|
|
5
|
+
const props = withDefaults(defineProps<{
|
|
6
|
+
categories?: Array<{
|
|
7
|
+
path: string;
|
|
8
|
+
slug?: string;
|
|
9
|
+
name: string;
|
|
10
|
+
image?: string;
|
|
11
|
+
count: number;
|
|
12
|
+
}>;
|
|
13
|
+
}>(), {
|
|
14
|
+
categories: () => []
|
|
7
15
|
});
|
|
8
16
|
</script>
|
|
9
17
|
|