@brumaombra/ui-vintage 0.7.8 → 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 +43 -64
- 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/ui/accordion/Accordion.vue +10 -13
- 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
|
@@ -4,23 +4,33 @@ import { useI18n } from 'vue-i18n';
|
|
|
4
4
|
import { PackageIcon } from '@hugeicons/core-free-icons';
|
|
5
5
|
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
6
6
|
import { Card, CardContent } from '../ui/card';
|
|
7
|
+
import type { HugeiconsIconDefinition } from '../../lib/common-types';
|
|
7
8
|
|
|
8
9
|
// Props
|
|
9
|
-
const props = defineProps
|
|
10
|
-
icon
|
|
11
|
-
title
|
|
12
|
-
description
|
|
13
|
-
titleKey
|
|
14
|
-
descriptionKey
|
|
10
|
+
const props = withDefaults(defineProps<{
|
|
11
|
+
icon?: HugeiconsIconDefinition;
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
titleKey?: string;
|
|
15
|
+
descriptionKey?: string;
|
|
16
|
+
}>(), {
|
|
17
|
+
icon: () => PackageIcon,
|
|
18
|
+
title: '',
|
|
19
|
+
description: '',
|
|
20
|
+
titleKey: '',
|
|
21
|
+
descriptionKey: ''
|
|
15
22
|
});
|
|
16
23
|
|
|
17
24
|
const { t } = useI18n();
|
|
18
|
-
|
|
19
25
|
const hasCustomCopy = computed(() => Boolean(props.title || props.description || props.titleKey || props.descriptionKey));
|
|
26
|
+
|
|
27
|
+
// Title
|
|
20
28
|
const resolvedTitle = computed(() => props.title
|
|
21
29
|
|| (props.titleKey ? t(props.titleKey) : '')
|
|
22
30
|
|| (!hasCustomCopy.value ? t('uiVintage.common.empty.title') : '')
|
|
23
31
|
|| (!hasCustomCopy.value ? 'Nothing here yet' : ''));
|
|
32
|
+
|
|
33
|
+
// Description
|
|
24
34
|
const resolvedDescription = computed(() => props.description
|
|
25
35
|
|| (props.descriptionKey ? t(props.descriptionKey) : '')
|
|
26
36
|
|| (!hasCustomCopy.value ? t('uiVintage.common.empty.description') : '')
|
|
@@ -29,19 +39,19 @@ const resolvedDescription = computed(() => props.description
|
|
|
29
39
|
|
|
30
40
|
<template>
|
|
31
41
|
<Card class="flex flex-col items-center justify-center px-4 py-8 text-center md:py-12">
|
|
32
|
-
<CardContent class="flex flex-col items-center justify-center
|
|
42
|
+
<CardContent class="flex flex-col items-center justify-center p-0! text-center">
|
|
33
43
|
<!-- Icon -->
|
|
34
|
-
<div class="flex items-center justify-center text-4xl text-
|
|
44
|
+
<div class="flex items-center justify-center text-4xl text-(--text-secondary-light) opacity-40 dark:text-(--text-secondary-dark)">
|
|
35
45
|
<HugeiconsIcon :icon="props.icon" class="size-10" />
|
|
36
46
|
</div>
|
|
37
47
|
|
|
38
48
|
<!-- Title -->
|
|
39
|
-
<h3 v-if="resolvedTitle" class="text-sm font-bold text-
|
|
49
|
+
<h3 v-if="resolvedTitle" class="text-sm font-bold text-(--text-primary-light) dark:text-(--text-primary-dark) md:text-lg">
|
|
40
50
|
{{ resolvedTitle }}
|
|
41
51
|
</h3>
|
|
42
52
|
|
|
43
53
|
<!-- Description -->
|
|
44
|
-
<p v-if="resolvedDescription" class="max-w-md text-xs text-
|
|
54
|
+
<p v-if="resolvedDescription" class="max-w-md text-xs text-(--text-secondary-light) dark:text-(--text-secondary-dark) md:text-sm">
|
|
45
55
|
{{ resolvedDescription }}
|
|
46
56
|
</p>
|
|
47
57
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { cn } from "../../lib/utils";
|
|
2
|
+
import { ArrowLeft01Icon } from '@hugeicons/core-free-icons';
|
|
3
|
+
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
4
|
+
import { computed, type HTMLAttributes } from 'vue';
|
|
5
|
+
import BackgroundGrid from '../background-grid/BackgroundGrid.vue';
|
|
6
|
+
import { Button } from '../ui/button';
|
|
7
|
+
import { Card, CardContent, CardFooter } from '../ui/card';
|
|
8
|
+
import { cn } from '../../lib/utils';
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
// Props
|
|
11
|
+
const props = withDefaults(defineProps<{
|
|
12
12
|
statusCode?: number | string;
|
|
13
13
|
label?: string;
|
|
14
14
|
title?: string;
|
|
@@ -16,19 +16,16 @@ interface ErrorPageProps {
|
|
|
16
16
|
actionLabel?: string;
|
|
17
17
|
showBackground?: boolean;
|
|
18
18
|
showDefaultAction?: boolean;
|
|
19
|
-
class?: HTMLAttributes[
|
|
20
|
-
cardClass?: HTMLAttributes[
|
|
21
|
-
contentClass?: HTMLAttributes[
|
|
22
|
-
footerClass?: HTMLAttributes[
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Props
|
|
26
|
-
const props = withDefaults(defineProps<ErrorPageProps>(), {
|
|
19
|
+
class?: HTMLAttributes['class'];
|
|
20
|
+
cardClass?: HTMLAttributes['class'];
|
|
21
|
+
contentClass?: HTMLAttributes['class'];
|
|
22
|
+
footerClass?: HTMLAttributes['class'];
|
|
23
|
+
}>(), {
|
|
27
24
|
statusCode: 500,
|
|
28
|
-
label:
|
|
25
|
+
label: 'Error',
|
|
29
26
|
title: undefined,
|
|
30
27
|
message: undefined,
|
|
31
|
-
actionLabel:
|
|
28
|
+
actionLabel: 'Go back',
|
|
32
29
|
showBackground: true,
|
|
33
30
|
showDefaultAction: true,
|
|
34
31
|
class: undefined,
|
|
@@ -47,25 +44,25 @@ const resolvedStatusCode = computed(() => String(props.statusCode ?? 500));
|
|
|
47
44
|
// Resolve the heading copy.
|
|
48
45
|
const resolvedTitle = computed(() => {
|
|
49
46
|
if (props.title) return props.title;
|
|
50
|
-
if (resolvedStatusCode.value ===
|
|
51
|
-
return
|
|
47
|
+
if (resolvedStatusCode.value === '404') return 'Page not found';
|
|
48
|
+
return 'Something went wrong';
|
|
52
49
|
});
|
|
53
50
|
|
|
54
51
|
// Resolve the supporting message.
|
|
55
52
|
const resolvedMessage = computed(() => {
|
|
56
53
|
if (props.message) return props.message;
|
|
57
|
-
if (resolvedStatusCode.value ===
|
|
58
|
-
return
|
|
54
|
+
if (resolvedStatusCode.value === '404') return 'The page you requested could not be found or may have been moved.';
|
|
55
|
+
return 'An unexpected error interrupted the current flow. Please try again or go back to a safe page.';
|
|
59
56
|
});
|
|
60
57
|
|
|
61
58
|
// Emit the default action.
|
|
62
59
|
const handleAction = () => {
|
|
63
|
-
emit(
|
|
60
|
+
emit('action');
|
|
64
61
|
};
|
|
65
62
|
</script>
|
|
66
63
|
|
|
67
64
|
<template>
|
|
68
|
-
<div :class="cn('relative min-h-screen bg-
|
|
65
|
+
<div :class="cn('relative min-h-screen bg-(--bg-main-light) text-(--text-primary-light) dark:bg-(--bg-main-dark) dark:text-(--text-primary-dark)', props.class)">
|
|
69
66
|
<!-- Decorative background -->
|
|
70
67
|
<BackgroundGrid v-if="props.showBackground" />
|
|
71
68
|
|
|
@@ -86,7 +83,7 @@ const handleAction = () => {
|
|
|
86
83
|
<!-- Error copy -->
|
|
87
84
|
<div>
|
|
88
85
|
<!-- Status code -->
|
|
89
|
-
<div class="text-sm font-semibold uppercase tracking-[0.24em] text-
|
|
86
|
+
<div class="text-sm font-semibold uppercase tracking-[0.24em] text-(--button-primary-light) dark:text-(--button-primary-dark)">
|
|
90
87
|
{{ props.label }} {{ resolvedStatusCode }}
|
|
91
88
|
</div>
|
|
92
89
|
|
|
@@ -96,7 +93,7 @@ const handleAction = () => {
|
|
|
96
93
|
</h1>
|
|
97
94
|
|
|
98
95
|
<!-- Message -->
|
|
99
|
-
<p class="text-sm leading-7 text-
|
|
96
|
+
<p class="text-sm leading-7 text-(--text-secondary-light) dark:text-(--text-secondary-dark) sm:text-base mt-4">
|
|
100
97
|
{{ resolvedMessage }}
|
|
101
98
|
</p>
|
|
102
99
|
</div>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as ErrorPage } from
|
|
1
|
+
export { default } from './ErrorPage.vue';
|
|
2
|
+
export { default as ErrorPage } from './ErrorPage.vue';
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { HugeiconsIcon } from
|
|
3
|
-
import {
|
|
2
|
+
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
3
|
+
import type { HTMLAttributes } from 'vue';
|
|
4
|
+
import { Card, CardContent, CardText } from '../ui/card';
|
|
5
|
+
import type { HugeiconsIconDefinition } from '../../lib/common-types';
|
|
4
6
|
|
|
5
7
|
// Props
|
|
6
|
-
const props = defineProps
|
|
7
|
-
icon:
|
|
8
|
-
title
|
|
9
|
-
description
|
|
10
|
-
|
|
8
|
+
const props = withDefaults(defineProps<{
|
|
9
|
+
icon: HugeiconsIconDefinition;
|
|
10
|
+
title?: string;
|
|
11
|
+
description?: string | number;
|
|
12
|
+
class?: HTMLAttributes['class'];
|
|
13
|
+
}>(), {
|
|
14
|
+
title: '',
|
|
15
|
+
description: ''
|
|
16
|
+
});
|
|
11
17
|
</script>
|
|
12
18
|
|
|
13
19
|
<template>
|
|
14
|
-
<Card class="flex flex-col items-center
|
|
15
|
-
<CardContent class="flex w-full flex-col items-center gap-0
|
|
20
|
+
<Card :class="['flex flex-col items-center p-4! sm:flex-row', props.class]">
|
|
21
|
+
<CardContent class="flex w-full flex-col items-center gap-0 p-0! sm:flex-row">
|
|
16
22
|
<!-- Icon -->
|
|
17
|
-
<Card color="gray" class="mb-3 mr-0 flex h-12 w-12
|
|
23
|
+
<Card color="gray" class="mb-3 mr-0 flex h-12 w-12 shrink-0 items-center justify-center p-0! sm:mb-0 sm:mr-4">
|
|
18
24
|
<HugeiconsIcon :icon="props.icon" class="size-5" />
|
|
19
25
|
</Card>
|
|
20
26
|
|
|
@@ -22,7 +28,7 @@ const props = defineProps({
|
|
|
22
28
|
<div class="flex w-full flex-1 items-center justify-between text-center sm:w-auto sm:text-left">
|
|
23
29
|
<div class="flex flex-col w-full gap-2 sm:gap-1">
|
|
24
30
|
<!-- Title -->
|
|
25
|
-
<span class="text-base font-bold text-
|
|
31
|
+
<span class="text-base font-bold text-(--text-primary-light) dark:text-(--text-primary-dark)">
|
|
26
32
|
{{ props.title }}
|
|
27
33
|
</span>
|
|
28
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as LandingContent } from
|
|
3
|
-
export { default as LandingShell } from
|
|
4
|
-
export { default as LandingNavbar } from
|
|
5
|
-
export { default as LandingFooter } from
|
|
6
|
-
export type { LandingFooterLink, LandingFooterSection } from
|
|
1
|
+
export { default } from './landing-navbar';
|
|
2
|
+
export { default as LandingContent } from './landing-content';
|
|
3
|
+
export { default as LandingShell } from './landing-shell';
|
|
4
|
+
export { default as LandingNavbar } from './landing-navbar';
|
|
5
|
+
export { default as LandingFooter } from './landing-footer';
|
|
6
|
+
export type { LandingFooterLink, LandingFooterSection } from './landing-footer';
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from
|
|
3
|
-
import { cn } from
|
|
4
|
-
|
|
5
|
-
interface LandingContentProps {
|
|
6
|
-
class?: HTMLAttributes["class"];
|
|
7
|
-
}
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
import { cn } from '../../../lib/utils';
|
|
8
4
|
|
|
9
5
|
// Props
|
|
10
|
-
const props = defineProps<
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
class?: HTMLAttributes['class'];
|
|
8
|
+
}>();
|
|
11
9
|
</script>
|
|
12
10
|
|
|
13
11
|
<template>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as LandingContent } from
|
|
1
|
+
export { default } from './LandingContent.vue';
|
|
2
|
+
export { default as LandingContent } from './LandingContent.vue';
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { NuxtImg } from
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { cn } from "../../../lib/utils";
|
|
2
|
+
import { NuxtImg } from '#components';
|
|
3
|
+
import { FavouriteIcon } from '@hugeicons/core-free-icons';
|
|
4
|
+
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
5
|
+
import { computed, type Component, type HTMLAttributes } from 'vue';
|
|
6
|
+
import { useI18n } from 'vue-i18n';
|
|
7
|
+
import { cn } from '../../../lib/utils';
|
|
9
8
|
|
|
10
9
|
export interface LandingFooterLink {
|
|
11
10
|
id: string;
|
|
@@ -21,7 +20,8 @@ export interface LandingFooterSection {
|
|
|
21
20
|
links: LandingFooterLink[];
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
// Props
|
|
24
|
+
const props = withDefaults(defineProps<{
|
|
25
25
|
appName: string;
|
|
26
26
|
appLogo?: string;
|
|
27
27
|
appLinkTo?: string;
|
|
@@ -32,21 +32,18 @@ interface LandingFooterProps {
|
|
|
32
32
|
authorLink?: string;
|
|
33
33
|
year?: number;
|
|
34
34
|
showBottomBar?: boolean;
|
|
35
|
-
class?: HTMLAttributes[
|
|
36
|
-
containerClass?: HTMLAttributes[
|
|
37
|
-
brandClass?: HTMLAttributes[
|
|
38
|
-
sectionsClass?: HTMLAttributes[
|
|
39
|
-
bottomBarClass?: HTMLAttributes[
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const props = withDefaults(defineProps<LandingFooterProps>(), {
|
|
44
|
-
appLinkTo: "/",
|
|
45
|
-
appDescription: "",
|
|
35
|
+
class?: HTMLAttributes['class'];
|
|
36
|
+
containerClass?: HTMLAttributes['class'];
|
|
37
|
+
brandClass?: HTMLAttributes['class'];
|
|
38
|
+
sectionsClass?: HTMLAttributes['class'];
|
|
39
|
+
bottomBarClass?: HTMLAttributes['class'];
|
|
40
|
+
}>(), {
|
|
41
|
+
appLinkTo: '/',
|
|
42
|
+
appDescription: '',
|
|
46
43
|
sections: () => [],
|
|
47
|
-
linkComponent:
|
|
48
|
-
authorName:
|
|
49
|
-
authorLink:
|
|
44
|
+
linkComponent: 'a',
|
|
45
|
+
authorName: '',
|
|
46
|
+
authorLink: '',
|
|
50
47
|
year: () => new Date().getFullYear(),
|
|
51
48
|
showBottomBar: true
|
|
52
49
|
});
|
|
@@ -56,19 +53,19 @@ const hasSingleSection = computed(() => props.sections.length === 1);
|
|
|
56
53
|
|
|
57
54
|
// Get link props based on the type of link component and whether the link should open in a new tab
|
|
58
55
|
const getLinkProps = (link: LandingFooterLink) => {
|
|
59
|
-
const sharedProps = link.newTab ? { target:
|
|
56
|
+
const sharedProps = link.newTab ? { target: '_blank', rel: 'noopener noreferrer' } : {};
|
|
60
57
|
|
|
61
58
|
// If the link component is an anchor, use href. Otherwise, use to for router links.
|
|
62
|
-
if (props.linkComponent ===
|
|
59
|
+
if (props.linkComponent === 'a') {
|
|
63
60
|
return {
|
|
64
|
-
href: link.href ??
|
|
61
|
+
href: link.href ?? '#',
|
|
65
62
|
...sharedProps
|
|
66
63
|
};
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
// For non-anchor link components, assume they use a "to" prop (like Vue Router's <RouterLink>).
|
|
70
67
|
return {
|
|
71
|
-
to: link.to ?? link.href ??
|
|
68
|
+
to: link.to ?? link.href ?? '/',
|
|
72
69
|
...sharedProps
|
|
73
70
|
};
|
|
74
71
|
};
|
|
@@ -135,14 +132,14 @@ const getLinkProps = (link: LandingFooterLink) => {
|
|
|
135
132
|
<div v-if="props.showBottomBar" :class="cn('mt-12 flex flex-col items-center justify-between gap-4 border-t border-border pt-8 text-xs md:text-sm text-muted-foreground md:flex-row', props.bottomBarClass)">
|
|
136
133
|
<!-- Copyright -->
|
|
137
134
|
<div>
|
|
138
|
-
© {{ props.year }} {{ props.appName }}. {{ t(
|
|
135
|
+
© {{ props.year }} {{ props.appName }}. {{ t('uiVintage.footer.allRightsReserved') }}
|
|
139
136
|
</div>
|
|
140
137
|
|
|
141
138
|
<!-- Author -->
|
|
142
139
|
<div v-if="props.authorName && props.authorLink" class="flex flex-wrap items-center justify-center gap-1.5 md:justify-end">
|
|
143
|
-
<span>{{ t(
|
|
140
|
+
<span>{{ t('uiVintage.footer.madeWith') }}</span>
|
|
144
141
|
<HugeiconsIcon :icon="FavouriteIcon" class="size-4 shrink-0 text-red-700 dark:text-red-400" />
|
|
145
|
-
<span>{{ t(
|
|
142
|
+
<span>{{ t('uiVintage.footer.by') }}</span>
|
|
146
143
|
<a :href="props.authorLink" target="_blank" rel="noopener noreferrer" class="font-semibold text-foreground hover:underline">
|
|
147
144
|
{{ props.authorName }}
|
|
148
145
|
</a>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as LandingFooter } from
|
|
3
|
-
export type { LandingFooterLink, LandingFooterSection } from
|
|
1
|
+
export { default } from './LandingFooter.vue';
|
|
2
|
+
export { default as LandingFooter } from './LandingFooter.vue';
|
|
3
|
+
export type { LandingFooterLink, LandingFooterSection } from './LandingFooter.vue';
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { NuxtImg } from
|
|
3
|
-
import type { HTMLAttributes } from
|
|
4
|
-
import { cn } from
|
|
2
|
+
import { NuxtImg } from '#components';
|
|
3
|
+
import type { HTMLAttributes } from 'vue';
|
|
4
|
+
import { cn } from '../../../lib/utils';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// Props
|
|
7
|
+
const props = withDefaults(defineProps<{
|
|
7
8
|
appName?: string;
|
|
8
9
|
appLogo?: string;
|
|
9
10
|
appLinkTo?: string;
|
|
10
|
-
logoClass?: HTMLAttributes[
|
|
11
|
-
class?: HTMLAttributes[
|
|
12
|
-
containerClass?: HTMLAttributes[
|
|
13
|
-
leftClass?: HTMLAttributes[
|
|
14
|
-
rightClass?: HTMLAttributes[
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
appName: "",
|
|
20
|
-
appLogo: "",
|
|
21
|
-
appLinkTo: "/"
|
|
11
|
+
logoClass?: HTMLAttributes['class'];
|
|
12
|
+
class?: HTMLAttributes['class'];
|
|
13
|
+
containerClass?: HTMLAttributes['class'];
|
|
14
|
+
leftClass?: HTMLAttributes['class'];
|
|
15
|
+
rightClass?: HTMLAttributes['class'];
|
|
16
|
+
}>(), {
|
|
17
|
+
appName: '',
|
|
18
|
+
appLogo: '',
|
|
19
|
+
appLinkTo: '/'
|
|
22
20
|
});
|
|
23
21
|
</script>
|
|
24
22
|
|
|
@@ -33,7 +31,7 @@ const props = withDefaults(defineProps<LandingNavbarProps>(), {
|
|
|
33
31
|
<NuxtImg v-if="props.appLogo" :src="props.appLogo" :alt="`${props.appName} logo`" width="44" height="44" :sizes="{ 320: '44px', 640: '36px' }" loading="eager" fetchpriority="high" :class="cn('size-11 sm:size-9 shrink-0 object-contain', props.logoClass)" />
|
|
34
32
|
|
|
35
33
|
<!-- App name -->
|
|
36
|
-
<span v-if="props.appName" class="hidden sm
|
|
34
|
+
<span v-if="props.appName" class="hidden sm:inline! text-xl font-bold tracking-tight text-foreground">
|
|
37
35
|
{{ props.appName }}
|
|
38
36
|
</span>
|
|
39
37
|
</a>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as LandingNavbar } from
|
|
1
|
+
export { default } from './LandingNavbar.vue';
|
|
2
|
+
export { default as LandingNavbar } from './LandingNavbar.vue';
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { cn } from "../../../lib/utils";
|
|
6
|
-
|
|
7
|
-
interface LandingShellProps {
|
|
8
|
-
showBackground?: boolean;
|
|
9
|
-
rootClass?: HTMLAttributes["class"];
|
|
10
|
-
navbarClass?: HTMLAttributes["class"];
|
|
11
|
-
mainClass?: HTMLAttributes["class"];
|
|
12
|
-
footerClass?: HTMLAttributes["class"];
|
|
13
|
-
}
|
|
2
|
+
import { computed, useSlots, type HTMLAttributes } from 'vue';
|
|
3
|
+
import BackgroundGrid from '../../background-grid/BackgroundGrid.vue';
|
|
4
|
+
import { cn } from '../../../lib/utils';
|
|
14
5
|
|
|
15
6
|
// Props
|
|
16
|
-
const props = withDefaults(defineProps<
|
|
7
|
+
const props = withDefaults(defineProps<{
|
|
8
|
+
showBackground?: boolean;
|
|
9
|
+
rootClass?: HTMLAttributes['class'];
|
|
10
|
+
navbarClass?: HTMLAttributes['class'];
|
|
11
|
+
mainClass?: HTMLAttributes['class'];
|
|
12
|
+
footerClass?: HTMLAttributes['class'];
|
|
13
|
+
}>(), {
|
|
17
14
|
showBackground: true
|
|
18
15
|
});
|
|
19
16
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as LandingShell } from
|
|
1
|
+
export { default } from './LandingShell.vue';
|
|
2
|
+
export { default as LandingShell } from './LandingShell.vue';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type
|
|
3
|
-
import { computed, defineAsyncComponent } from 'vue';
|
|
2
|
+
import { computed, defineAsyncComponent, type Component } from 'vue';
|
|
4
3
|
|
|
5
4
|
// Single source of truth for supported flag component loaders
|
|
6
5
|
const supportedFlagLoaders = {
|
|
@@ -15,7 +14,7 @@ const supportedFlagLoaders = {
|
|
|
15
14
|
ru: () => import('./flags/RussianFlag.vue')
|
|
16
15
|
} as const;
|
|
17
16
|
|
|
18
|
-
type SupportedLanguageCode = keyof typeof supportedFlagLoaders;
|
|
17
|
+
export type SupportedLanguageCode = keyof typeof supportedFlagLoaders;
|
|
19
18
|
const asyncFlagComponentCache = new Map<SupportedLanguageCode, Component>();
|
|
20
19
|
|
|
21
20
|
// Type guard to ensure a code is one of the supported flag codes
|
|
@@ -38,8 +37,10 @@ const getAsyncFlagComponent = (code: SupportedLanguageCode) => {
|
|
|
38
37
|
};
|
|
39
38
|
|
|
40
39
|
// Props
|
|
41
|
-
const props = defineProps
|
|
42
|
-
code
|
|
40
|
+
const props = withDefaults(defineProps<{
|
|
41
|
+
code?: SupportedLanguageCode;
|
|
42
|
+
}>(), {
|
|
43
|
+
code: 'en'
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
// Get the appropriate flag component based on the code prop
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default } from './LanguageFlag.vue';
|
|
2
2
|
export { default as LanguageFlag } from './LanguageFlag.vue';
|
|
3
|
+
export type { SupportedLanguageCode } from './LanguageFlag.vue';
|
|
3
4
|
export { default as EnglishFlag } from './flags/EnglishFlag.vue';
|
|
4
5
|
export { default as FrenchFlag } from './flags/FrenchFlag.vue';
|
|
5
6
|
export { default as GermanFlag } from './flags/GermanFlag.vue';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import { computed, defineAsyncComponent, ref } from 'vue';
|
|
2
|
+
import { computed, defineAsyncComponent, ref, type Component } from 'vue';
|
|
4
3
|
import { useI18n } from 'vue-i18n';
|
|
5
4
|
import { Tick02Icon } from '@hugeicons/core-free-icons';
|
|
6
5
|
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
@@ -10,6 +9,24 @@ import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
|
|
10
9
|
|
|
11
10
|
export type LanguageSelectorCode = string;
|
|
12
11
|
|
|
12
|
+
// Props
|
|
13
|
+
const props = withDefaults(defineProps<{
|
|
14
|
+
modelValue?: string;
|
|
15
|
+
languages?: LanguageSelectorCode[];
|
|
16
|
+
}>(), {
|
|
17
|
+
modelValue: '',
|
|
18
|
+
languages: () => ['en', 'it']
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Emits
|
|
22
|
+
const emits = defineEmits<{
|
|
23
|
+
'update:modelValue': [value: string];
|
|
24
|
+
select: [value: string];
|
|
25
|
+
}>();
|
|
26
|
+
|
|
27
|
+
const { locale, t } = useI18n();
|
|
28
|
+
const isOpen = ref(false);
|
|
29
|
+
|
|
13
30
|
// Single source of truth for supported language codes, labels, and flag loaders
|
|
14
31
|
const supportedLanguages = [
|
|
15
32
|
{ code: 'en', label: 'English', loadFlag: () => import('../language-flag/flags/EnglishFlag.vue') },
|
|
@@ -51,24 +68,6 @@ const getAsyncFlagComponent = (code: SupportedLanguageCode) => {
|
|
|
51
68
|
return asyncComponent;
|
|
52
69
|
};
|
|
53
70
|
|
|
54
|
-
// Props
|
|
55
|
-
const props = defineProps({
|
|
56
|
-
modelValue: { type: String, default: '' },
|
|
57
|
-
languages: {
|
|
58
|
-
type: Array as PropType<LanguageSelectorCode[]>,
|
|
59
|
-
default: () => ['en', 'it']
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Emits
|
|
64
|
-
const emits = defineEmits<{
|
|
65
|
-
'update:modelValue': [value: string];
|
|
66
|
-
select: [value: string];
|
|
67
|
-
}>();
|
|
68
|
-
|
|
69
|
-
const { locale, t } = useI18n();
|
|
70
|
-
const isOpen = ref(false);
|
|
71
|
-
|
|
72
71
|
// Build localized language labels from the provided language codes
|
|
73
72
|
const languageDisplayNames = computed(() => {
|
|
74
73
|
return typeof Intl.DisplayNames === 'function' ? new Intl.DisplayNames([locale.value], { type: 'language' }) : null;
|
|
@@ -137,7 +136,7 @@ const handleSelectLanguage = (language: string) => {
|
|
|
137
136
|
</PopoverTrigger>
|
|
138
137
|
|
|
139
138
|
<!-- Popover content with language options -->
|
|
140
|
-
<PopoverContent side="bottom" align="end" :side-offset="8" class="w-44
|
|
139
|
+
<PopoverContent side="bottom" align="end" :side-offset="8" class="w-44 p-0!">
|
|
141
140
|
<Command :model-value="props.modelValue">
|
|
142
141
|
<CommandList>
|
|
143
142
|
<CommandGroup :heading="t('uiVintage.language.title')">
|
|
@@ -5,19 +5,27 @@ import { ArrowDown01Icon, RefreshIcon } from '@hugeicons/core-free-icons';
|
|
|
5
5
|
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
6
6
|
import { Button } from '../ui/button';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
// Props
|
|
9
|
+
const props = withDefaults(defineProps<{
|
|
10
|
+
busy?: boolean;
|
|
11
|
+
text?: string;
|
|
12
|
+
loadingText?: string;
|
|
13
|
+
}>(), {
|
|
14
|
+
busy: false,
|
|
15
|
+
text: '',
|
|
16
|
+
loadingText: ''
|
|
12
17
|
});
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
// Emits
|
|
20
|
+
const emits = defineEmits<{
|
|
21
|
+
'load-more': [];
|
|
22
|
+
}>();
|
|
15
23
|
|
|
16
24
|
const { t } = useI18n();
|
|
17
|
-
|
|
18
25
|
const resolvedText = computed(() => props.text || t('uiVintage.buttons.loadMore') || 'Load more');
|
|
19
26
|
const resolvedLoadingText = computed(() => props.loadingText || t('uiVintage.buttons.loading') || 'Loading');
|
|
20
27
|
|
|
28
|
+
// Handle click event
|
|
21
29
|
const handleClick = () => {
|
|
22
30
|
emits('load-more');
|
|
23
31
|
};
|
|
@@ -25,18 +33,14 @@ const handleClick = () => {
|
|
|
25
33
|
|
|
26
34
|
<template>
|
|
27
35
|
<div class="flex justify-center">
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class="w-full md:w-auto"
|
|
31
|
-
:disabled="true">
|
|
36
|
+
<!-- Loading button -->
|
|
37
|
+
<Button v-if="props.busy" variant="secondary" class="w-full md:w-auto" :disabled="true">
|
|
32
38
|
<HugeiconsIcon :icon="RefreshIcon" class="size-4 animate-spin" />
|
|
33
39
|
{{ resolvedLoadingText }}
|
|
34
40
|
</Button>
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class="w-full md:w-auto"
|
|
39
|
-
@click="handleClick">
|
|
42
|
+
<!-- Load more button -->
|
|
43
|
+
<Button v-else variant="secondary" class="w-full md:w-auto" @click="handleClick">
|
|
40
44
|
<HugeiconsIcon :icon="ArrowDown01Icon" class="size-4" />
|
|
41
45
|
{{ resolvedText }}
|
|
42
46
|
</Button>
|