perf: replace vue-sonner with the toast component of shadcn-ui

This commit is contained in:
vben 2024-07-07 11:36:32 +08:00
parent fd61d2efc4
commit 0eda99ec3b
23 changed files with 536 additions and 131 deletions

View File

@ -113,6 +113,8 @@
"title": "Preferences",
"subtitle": "Customize Preferences & Preview in Real Time",
"reset-tip": "The data has changed, click to reset",
"reset-title": "Preferences reset",
"reset-success": "Preferences reset successfully",
"appearance": "Appearance",
"layout": "Layout",
"content": "Content",
@ -140,7 +142,6 @@
"copy": "Copy Preferences",
"copy-success": "Copy successful. Please replace in `src/preferences.ts` of the app",
"clear-and-logout": "Clear Cache & Logout",
"reset-success": "Preferences reset successfully",
"mode": "Mode",
"logo-visible": "Display Logo",
"general": "General",

View File

@ -113,7 +113,9 @@
"preferences": {
"title": "偏好设置",
"subtitle": "自定义偏好设置 & 实时预览",
"reset-title": "重置偏好设置",
"reset-tip": "数据有变化,点击可进行重置",
"reset-success": "重置偏好设置成功",
"appearance": "外观",
"layout": "布局",
"content": "内容",
@ -137,9 +139,8 @@
"plain": "朴素",
"rounded": "圆润",
"copy": "复制偏好设置",
"copy-success": "拷贝成功,请在 app 下的 `src/preferences.ts`内进行覆盖",
"copy-success": "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖",
"clear-and-logout": "清空缓存 & 退出登录",
"reset-success": "重置偏好设置成功",
"mode": "模式",
"logo-visible": "显示 Logo",
"general": "通用",

View File

@ -2,8 +2,8 @@ import { h } from 'vue';
import { Icon } from '@iconify/vue';
function createIcon(icon: string) {
function createIconifyIcon(icon: string) {
return h(Icon, { icon });
}
export { createIcon };
export { createIconifyIcon };

View File

@ -1,77 +1,84 @@
import { createIcon } from './create-icon';
import { createIconifyIcon } from './create-icon';
export const IconDefault = createIcon('ic:round-auto-awesome');
export const IconDefault = createIconifyIcon('ic:round-auto-awesome');
export const IcRoundKeyboardArrowDown = createIcon(
export const IcRoundKeyboardArrowDown = createIconifyIcon(
'ic:round-keyboard-arrow-down',
);
export const IcRoundChevronRight = createIcon('ic:round-chevron-right');
export const IcRoundChevronRight = createIconifyIcon('ic:round-chevron-right');
export const IcRoundKeyboard = createIcon('ic:round-keyboard');
// export const IcRoundMenuOpen = createIcon('ic:round-menu-open');
export const IcRoundMenu = createIconifyIcon('ic:round-menu');
export const IcRoundMenu = createIcon('ic:round-menu');
export const IcRoundMoreHoriz = createIconifyIcon('ic:round-more-horiz');
export const IcRoundMoreHoriz = createIcon('ic:round-more-horiz');
export const IcRoundFitScreen = createIconifyIcon('ic:round-fit-screen');
export const IcRoundFitScreen = createIcon('ic:round-fit-screen');
export const IcTwotoneFitScreen = createIconifyIcon('ic:twotone-fit-screen');
export const IcTwotoneFitScreen = createIcon('ic:twotone-fit-screen');
export const IcRoundColorLens = createIconifyIcon('ic:round-color-lens');
export const IcRoundColorLens = createIcon('ic:round-color-lens');
export const IcRoundMoreVert = createIconifyIcon('ic:round-more-vert');
export const IcRoundMoreVert = createIcon('ic:round-more-vert');
export const IcRoundFullscreen = createIconifyIcon('ic:round-fullscreen');
export const IcRoundFullscreen = createIcon('ic:round-fullscreen');
export const IcRoundFullscreenExit = createIconifyIcon(
'ic:round-fullscreen-exit',
);
export const IcRoundFullscreenExit = createIcon('ic:round-fullscreen-exit');
export const IcRoundClose = createIconifyIcon('ic:round-close');
export const IcRoundAutoAwesome = createIcon('ic:round-auto-awesome');
export const IcRoundRestartAlt = createIconifyIcon('ic:round-restart-alt');
export const IcRoundClose = createIcon('ic:round-close');
export const IcRoundLogout = createIconifyIcon('ic:round-logout');
export const IcRoundRestartAlt = createIcon('ic:round-restart-alt');
export const IcOutlineVisibility = createIconifyIcon('ic:outline-visibility');
export const IcRoundLogout = createIcon('ic:round-logout');
export const IcOutlineVisibilityOff = createIconifyIcon(
'ic:outline-visibility-off',
);
export const IcOutlineVisibility = createIcon('ic:outline-visibility');
export const IcRoundSearch = createIconifyIcon('ic:round-search');
export const IcOutlineVisibilityOff = createIcon('ic:outline-visibility-off');
export const IcRoundFolderCopy = createIconifyIcon('ic:round-folder-copy');
export const IcRoundSearch = createIcon('ic:round-search');
export const IcRoundFolderCopy = createIcon('ic:round-folder-copy');
export const IcRoundSubdirectoryArrowLeft = createIcon(
export const IcRoundSubdirectoryArrowLeft = createIconifyIcon(
'ic:round-subdirectory-arrow-left',
);
export const IcRoundArrowUpward = createIcon('ic:round-arrow-upward');
export const IcRoundArrowUpward = createIconifyIcon('ic:round-arrow-upward');
export const IcRoundArrowDownward = createIcon('ic:round-arrow-downward');
export const IcRoundArrowDownward = createIconifyIcon(
'ic:round-arrow-downward',
);
export const IcBaselineLanguage = createIcon('ic:baseline-language');
export const IcBaselineLanguage = createIconifyIcon('ic:baseline-language');
export const IcRoundSearchOff = createIcon('ic:round-search-off');
export const IcRoundSearchOff = createIconifyIcon('ic:round-search-off');
export const IcRoundNotificationsNone = createIcon(
export const IcRoundNotificationsNone = createIconifyIcon(
'ic:round-notifications-none',
);
export const IcRoundMarkEmailRead = createIcon('ic:round-mark-email-read');
export const IcRoundMarkEmailRead = createIconifyIcon(
'ic:round-mark-email-read',
);
export const IcRoundWbSunny = createIcon('ic:round-wb-sunny');
export const IcRoundWbSunny = createIconifyIcon('ic:round-wb-sunny');
export const IcRoundMotionPhotosAuto = createIcon(
export const IcRoundMotionPhotosAuto = createIconifyIcon(
'ic:round-motion-photos-auto',
);
export const IcRoundSettingsSuggest = createIcon('ic:round-settings-suggest');
export const IcRoundSettingsSuggest = createIconifyIcon(
'ic:round-settings-suggest',
);
export const IcRoundArrowBackIosNew = createIcon('ic:round-arrow-back-ios-new');
export const IcRoundArrowBackIosNew = createIconifyIcon(
'ic:round-arrow-back-ios-new',
);
export const IcRoundMultipleStop = createIcon('ic:round-multiple-stop');
export const IcRoundMultipleStop = createIconifyIcon('ic:round-multiple-stop');
export const IcRoundRefresh = createIcon('ic:round-refresh');
export const IcRoundRefresh = createIconifyIcon('ic:round-refresh');
export const IcRoundCreditScore = createIcon('ic:round-credit-score');
export const IcRoundCreditScore = createIconifyIcon('ic:round-credit-score');

View File

@ -1,49 +1,49 @@
import { createIcon } from './create-icon';
import { createIconifyIcon } from './create-icon';
export const MdiKeyboardEsc = createIcon('mdi:keyboard-esc');
export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');
export const MdiLoading = createIcon('mdi:loading');
export const MdiLoading = createIconifyIcon('mdi:loading');
export const MdiWechat = createIcon('mdi:wechat');
export const MdiWechat = createIconifyIcon('mdi:wechat');
export const MdiGithub = createIcon('mdi:github');
export const MdiGithub = createIconifyIcon('mdi:github');
export const MdiGoogle = createIcon('mdi:google');
export const MdiGoogle = createIconifyIcon('mdi:google');
export const MdiQqchat = createIcon('mdi:qqchat');
export const MdiQqchat = createIconifyIcon('mdi:qqchat');
export const MdiPin = createIcon('mdi:pin');
export const MdiPin = createIconifyIcon('mdi:pin');
export const MdiPinOff = createIcon('mdi:pin-off');
export const MdiPinOff = createIconifyIcon('mdi:pin-off');
export const MdiFormatHorizontalAlignLeft = createIcon(
export const MdiFormatHorizontalAlignLeft = createIconifyIcon(
'mdi:format-horizontal-align-left',
);
export const MdiFormatHorizontalAlignRight = createIcon(
export const MdiFormatHorizontalAlignRight = createIconifyIcon(
'mdi:format-horizontal-align-right',
);
export const MdiArrowExpandHorizontal = createIcon(
export const MdiArrowExpandHorizontal = createIconifyIcon(
'mdi:arrow-expand-horizontal',
);
export const MdiMenuClose = createIcon('mdi:menu-close');
export const MdiMenuClose = createIconifyIcon('mdi:menu-close');
export const MdiMenuOpen = createIcon('mdi:menu-open');
export const MdiMenuOpen = createIconifyIcon('mdi:menu-open');
export const MdiDockLeft = createIcon('mdi:dock-left');
export const MdiDockLeft = createIconifyIcon('mdi:dock-left');
export const MdiDockRight = createIcon('mdi:dock-right');
export const MdiDockRight = createIconifyIcon('mdi:dock-right');
export const MdiDockBottom = createIcon('mdi:dock-bottom');
export const MdiDockBottom = createIconifyIcon('mdi:dock-bottom');
export const MdiDriveDocument = createIcon('mdi:drive-document');
export const MdiDriveDocument = createIconifyIcon('mdi:drive-document');
export const MdiMoonAndStars = createIcon('mdi:moon-and-stars');
export const MdiMoonAndStars = createIconifyIcon('mdi:moon-and-stars');
export const MdiEditBoxOutline = createIcon('mdi:edit-box-outline');
export const MdiEditBoxOutline = createIconifyIcon('mdi:edit-box-outline');
export const MdiQuestionMarkCircleOutline = createIcon(
export const MdiQuestionMarkCircleOutline = createIconifyIcon(
'mdi:question-mark-circle-outline',
);

View File

@ -51,7 +51,6 @@
"class-variance-authority": "^0.7.0",
"lucide-vue-next": "^0.400.0",
"radix-vue": "^1.9.0",
"vue": "^3.4.31",
"vue-sonner": "^1.1.3"
"vue": "^3.4.31"
}
}

View File

@ -41,9 +41,9 @@ export * from './ui/popover';
export * from './ui/scroll-area';
export * from './ui/select';
export * from './ui/sheet';
export * from './ui/sonner';
export * from './ui/switch';
export * from './ui/tabs';
export * from './ui/toast';
export * from './ui/toggle';
export * from './ui/toggle-group';
export * from './ui/tooltip';

View File

@ -1,41 +0,0 @@
<script lang="ts" setup>
import { Toaster as Sonner, type ToasterProps } from 'vue-sonner';
const props = withDefaults(defineProps<ToasterProps>(), {
closeButton: true,
duration: 2500,
position: 'top-right',
richColors: true,
visibleToasts: 3,
});
</script>
<template>
<Sonner
class="toaster group"
v-bind="props"
:toast-options="{
classes: {
closeButton:
'!border-border group-[.toast]:bg-muted group-[.toast]:text-muted-foreground !bg-muted hover:!text-foreground',
toast:
'group toast group-[.toaster]:bg-background group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
description: 'group-[.toast]:text-muted-foreground',
actionButton:
'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
cancelButton:
'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
},
}"
/>
</template>
<!-- <style scoped>
:deep([data-sonner-toaster][data-theme='dark']),
:deep([data-sonner-toaster][data-theme='light']) {
--normal-bg: hsl(var(--background));
--normal-border: theme('colors.border');
--normal-text: theme('colors.popover.foreground');
--border-radius: theme('borderRadius.md');
}
</style> -->

View File

@ -1,2 +0,0 @@
export { default as Toaster } from './Sonner.vue';
export { toast } from 'vue-sonner';

View File

@ -0,0 +1,35 @@
<script setup lang="ts">
import { computed } from 'vue';
import { cn } from '@vben-core/toolkit';
import {
ToastRoot,
type ToastRootEmits,
useForwardPropsEmits,
} from 'radix-vue';
import { type ToastProps, toastVariants } from '.';
const props = defineProps<ToastProps>();
const emits = defineEmits<ToastRootEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<ToastRoot
v-bind="forwarded"
:class="cn(toastVariants({ variant }), props.class)"
@update:open="onOpenChange"
>
<slot></slot>
</ToastRoot>
</template>

View File

@ -0,0 +1,31 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue';
import { cn } from '@vben-core/toolkit';
import { ToastAction, type ToastActionProps } from 'radix-vue';
const props = defineProps<
{ class?: HTMLAttributes['class'] } & ToastActionProps
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<ToastAction
v-bind="delegatedProps"
:class="
cn(
'hover:bg-secondary focus:ring-ring group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive border-border inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors focus:outline-none focus:ring-1 disabled:pointer-events-none disabled:opacity-50',
props.class,
)
"
>
<slot></slot>
</ToastAction>
</template>

View File

@ -0,0 +1,34 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue';
import { cn } from '@vben-core/toolkit';
import { Cross2Icon } from '@radix-icons/vue';
import { ToastClose, type ToastCloseProps } from 'radix-vue';
const props = defineProps<
{
class?: HTMLAttributes['class'];
} & ToastCloseProps
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<ToastClose
v-bind="delegatedProps"
:class="
cn(
'text-foreground/50 hover:text-foreground absolute right-1 top-1 rounded-md p-1 opacity-0 transition-opacity focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600',
props.class,
)
"
>
<Cross2Icon class="h-4 w-4" />
</ToastClose>
</template>

View File

@ -0,0 +1,26 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue';
import { cn } from '@vben-core/toolkit';
import { ToastDescription, type ToastDescriptionProps } from 'radix-vue';
const props = defineProps<
{ class?: HTMLAttributes['class'] } & ToastDescriptionProps
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<ToastDescription
:class="cn('text-sm opacity-90', props.class)"
v-bind="delegatedProps"
>
<slot></slot>
</ToastDescription>
</template>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
import { ToastProvider, type ToastProviderProps } from 'radix-vue';
const props = defineProps<ToastProviderProps>();
</script>
<template>
<ToastProvider v-bind="props">
<slot></slot>
</ToastProvider>
</template>

View File

@ -0,0 +1,26 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue';
import { cn } from '@vben-core/toolkit';
import { ToastTitle, type ToastTitleProps } from 'radix-vue';
const props = defineProps<
{ class?: HTMLAttributes['class'] } & ToastTitleProps
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<ToastTitle
v-bind="delegatedProps"
:class="cn('text-sm font-semibold [&+div]:text-xs', props.class)"
>
<slot></slot>
</ToastTitle>
</template>

View File

@ -0,0 +1,29 @@
<script setup lang="ts">
import { type HTMLAttributes, computed } from 'vue';
import { cn } from '@vben-core/toolkit';
import { ToastViewport, type ToastViewportProps } from 'radix-vue';
const props = defineProps<
{ class?: HTMLAttributes['class'] } & ToastViewportProps
>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
</script>
<template>
<ToastViewport
v-bind="delegatedProps"
:class="
cn(
'fixed top-0 z-[1200] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
props.class,
)
"
/>
</template>

View File

@ -0,0 +1,38 @@
<script setup lang="ts">
import { isVNode } from 'vue';
import {
Toast,
ToastClose,
ToastDescription,
ToastProvider,
ToastTitle,
ToastViewport,
} from '.';
import { useToast } from './use-toast';
const { toasts } = useToast();
</script>
<template>
<ToastProvider swipe-direction="down">
<Toast v-for="toast in toasts" :key="toast.id" v-bind="toast">
<div class="grid gap-1">
<ToastTitle v-if="toast.title">
{{ toast.title }}
</ToastTitle>
<template v-if="toast.description">
<ToastDescription v-if="isVNode(toast.description)">
<component :is="toast.description" />
</ToastDescription>
<ToastDescription v-else>
{{ toast.description }}
</ToastDescription>
</template>
<ToastClose />
</div>
<component :is="toast.action" />
</Toast>
<ToastViewport />
</ToastProvider>
</template>

View File

@ -0,0 +1,39 @@
import type { ToastRootProps } from 'radix-vue';
import type { HTMLAttributes } from 'vue';
import { type VariantProps, cva } from 'class-variance-authority';
export { default as Toast } from './Toast.vue';
export { default as ToastAction } from './ToastAction.vue';
export { default as ToastClose } from './ToastClose.vue';
export { default as ToastDescription } from './ToastDescription.vue';
export { default as ToastProvider } from './ToastProvider.vue';
export { default as ToastTitle } from './ToastTitle.vue';
export { default as ToastViewport } from './ToastViewport.vue';
export { default as Toaster } from './Toaster.vue';
export { toast, useToast } from './use-toast';
export const toastVariants = cva(
'group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',
{
defaultVariants: {
variant: 'default',
},
variants: {
variant: {
default: 'border bg-background border-border text-foreground',
destructive:
'destructive group border-destructive bg-destructive text-destructive-foreground',
},
},
},
);
type ToastVariants = VariantProps<typeof toastVariants>;
export interface ToastProps extends ToastRootProps {
class?: HTMLAttributes['class'];
onOpenChange?: ((value: boolean) => void) | undefined;
variant?: ToastVariants['variant'];
}

View File

@ -0,0 +1,168 @@
import type { ToastProps } from '.';
import { computed, ref } from 'vue';
import type { Component, VNode } from 'vue';
const TOAST_LIMIT = 1;
const TOAST_REMOVE_DELAY = 1_000_000;
export type StringOrVNode = (() => VNode) | VNode | string;
type ToasterToast = {
action?: Component;
description?: StringOrVNode;
id: string;
title?: string;
} & ToastProps;
const actionTypes = {
ADD_TOAST: 'ADD_TOAST',
DISMISS_TOAST: 'DISMISS_TOAST',
REMOVE_TOAST: 'REMOVE_TOAST',
UPDATE_TOAST: 'UPDATE_TOAST',
} as const;
let count = 0;
function genId() {
count = (count + 1) % Number.MAX_VALUE;
return count.toString();
}
type ActionType = typeof actionTypes;
type Action =
| {
toast: Partial<ToasterToast>;
type: ActionType['UPDATE_TOAST'];
}
| {
toast: ToasterToast;
type: ActionType['ADD_TOAST'];
}
| {
toastId?: ToasterToast['id'];
type: ActionType['DISMISS_TOAST'];
}
| {
toastId?: ToasterToast['id'];
type: ActionType['REMOVE_TOAST'];
};
interface State {
toasts: ToasterToast[];
}
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
function addToRemoveQueue(toastId: string) {
if (toastTimeouts.has(toastId)) return;
const timeout = setTimeout(() => {
toastTimeouts.delete(toastId);
dispatch({
toastId,
type: actionTypes.REMOVE_TOAST,
});
}, TOAST_REMOVE_DELAY);
toastTimeouts.set(toastId, timeout);
}
const state = ref<State>({
toasts: [],
});
function dispatch(action: Action) {
switch (action.type) {
case actionTypes.ADD_TOAST: {
state.value.toasts = [action.toast, ...state.value.toasts].slice(
0,
TOAST_LIMIT,
);
break;
}
case actionTypes.UPDATE_TOAST: {
state.value.toasts = state.value.toasts.map((t) =>
t.id === action.toast.id ? { ...t, ...action.toast } : t,
);
break;
}
case actionTypes.DISMISS_TOAST: {
const { toastId } = action;
if (toastId) {
addToRemoveQueue(toastId);
} else {
state.value.toasts.forEach((toast) => {
addToRemoveQueue(toast.id);
});
}
state.value.toasts = state.value.toasts.map((t) =>
t.id === toastId || toastId === undefined
? {
...t,
open: false,
}
: t,
);
break;
}
case actionTypes.REMOVE_TOAST: {
state.value.toasts =
action.toastId === undefined
? []
: state.value.toasts.filter((t) => t.id !== action.toastId);
break;
}
}
}
function useToast() {
return {
dismiss: (toastId?: string) =>
dispatch({ toastId, type: actionTypes.DISMISS_TOAST }),
toast,
toasts: computed(() => state.value.toasts),
};
}
type Toast = Omit<ToasterToast, 'id'>;
function toast(props: Toast) {
const id = genId();
const update = (props: ToasterToast) =>
dispatch({
toast: { ...props, id },
type: actionTypes.UPDATE_TOAST,
});
const dismiss = () =>
dispatch({ toastId: id, type: actionTypes.DISMISS_TOAST });
dispatch({
toast: {
...props,
id,
onOpenChange: (open: boolean) => {
if (!open) dismiss();
},
open: true,
},
type: actionTypes.ADD_TOAST,
});
return {
dismiss,
id,
update,
};
}
export { toast, useToast };

View File

@ -2,3 +2,4 @@ export * from './about';
export * from './authentication';
export * from './dashboard';
export * from './fallback';
export { useToast } from '@vben-core/shadcn-ui';

View File

@ -28,7 +28,7 @@ import {
VbenIconButton,
VbenSegmented,
VbenSheet,
toast,
useToast,
} from '@vben-core/shadcn-ui';
import { useClipboard } from '@vueuse/core';
@ -56,7 +56,7 @@ import Trigger from './trigger.vue';
import { useOpenPreferences } from './use-open-preferences';
const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
const { toast } = useToast();
const appLocale = defineModel<SupportedLanguagesType>('appLocale');
const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
const appAiAssistant = defineModel<boolean>('appAiAssistant');
@ -177,7 +177,10 @@ const { openPreferences } = useOpenPreferences();
async function handleCopy() {
await copy(JSON.stringify(diffPreference.value, null, 2));
toast($t('preferences.copy-success'));
toast({
description: $t('preferences.copy'),
title: $t('preferences.copy-success'),
});
}
async function handleClearCache() {
@ -192,7 +195,14 @@ async function handleReset() {
}
resetPreferences();
await loadLocaleMessages(preferences.app.locale);
toast($t('preferences.reset-success'));
toast({
description: $t('preferences.reset-title'),
title: $t('preferences.reset-success'),
});
toast({
description: $t('preferences.reset-title'),
title: $t('preferences.reset-success'),
});
}
</script>

View File

@ -1,4 +1,4 @@
import { createIcon } from '@vben-core/iconify';
import { createIconifyIcon } from '@vben-core/iconify';
import { loadSvgIcons } from './load';
@ -8,14 +8,14 @@ if (!loaded) {
loaded = true;
}
const SvgAvatar1Icon = createIcon('svg:avatar-1');
const SvgAvatar2Icon = createIcon('svg:avatar-2');
const SvgAvatar3Icon = createIcon('svg:avatar-3');
const SvgAvatar4Icon = createIcon('svg:avatar-4');
const SvgDownloadIcon = createIcon('svg:download');
const SvgCardIcon = createIcon('svg:card');
const SvgBellIcon = createIcon('svg:bell');
const SvgCakeIcon = createIcon('svg:cake');
const SvgAvatar1Icon = createIconifyIcon('svg:avatar-1');
const SvgAvatar2Icon = createIconifyIcon('svg:avatar-2');
const SvgAvatar3Icon = createIconifyIcon('svg:avatar-3');
const SvgAvatar4Icon = createIconifyIcon('svg:avatar-4');
const SvgDownloadIcon = createIconifyIcon('svg:download');
const SvgCardIcon = createIconifyIcon('svg:card');
const SvgBellIcon = createIconifyIcon('svg:bell');
const SvgCakeIcon = createIconifyIcon('svg:cake');
export {
SvgAvatar1Icon,

View File

@ -784,9 +784,6 @@ importers:
vue:
specifier: ^3.4.31
version: 3.4.31(typescript@5.5.3)
vue-sonner:
specifier: ^1.1.3
version: 1.1.3
packages/@core/ui-kit/tabs-ui:
dependencies:
@ -9183,9 +9180,6 @@ packages:
peerDependencies:
vue: ^3.4.31
vue-sonner@1.1.3:
resolution: {integrity: sha512-6I+5GNobKvE2nR5MPhO+T59d4j2LXRQoc/ZCmGtCoBWKDQr5nzSqjFaOOdPysHFI2p42wNLhQMafd0N540UW9Q==}
vue-template-compiler@2.7.16:
resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==}
@ -18548,8 +18542,6 @@ snapshots:
'@vue/devtools-api': 6.6.3
vue: 3.4.31(typescript@5.5.3)
vue-sonner@1.1.3: {}
vue-template-compiler@2.7.16:
dependencies:
de-indent: 1.0.2