@brumaombra/ui-vintage 0.7.8 → 0.7.10
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/BlogContentRenderer.vue +133 -0
- 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/BlogProgressBar.vue +77 -0
- 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 +43 -41
- package/src/components/blog/TableOfContents.vue +29 -13
- package/src/components/blog/index.ts +1 -0
- 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 +51 -19
- package/src/components/landing/landing-navbar/index.ts +2 -2
- package/src/components/landing/landing-shell/LandingShell.vue +12 -15
- 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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as AllPostsSection } from './AllPostsSection.vue';
|
|
2
|
+
export { default as BlogContentRenderer } from './BlogContentRenderer.vue';
|
|
2
3
|
export { default as BlogFAQSection } from './BlogFAQSection.vue';
|
|
3
4
|
export { default as BlogInfoSection } from './BlogInfoSection.vue';
|
|
4
5
|
export { default as BlogHeaderSection } from './BlogHeaderSection.vue';
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import { h, reactive, render } from
|
|
2
|
-
import type { HTMLAttributes } from "vue";
|
|
1
|
+
import { h, reactive, render, type HTMLAttributes } from 'vue';
|
|
3
2
|
|
|
4
3
|
export interface SetBusyOptions {
|
|
5
4
|
label?: string;
|
|
6
|
-
class?: HTMLAttributes[
|
|
7
|
-
overlayClass?: HTMLAttributes[
|
|
5
|
+
class?: HTMLAttributes['class'];
|
|
6
|
+
overlayClass?: HTMLAttributes['class'];
|
|
8
7
|
}
|
|
9
8
|
|
|
10
9
|
interface BusyIndicatorState {
|
|
11
10
|
show: boolean;
|
|
12
11
|
label: string;
|
|
13
|
-
class: HTMLAttributes[
|
|
14
|
-
overlayClass: HTMLAttributes[
|
|
12
|
+
class: HTMLAttributes['class'];
|
|
13
|
+
overlayClass: HTMLAttributes['class'];
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
const BUSY_INDICATOR_ROOT_ID =
|
|
16
|
+
const BUSY_INDICATOR_ROOT_ID = 'ui-vintage-busy-indicator-root';
|
|
18
17
|
|
|
19
18
|
let busyIndicatorMountPromise: Promise<void> | null = null;
|
|
20
19
|
|
|
21
20
|
// Shared busy state
|
|
22
21
|
export const busyIndicatorState: BusyIndicatorState = reactive({
|
|
23
22
|
show: false,
|
|
24
|
-
label:
|
|
23
|
+
label: 'Loading...',
|
|
25
24
|
class: undefined,
|
|
26
25
|
overlayClass: undefined
|
|
27
26
|
});
|
|
@@ -29,7 +28,7 @@ export const busyIndicatorState: BusyIndicatorState = reactive({
|
|
|
29
28
|
// Mount the busy indicator once on demand
|
|
30
29
|
const ensureBusyIndicatorMounted = () => {
|
|
31
30
|
// Skip mounting during SSR
|
|
32
|
-
if (typeof document ===
|
|
31
|
+
if (typeof document === 'undefined') {
|
|
33
32
|
return Promise.resolve();
|
|
34
33
|
}
|
|
35
34
|
|
|
@@ -47,7 +46,7 @@ const ensureBusyIndicatorMounted = () => {
|
|
|
47
46
|
// Start the lazy mount
|
|
48
47
|
busyIndicatorMountPromise = (async () => {
|
|
49
48
|
// Load the component only when needed
|
|
50
|
-
const { default: BusyIndicator } = await import(
|
|
49
|
+
const { default: BusyIndicator } = await import('./BusyIndicator.vue');
|
|
51
50
|
|
|
52
51
|
// Guard against a concurrent mount
|
|
53
52
|
if (document.getElementById(BUSY_INDICATOR_ROOT_ID)) {
|
|
@@ -55,7 +54,7 @@ const ensureBusyIndicatorMounted = () => {
|
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
// Create the host element and render the component
|
|
58
|
-
const container = document.createElement(
|
|
57
|
+
const container = document.createElement('div');
|
|
59
58
|
container.id = BUSY_INDICATOR_ROOT_ID;
|
|
60
59
|
document.body.appendChild(container);
|
|
61
60
|
render(h(BusyIndicator), container);
|
|
@@ -71,7 +70,7 @@ const ensureBusyIndicatorMounted = () => {
|
|
|
71
70
|
export const setBusy = (show: boolean, options: SetBusyOptions = {}) => {
|
|
72
71
|
// Prepare the overlay before showing it
|
|
73
72
|
if (show) {
|
|
74
|
-
busyIndicatorState.label = options.label ?? busyIndicatorState.label ??
|
|
73
|
+
busyIndicatorState.label = options.label ?? busyIndicatorState.label ?? 'Loading...';
|
|
75
74
|
busyIndicatorState.class = options.class;
|
|
76
75
|
busyIndicatorState.overlayClass = options.overlayClass;
|
|
77
76
|
void ensureBusyIndicatorMounted();
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as BusyIndicator } from
|
|
2
|
-
export { busyIndicatorState, setBusy } from
|
|
3
|
-
export type { SetBusyOptions } from
|
|
1
|
+
export { default as BusyIndicator } from './BusyIndicator.vue';
|
|
2
|
+
export { busyIndicatorState, setBusy } from './busy-indicator-state';
|
|
3
|
+
export type { SetBusyOptions } from './busy-indicator-state';
|
|
@@ -1,21 +1,35 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
1
|
+
<script setup lang="ts" generic="T extends { id: PropertyKey }">
|
|
2
2
|
import { PackageIcon } from '@hugeicons/core-free-icons';
|
|
3
3
|
import { EmptyStateCard } from '../empty-state-card';
|
|
4
4
|
import { LoadMoreButton } from '../load-more-button';
|
|
5
5
|
import { LoadingStateCard } from '../loading-state-card';
|
|
6
|
+
import type { HugeiconsIconDefinition } from '../../lib/common-types';
|
|
6
7
|
|
|
7
8
|
// Props
|
|
8
|
-
const props = defineProps
|
|
9
|
-
items
|
|
10
|
-
busy
|
|
11
|
-
loadMoreBusy
|
|
12
|
-
hasMore
|
|
13
|
-
emptyMessage:
|
|
14
|
-
emptyIcon
|
|
9
|
+
const props = withDefaults(defineProps<{
|
|
10
|
+
items?: T[];
|
|
11
|
+
busy?: boolean;
|
|
12
|
+
loadMoreBusy?: boolean;
|
|
13
|
+
hasMore?: boolean;
|
|
14
|
+
emptyMessage: string;
|
|
15
|
+
emptyIcon?: HugeiconsIconDefinition;
|
|
16
|
+
}>(), {
|
|
17
|
+
items: () => [],
|
|
18
|
+
busy: false,
|
|
19
|
+
loadMoreBusy: false,
|
|
20
|
+
hasMore: false,
|
|
21
|
+
emptyIcon: () => PackageIcon
|
|
15
22
|
});
|
|
16
23
|
|
|
17
24
|
// Emits
|
|
18
|
-
const emits = defineEmits
|
|
25
|
+
const emits = defineEmits<{
|
|
26
|
+
'load-more': [];
|
|
27
|
+
}>();
|
|
28
|
+
|
|
29
|
+
// Slots
|
|
30
|
+
defineSlots<{
|
|
31
|
+
card(props: { item: T; key?: PropertyKey }): unknown;
|
|
32
|
+
}>();
|
|
19
33
|
|
|
20
34
|
// Handle load more
|
|
21
35
|
const handleLoadMore = () => {
|
|
@@ -29,13 +43,13 @@ const handleLoadMore = () => {
|
|
|
29
43
|
<LoadingStateCard v-if="props.busy" />
|
|
30
44
|
|
|
31
45
|
<!-- Empty state -->
|
|
32
|
-
<EmptyStateCard v-else-if="
|
|
46
|
+
<EmptyStateCard v-else-if="props.items.length === 0"
|
|
33
47
|
:description="props.emptyMessage"
|
|
34
48
|
:icon="props.emptyIcon" />
|
|
35
49
|
|
|
36
50
|
<!-- Cards grid -->
|
|
37
51
|
<div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6 xl:gap-4">
|
|
38
|
-
<slot name="card" v-for="item in props.items" :item="item" :key="
|
|
52
|
+
<slot name="card" v-for="item in props.items" :item="item" :key="item.id" />
|
|
39
53
|
</div>
|
|
40
54
|
|
|
41
55
|
<!-- Load more button -->
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { Cancel01Icon } from
|
|
3
|
-
import { HugeiconsIcon } from
|
|
4
|
-
import type { HTMLAttributes } from
|
|
5
|
-
import { getSurfaceToneClasses, type ToneColor } from
|
|
6
|
-
import { cn } from
|
|
2
|
+
import { Cancel01Icon } from '@hugeicons/core-free-icons';
|
|
3
|
+
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
4
|
+
import type { HTMLAttributes } from 'vue';
|
|
5
|
+
import { getSurfaceToneClasses, type ToneColor } from '../../lib/color-tokens';
|
|
6
|
+
import { cn } from '../../lib/utils';
|
|
7
7
|
|
|
8
8
|
// Props
|
|
9
9
|
const props = withDefaults(defineProps<{
|
|
10
|
-
text: string
|
|
11
|
-
color?: ToneColor
|
|
12
|
-
removeLabel?: string
|
|
13
|
-
class?: HTMLAttributes[
|
|
10
|
+
text: string;
|
|
11
|
+
color?: ToneColor;
|
|
12
|
+
removeLabel?: string;
|
|
13
|
+
class?: HTMLAttributes['class'];
|
|
14
14
|
}>(), {
|
|
15
|
-
color:
|
|
16
|
-
removeLabel:
|
|
17
|
-
})
|
|
15
|
+
color: 'gray',
|
|
16
|
+
removeLabel: 'Remove'
|
|
17
|
+
});
|
|
18
18
|
|
|
19
19
|
// Emits
|
|
20
20
|
const emits = defineEmits<{
|
|
21
21
|
remove: []
|
|
22
|
-
}>()
|
|
22
|
+
}>();
|
|
23
23
|
|
|
24
24
|
// Handle remove button click
|
|
25
25
|
const handleRemove = () => {
|
|
26
|
-
emits(
|
|
27
|
-
}
|
|
26
|
+
emits('remove');
|
|
27
|
+
};
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
30
|
<template>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default } from
|
|
2
|
-
export { default as Chip } from
|
|
1
|
+
export { default } from './Chip.vue';
|
|
2
|
+
export { default as Chip } from './Chip.vue';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { HugeiconsIcon } from
|
|
3
|
-
import { computed } from
|
|
4
|
-
import { InformationCircleIcon } from
|
|
5
|
-
import { AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from
|
|
6
|
-
import { Button } from
|
|
7
|
-
import { cancelActiveConfirmDialog, closeConfirmDialog, confirmActiveDialog, confirmDialogState } from
|
|
2
|
+
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
3
|
+
import { computed } from 'vue';
|
|
4
|
+
import { InformationCircleIcon } from '@hugeicons/core-free-icons';
|
|
5
|
+
import { AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '../ui/alert-dialog';
|
|
6
|
+
import { Button } from '../ui/button';
|
|
7
|
+
import { cancelActiveConfirmDialog, closeConfirmDialog, confirmActiveDialog, confirmDialogState } from './confirm-dialog-state';
|
|
8
8
|
|
|
9
9
|
const currentDialog = computed(() => confirmDialogState.current);
|
|
10
10
|
|
|
@@ -24,9 +24,9 @@ const handleOpenChange = (open: boolean) => {
|
|
|
24
24
|
<div class="px-5 pb-5 pt-5 sm:px-6 sm:pb-4 sm:pt-6">
|
|
25
25
|
<div class="flex flex-col gap-4 sm:flex-row sm:items-start">
|
|
26
26
|
<!-- Dialog icon -->
|
|
27
|
-
<div class="flex size-12 shrink-0 self-center items-center justify-center rounded border border-
|
|
28
|
-
<HugeiconsIcon v-if="currentDialog.options.icon" :icon="currentDialog.options.icon" :stroke-width="1.8" class="size-6 text-
|
|
29
|
-
<HugeiconsIcon v-else :icon="InformationCircleIcon" :stroke-width="1.8" class="size-6 text-
|
|
27
|
+
<div class="flex size-12 shrink-0 self-center items-center justify-center rounded border border-(--border-light) bg-(--bg-surface-light) sm:size-10 sm:self-start dark:border-(--border-dark) dark:bg-(--bg-surface-dark)">
|
|
28
|
+
<HugeiconsIcon v-if="currentDialog.options.icon" :icon="currentDialog.options.icon" :stroke-width="1.8" class="size-6 text-(--button-primary-light) dark:text-(--button-primary-dark)" />
|
|
29
|
+
<HugeiconsIcon v-else :icon="InformationCircleIcon" :stroke-width="1.8" class="size-6 text-(--button-primary-light) dark:text-(--button-primary-dark)" />
|
|
30
30
|
</div>
|
|
31
31
|
|
|
32
32
|
<!-- Dialog header -->
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { h, markRaw, reactive, render } from
|
|
2
|
-
import type { ButtonVariants } from
|
|
1
|
+
import { h, markRaw, reactive, render } from 'vue';
|
|
2
|
+
import type { ButtonVariants } from '../ui/button';
|
|
3
|
+
import type { HugeiconsIconDefinition } from '../../lib/common-types';
|
|
3
4
|
|
|
4
|
-
export type DialogButtonVariant = NonNullable<ButtonVariants[
|
|
5
|
-
export type
|
|
5
|
+
export type DialogButtonVariant = NonNullable<ButtonVariants['variant']>;
|
|
6
|
+
export type { HugeiconsIconDefinition };
|
|
6
7
|
|
|
7
8
|
export interface ShowConfirmDialogOptions {
|
|
8
9
|
title?: string;
|
|
@@ -20,7 +21,7 @@ export interface ShowConfirmDialogOptions {
|
|
|
20
21
|
|
|
21
22
|
interface ConfirmDialogRequest {
|
|
22
23
|
id: number;
|
|
23
|
-
options: Required<Omit<ShowConfirmDialogOptions,
|
|
24
|
+
options: Required<Omit<ShowConfirmDialogOptions, 'icon' | 'confirmButtonIcon' | 'cancelButtonIcon' | 'onConfirm' | 'onCancel'>> & {
|
|
24
25
|
icon: HugeiconsIconDefinition | null;
|
|
25
26
|
confirmButtonIcon: HugeiconsIconDefinition | null;
|
|
26
27
|
cancelButtonIcon: HugeiconsIconDefinition | null;
|
|
@@ -42,7 +43,7 @@ const DIALOG_CLOSE_DURATION_MS = 300;
|
|
|
42
43
|
let closeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
43
44
|
let confirmDialogMountPromise: Promise<void> | null = null;
|
|
44
45
|
|
|
45
|
-
const CONFIRM_DIALOG_ROOT_ID =
|
|
46
|
+
const CONFIRM_DIALOG_ROOT_ID = 'ui-vintage-confirm-dialog-root';
|
|
46
47
|
|
|
47
48
|
// Shared confirm dialog state
|
|
48
49
|
export const confirmDialogState: ConfirmDialogState = reactive({
|
|
@@ -57,7 +58,7 @@ const markIcon = (icon: HugeiconsIconDefinition | null | undefined) => icon ? ma
|
|
|
57
58
|
// Mount the dialog once on demand
|
|
58
59
|
const ensureConfirmDialogMounted = () => {
|
|
59
60
|
// Skip mounting during SSR
|
|
60
|
-
if (typeof document ===
|
|
61
|
+
if (typeof document === 'undefined') {
|
|
61
62
|
return Promise.resolve();
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -75,7 +76,7 @@ const ensureConfirmDialogMounted = () => {
|
|
|
75
76
|
// Start the lazy mount
|
|
76
77
|
confirmDialogMountPromise = (async () => {
|
|
77
78
|
// Load the component only when needed
|
|
78
|
-
const { default: ConfirmDialog } = await import(
|
|
79
|
+
const { default: ConfirmDialog } = await import('./ConfirmDialog.vue');
|
|
79
80
|
|
|
80
81
|
// Guard against a concurrent mount
|
|
81
82
|
if (document.getElementById(CONFIRM_DIALOG_ROOT_ID)) {
|
|
@@ -83,7 +84,7 @@ const ensureConfirmDialogMounted = () => {
|
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
// Create the host element and render the component
|
|
86
|
-
const container = document.createElement(
|
|
87
|
+
const container = document.createElement('div');
|
|
87
88
|
container.id = CONFIRM_DIALOG_ROOT_ID;
|
|
88
89
|
document.body.appendChild(container);
|
|
89
90
|
render(h(ConfirmDialog), container);
|
|
@@ -182,12 +183,12 @@ export const showConfirmDialog = (options: ShowConfirmDialogOptions) => {
|
|
|
182
183
|
enqueueConfirmDialog({
|
|
183
184
|
id: nextConfirmDialogId += 1,
|
|
184
185
|
options: {
|
|
185
|
-
title: options.title ??
|
|
186
|
+
title: options.title ?? 'Confirm',
|
|
186
187
|
message: options.message,
|
|
187
|
-
confirmText: options.confirmText ??
|
|
188
|
-
cancelText: options.cancelText ??
|
|
189
|
-
confirmButtonType: options.confirmButtonType ??
|
|
190
|
-
cancelButtonType: options.cancelButtonType ??
|
|
188
|
+
confirmText: options.confirmText ?? 'Confirm',
|
|
189
|
+
cancelText: options.cancelText ?? 'Cancel',
|
|
190
|
+
confirmButtonType: options.confirmButtonType ?? 'primary',
|
|
191
|
+
cancelButtonType: options.cancelButtonType ?? 'secondary',
|
|
191
192
|
icon: markIcon(options.icon),
|
|
192
193
|
confirmButtonIcon: markIcon(options.confirmButtonIcon),
|
|
193
194
|
cancelButtonIcon: markIcon(options.cancelButtonIcon),
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
export { default as ConfirmDialog } from
|
|
2
|
-
export {
|
|
3
|
-
|
|
4
|
-
closeConfirmDialog,
|
|
5
|
-
confirmActiveDialog,
|
|
6
|
-
confirmDialogState,
|
|
7
|
-
showConfirmDialog
|
|
8
|
-
} from "./confirm-dialog-state";
|
|
9
|
-
export type {
|
|
10
|
-
DialogButtonVariant,
|
|
11
|
-
ShowConfirmDialogOptions
|
|
12
|
-
} from "./confirm-dialog-state";
|
|
1
|
+
export { default as ConfirmDialog } from './ConfirmDialog.vue';
|
|
2
|
+
export { cancelActiveConfirmDialog, closeConfirmDialog, confirmActiveDialog, confirmDialogState, showConfirmDialog } from './confirm-dialog-state';
|
|
3
|
+
export type { DialogButtonVariant, ShowConfirmDialogOptions } from './confirm-dialog-state';
|
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { Cancel01Icon, CheckmarkCircle02Icon, CircleSmallIcon } from '@hugeicons/core-free-icons';
|
|
3
3
|
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
4
4
|
import { Card, CardContent } from '../ui/card';
|
|
5
5
|
|
|
6
6
|
// Props
|
|
7
|
-
const props = defineProps
|
|
8
|
-
items
|
|
9
|
-
variant
|
|
7
|
+
const props = withDefaults(defineProps<{
|
|
8
|
+
items?: string[];
|
|
9
|
+
variant?: 'circle' | 'checkmark' | 'numbered' | 'cross';
|
|
10
|
+
}>(), {
|
|
11
|
+
items: () => [],
|
|
12
|
+
variant: 'checkmark'
|
|
10
13
|
});
|
|
11
14
|
|
|
12
15
|
// Icon container classes
|
|
13
16
|
const getIconContainerClasses = () => {
|
|
14
|
-
return 'flex items-center justify-center w-8 h-8 bg-
|
|
17
|
+
return 'flex items-center justify-center w-8 h-8 bg-(--bg-card-light) dark:bg-(--bg-card-dark) border border-(--border-light) dark:border-(--border-dark) rounded mr-4 shrink-0';
|
|
15
18
|
};
|
|
16
19
|
|
|
17
20
|
// Icon color classes
|
|
18
21
|
const getIconClasses = () => {
|
|
19
|
-
return 'text-
|
|
22
|
+
return 'text-(--text-secondary-light) dark:text-(--text-secondary-dark) text-xs';
|
|
20
23
|
};
|
|
21
24
|
</script>
|
|
22
25
|
|
|
@@ -24,7 +27,7 @@ const getIconClasses = () => {
|
|
|
24
27
|
<div class="not-prose my-6 sm:my-12">
|
|
25
28
|
<Card>
|
|
26
29
|
<CardContent class="gap-0">
|
|
27
|
-
<ul class="text-xs md:text-sm
|
|
30
|
+
<ul class="text-xs md:text-sm p-0! space-y-6!">
|
|
28
31
|
<li v-for="(item, index) in props.items" :key="index" class="flex items-center">
|
|
29
32
|
<!-- Circle -->
|
|
30
33
|
<div v-if="props.variant === 'circle'" :class="getIconContainerClasses()">
|
|
@@ -48,7 +51,7 @@ const getIconClasses = () => {
|
|
|
48
51
|
|
|
49
52
|
<!-- Content -->
|
|
50
53
|
<div class="flex-1">
|
|
51
|
-
<div class="text-
|
|
54
|
+
<div class="text-(--text-primary-light) dark:text-(--text-primary-dark) leading-relaxed">
|
|
52
55
|
{{ item }}
|
|
53
56
|
</div>
|
|
54
57
|
</div>
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { Card, CardContent } from '../ui/card';
|
|
3
3
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../ui/table';
|
|
4
4
|
|
|
5
5
|
// Props
|
|
6
|
-
const props = defineProps
|
|
7
|
-
headers
|
|
8
|
-
rows
|
|
9
|
-
highlightCol
|
|
6
|
+
const props = withDefaults(defineProps<{
|
|
7
|
+
headers?: string[];
|
|
8
|
+
rows?: string[][];
|
|
9
|
+
highlightCol?: number;
|
|
10
|
+
}>(), {
|
|
11
|
+
headers: () => [],
|
|
12
|
+
rows: () => [],
|
|
13
|
+
highlightCol: -1
|
|
10
14
|
});
|
|
11
15
|
|
|
12
16
|
// Header cell classes
|
|
13
|
-
const getHeaderClasses = colIndex => {
|
|
14
|
-
const baseClasses = 'text-left font-semibold text-
|
|
15
|
-
const highlightClass = props.highlightCol === colIndex ? 'bg-
|
|
17
|
+
const getHeaderClasses = (colIndex: number) => {
|
|
18
|
+
const baseClasses = 'text-left font-semibold text-(--text-primary-light) dark:text-(--text-primary-dark)';
|
|
19
|
+
const highlightClass = props.highlightCol === colIndex ? 'bg-(--bg-selected-light) dark:bg-(--bg-selected-dark)' : '';
|
|
16
20
|
return [baseClasses, highlightClass];
|
|
17
21
|
};
|
|
18
22
|
|
|
19
23
|
// Body cell classes
|
|
20
|
-
const getCellClasses = colIndex => {
|
|
21
|
-
const baseClasses = 'align-top text-
|
|
22
|
-
const firstColClass = colIndex === 0 ? 'font-semibold text-
|
|
23
|
-
const highlightClass = props.highlightCol === colIndex ? 'bg-
|
|
24
|
+
const getCellClasses = (colIndex: number) => {
|
|
25
|
+
const baseClasses = 'align-top text-(--text-primary-light) dark:text-(--text-primary-dark) leading-relaxed whitespace-normal';
|
|
26
|
+
const firstColClass = colIndex === 0 ? 'font-semibold text-(--text-secondary-light) dark:text-(--text-secondary-dark)' : '';
|
|
27
|
+
const highlightClass = props.highlightCol === colIndex ? 'bg-(--bg-selected-light) dark:bg-(--bg-selected-dark)' : '';
|
|
24
28
|
return [baseClasses, firstColClass, highlightClass];
|
|
25
29
|
};
|
|
26
30
|
</script>
|
|
@@ -33,7 +37,7 @@ const getCellClasses = colIndex => {
|
|
|
33
37
|
<Table class="w-full text-sm text-left">
|
|
34
38
|
<!-- Table header -->
|
|
35
39
|
<TableHeader>
|
|
36
|
-
<TableRow class="bg-transparent text-sm text-
|
|
40
|
+
<TableRow class="bg-transparent text-sm text-(--text-secondary-light) dark:text-(--text-secondary-dark) hover:bg-transparent">
|
|
37
41
|
<TableHead v-for="(header, colIndex) in props.headers" :key="colIndex" :class="getHeaderClasses(colIndex)">
|
|
38
42
|
{{ header }}
|
|
39
43
|
</TableHead>
|
|
@@ -42,7 +46,7 @@ const getCellClasses = colIndex => {
|
|
|
42
46
|
|
|
43
47
|
<!-- Table body -->
|
|
44
48
|
<TableBody>
|
|
45
|
-
<TableRow v-for="(row, rowIndex) in props.rows" :key="rowIndex" class="text-
|
|
49
|
+
<TableRow v-for="(row, rowIndex) in props.rows" :key="rowIndex" class="text-(--text-secondary-light) dark:text-(--text-secondary-dark) hover:bg-transparent">
|
|
46
50
|
<TableCell v-for="(cell, colIndex) in row" :key="colIndex" :class="getCellClasses(colIndex)">
|
|
47
51
|
{{ cell }}
|
|
48
52
|
</TableCell>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
<script setup>
|
|
1
|
+
<script setup lang="ts">
|
|
2
2
|
import { ChartLineData02Icon } from '@hugeicons/core-free-icons';
|
|
3
3
|
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
4
|
+
import type { HugeiconsIconDefinition } from '../../lib/common-types';
|
|
4
5
|
|
|
5
6
|
// Props
|
|
6
|
-
const props = defineProps
|
|
7
|
-
icon
|
|
7
|
+
const props = withDefaults(defineProps<{
|
|
8
|
+
icon?: HugeiconsIconDefinition;
|
|
9
|
+
}>(), {
|
|
10
|
+
icon: () => ChartLineData02Icon
|
|
8
11
|
});
|
|
9
12
|
</script>
|
|
10
13
|
|
|
@@ -12,15 +15,15 @@ const props = defineProps({
|
|
|
12
15
|
<div aria-hidden="true" class="not-prose my-6 sm:my-12">
|
|
13
16
|
<div class="flex items-center gap-3 sm:gap-4">
|
|
14
17
|
<!-- Left line -->
|
|
15
|
-
<div class="h-px flex-1 bg-
|
|
18
|
+
<div class="h-px flex-1 bg-linear-to-r from-transparent via-(--border-light) to-(--border-light) dark:via-(--border-dark) dark:to-(--border-dark)" />
|
|
16
19
|
|
|
17
20
|
<!-- Icon in the middle -->
|
|
18
|
-
<div class="flex h-9 w-9 items-center justify-center rounded bg-
|
|
19
|
-
<HugeiconsIcon :icon="props.icon" class="size-4 text-
|
|
21
|
+
<div class="flex h-9 w-9 items-center justify-center rounded bg-(--bg-card-light) dark:bg-(--bg-card-dark) border border-(--border-light) dark:border-(--border-dark)">
|
|
22
|
+
<HugeiconsIcon :icon="props.icon" class="size-4 text-(--text-secondary-light) dark:text-(--text-secondary-dark)" />
|
|
20
23
|
</div>
|
|
21
24
|
|
|
22
25
|
<!-- Right line -->
|
|
23
|
-
<div class="h-px flex-1 bg-
|
|
26
|
+
<div class="h-px flex-1 bg-linear-to-l from-transparent via-(--border-light) to-(--border-light) dark:via-(--border-dark) dark:to-(--border-dark)" />
|
|
24
27
|
</div>
|
|
25
28
|
</div>
|
|
26
29
|
</template>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { CheckmarkCircle02Icon, Copy01Icon, TerminalIcon } from '@hugeicons/core-free-icons';
|
|
3
|
+
import { HugeiconsIcon } from '@hugeicons/vue';
|
|
4
|
+
import { computed, ref } from 'vue';
|
|
5
|
+
import { useI18n } from 'vue-i18n';
|
|
6
|
+
import { Button } from '../ui/button';
|
|
7
|
+
import { Card } from '../ui/card';
|
|
8
|
+
|
|
9
|
+
// Props
|
|
10
|
+
const props = withDefaults(defineProps<{
|
|
11
|
+
commands?: string[];
|
|
12
|
+
title?: string;
|
|
13
|
+
prompt?: string;
|
|
14
|
+
copyable?: boolean;
|
|
15
|
+
}>(), {
|
|
16
|
+
commands: () => [],
|
|
17
|
+
title: '',
|
|
18
|
+
prompt: '$',
|
|
19
|
+
copyable: true
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const { t } = useI18n();
|
|
23
|
+
const copied = ref(false);
|
|
24
|
+
const commandText = computed(() => props.commands.join('\n'));
|
|
25
|
+
const resolvedTitle = computed(() => props.title || t('uiVintage.terminal.title'));
|
|
26
|
+
|
|
27
|
+
// Copy all command lines to the clipboard
|
|
28
|
+
const copyCommands = async () => {
|
|
29
|
+
// Check if copy is enabled
|
|
30
|
+
if (!props.copyable || !commandText.value || !navigator.clipboard) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Copy the command text to the clipboard
|
|
35
|
+
await navigator.clipboard.writeText(commandText.value);
|
|
36
|
+
copied.value = true;
|
|
37
|
+
window.setTimeout(() => {
|
|
38
|
+
copied.value = false;
|
|
39
|
+
}, 1800);
|
|
40
|
+
};
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<div class="not-prose my-6 sm:my-12">
|
|
45
|
+
<Card class="gap-0! sm:gap-0! overflow-hidden p-0! text-(--text-primary-light) dark:text-(--text-primary-dark)">
|
|
46
|
+
<!-- Terminal header -->
|
|
47
|
+
<div class="flex items-center justify-between gap-3 border-b border-(--border-light) bg-(--bg-card-light) px-3 py-2 sm:px-4 dark:border-(--border-dark) dark:bg-(--bg-card-dark)">
|
|
48
|
+
<div class="flex min-w-0 items-center gap-2">
|
|
49
|
+
<HugeiconsIcon :icon="TerminalIcon" class="size-4 shrink-0 text-(--text-secondary-light) dark:text-(--text-secondary-dark)" />
|
|
50
|
+
<span class="truncate text-xs font-semibold text-(--text-secondary-light) dark:text-(--text-secondary-dark)">{{ resolvedTitle }}</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<!-- Copy command button -->
|
|
54
|
+
<Button v-if="props.copyable"
|
|
55
|
+
variant="ghost"
|
|
56
|
+
size="icon"
|
|
57
|
+
class="size-7 text-(--text-secondary-light) hover:bg-(--bg-selected-light) hover:text-(--text-primary-light) dark:text-(--text-secondary-dark) dark:hover:bg-(--bg-selected-dark) dark:hover:text-(--text-primary-dark)"
|
|
58
|
+
:aria-label="t('uiVintage.terminal.copy')"
|
|
59
|
+
:title="t('uiVintage.terminal.copy')"
|
|
60
|
+
:disabled="!commandText"
|
|
61
|
+
@click="copyCommands">
|
|
62
|
+
<HugeiconsIcon :icon="copied ? CheckmarkCircle02Icon : Copy01Icon" class="size-4" />
|
|
63
|
+
</Button>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<!-- Terminal commands -->
|
|
67
|
+
<pre class="overflow-x-auto bg-(--bg-surface-light) px-4 py-3 text-xs leading-6 dark:bg-(--bg-surface-dark) sm:px-5 sm:py-4 sm:text-sm"><code><span v-for="(command, index) in props.commands" :key="`${command}-${index}`" class="flex min-w-max"><span class="mr-3 select-none text-(--text-secondary-light) dark:text-(--text-secondary-dark)" aria-hidden="true">{{ props.prompt }}</span><span>{{ command }}</span></span></code></pre>
|
|
68
|
+
</Card>
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { default as BlogList } from './BlogList.vue';
|
|
2
2
|
export { default as BlogTable } from './BlogTable.vue';
|
|
3
|
-
export { default as ProseHr } from './ProseHr.vue';
|
|
3
|
+
export { default as ProseHr } from './ProseHr.vue';
|
|
4
|
+
export { default as Terminal } from './Terminal.vue';
|