mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 16:46:19 +08:00
feat: add modal and drawer components and examples (#4229)
* feat: add modal component * feat: add drawer component * feat: apply new modal and drawer components to the layout * chore: typo * feat: add some unit tests
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"@vben-core/layout-ui": "workspace:*",
|
||||
"@vben-core/menu-ui": "workspace:*",
|
||||
"@vben-core/popup-ui": "workspace:*",
|
||||
"@vben-core/shadcn-ui": "workspace:*",
|
||||
"@vben-core/tabs-ui": "workspace:*",
|
||||
"@vben/constants": "workspace:*",
|
||||
|
@@ -12,17 +12,9 @@ import {
|
||||
} from '@vben/icons';
|
||||
import { $t } from '@vben/locales';
|
||||
import { isWindowsOs } from '@vben/utils';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
import { useVbenModal } from '@vben-core/popup-ui';
|
||||
|
||||
import { useMagicKeys, useToggle, whenever } from '@vueuse/core';
|
||||
import { useMagicKeys, whenever } from '@vueuse/core';
|
||||
|
||||
import SearchPanel from './search-panel.vue';
|
||||
|
||||
@@ -38,12 +30,18 @@ const props = withDefaults(
|
||||
},
|
||||
);
|
||||
|
||||
const [open, toggleOpen] = useToggle();
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
onCancel() {
|
||||
modalApi.close();
|
||||
},
|
||||
});
|
||||
const open = modalApi.useStore((state) => state.isOpen);
|
||||
|
||||
const keyword = ref('');
|
||||
const searchInputRef = ref<HTMLInputElement>();
|
||||
|
||||
function handleClose() {
|
||||
open.value = false;
|
||||
modalApi.close();
|
||||
keyword.value = '';
|
||||
}
|
||||
|
||||
@@ -51,7 +49,7 @@ const keys = useMagicKeys();
|
||||
const cmd = isWindowsOs() ? keys['ctrl+k'] : keys['cmd+k'];
|
||||
whenever(cmd!, () => {
|
||||
if (props.enableShortcutKey) {
|
||||
open.value = true;
|
||||
modalApi.open();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -75,6 +73,10 @@ const toggleKeydownListener = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const toggleOpen = () => {
|
||||
open.value ? modalApi.close() : modalApi.open();
|
||||
};
|
||||
|
||||
watch(() => props.enableShortcutKey, toggleKeydownListener);
|
||||
|
||||
onMounted(() => {
|
||||
@@ -88,67 +90,58 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Dialog :open="open">
|
||||
<DialogTrigger as-child>
|
||||
<div
|
||||
class="md:bg-accent group flex h-8 cursor-pointer items-center gap-3 rounded-2xl border-none bg-none px-2 py-0.5 outline-none"
|
||||
@click="toggleOpen()"
|
||||
>
|
||||
<Search
|
||||
class="text-muted-foreground group-hover:text-foreground size-3 group-hover:opacity-100"
|
||||
<Modal :fullscreen-button="false" class="w-[600px]" header-class="py-2">
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<Search class="text-muted-foreground mr-2 size-4" />
|
||||
<input
|
||||
ref="searchInputRef"
|
||||
v-model="keyword"
|
||||
:placeholder="$t('widgets.search.searchNavigate')"
|
||||
class="ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 pl-0 text-sm font-normal outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent"
|
||||
/>
|
||||
<span
|
||||
class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block"
|
||||
>
|
||||
{{ $t('widgets.search.title') }}
|
||||
</span>
|
||||
<span
|
||||
v-if="enableShortcutKey"
|
||||
class="bg-background border-foreground/60 text-muted-foreground group-hover:text-foreground relative hidden rounded-sm rounded-r-xl px-1.5 py-1 text-xs leading-none group-hover:opacity-100 md:block"
|
||||
>
|
||||
{{ isWindowsOs() ? 'Ctrl' : '⌘' }}
|
||||
<kbd>K</kbd>
|
||||
</span>
|
||||
<span v-else></span>
|
||||
</div>
|
||||
</DialogTrigger>
|
||||
<DialogContent
|
||||
class="top-0 h-full w-full -translate-y-0 border-none p-0 shadow-xl sm:top-[10%] sm:h-[unset] sm:w-[600px] sm:rounded-2xl"
|
||||
@close="handleClose"
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle
|
||||
class="border-border flex h-12 items-center gap-3 border-b px-5 font-normal"
|
||||
>
|
||||
<Search class="text-muted-foreground size-4" />
|
||||
<input
|
||||
ref="searchInputRef"
|
||||
v-model="keyword"
|
||||
:placeholder="$t('widgets.search.searchNavigate')"
|
||||
class="ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 pl-0 text-sm outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<DialogDescription />
|
||||
</DialogHeader>
|
||||
<SearchPanel :keyword="keyword" :menus="menus" @close="handleClose" />
|
||||
<DialogFooter
|
||||
class="text-muted-foreground border-border hidden flex-row rounded-b-2xl border-t px-4 py-2 text-xs sm:flex sm:justify-start sm:gap-x-4"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
</template>
|
||||
|
||||
<SearchPanel :keyword="keyword" :menus="menus" @close="handleClose" />
|
||||
<template #footer>
|
||||
<div class="flex w-full justify-start text-xs">
|
||||
<div class="mr-2 flex items-center">
|
||||
<CornerDownLeft class="mr-1 size-3" />
|
||||
{{ $t('widgets.search.select') }}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<ArrowUp class="mr-2 size-3" />
|
||||
<ArrowDown class="mr-2 size-3" />
|
||||
<div class="mr-2 flex items-center">
|
||||
<ArrowUp class="mr-1 size-3" />
|
||||
<ArrowDown class="mr-1 size-3" />
|
||||
{{ $t('widgets.search.navigate') }}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<MdiKeyboardEsc class="mr-1 size-3" />
|
||||
{{ $t('widgets.search.close') }}
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
</Modal>
|
||||
<div
|
||||
class="md:bg-accent group flex h-8 cursor-pointer items-center gap-3 rounded-2xl border-none bg-none px-2 py-0.5 outline-none"
|
||||
@click="toggleOpen()"
|
||||
>
|
||||
<Search
|
||||
class="text-muted-foreground group-hover:text-foreground size-3 group-hover:opacity-100"
|
||||
/>
|
||||
<span
|
||||
class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block"
|
||||
>
|
||||
{{ $t('widgets.search.title') }}
|
||||
</span>
|
||||
<span
|
||||
v-if="enableShortcutKey"
|
||||
class="bg-background border-foreground/60 text-muted-foreground group-hover:text-foreground relative hidden rounded-sm rounded-r-xl px-1.5 py-1 text-xs leading-none group-hover:opacity-100 md:block"
|
||||
>
|
||||
{{ isWindowsOs() ? 'Ctrl' : '⌘' }}
|
||||
<kbd>K</kbd>
|
||||
</span>
|
||||
<span v-else></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -217,14 +217,14 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<VbenScrollbar>
|
||||
<div class="!flex h-full justify-center px-4 sm:max-h-[450px]">
|
||||
<div class="!flex h-full justify-center px-2 sm:max-h-[450px]">
|
||||
<!-- 无搜索结果 -->
|
||||
<div
|
||||
v-if="keyword && searchResults.length === 0"
|
||||
class="text-muted-foreground text-center"
|
||||
>
|
||||
<SearchX class="mx-auto size-12" />
|
||||
<p class="my-10 text-xs">
|
||||
<SearchX class="mx-auto mt-4 size-12" />
|
||||
<p class="mb-10 mt-6 text-xs">
|
||||
{{ $t('widgets.search.noResults') }}
|
||||
<span class="text-foreground text-sm font-medium">
|
||||
"{{ keyword }}"
|
||||
|
@@ -1,12 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben-core/popup-ui';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
VbenAvatar,
|
||||
VbenButton,
|
||||
VbenInputPassword,
|
||||
@@ -28,28 +24,33 @@ interface RegisterEmits {
|
||||
defineOptions({
|
||||
name: 'LockScreenModal',
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
avatar: '',
|
||||
text: '',
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: RegisterEmits['submit'];
|
||||
}>();
|
||||
|
||||
const [Modal] = useVbenModal({
|
||||
onConfirm() {
|
||||
handleSubmit();
|
||||
},
|
||||
});
|
||||
|
||||
const formState = reactive({
|
||||
lockScreenPassword: '',
|
||||
submitted: false,
|
||||
});
|
||||
const openModal = defineModel<boolean>('open');
|
||||
|
||||
const passwordStatus = computed(() => {
|
||||
return formState.submitted && !formState.lockScreenPassword
|
||||
? 'error'
|
||||
: 'default';
|
||||
});
|
||||
|
||||
function handleClose() {
|
||||
openModal.value = false;
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
formState.submitted = true;
|
||||
if (passwordStatus.value !== 'default') {
|
||||
@@ -62,51 +63,40 @@ function handleSubmit() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Dialog :open="openModal">
|
||||
<DialogContent
|
||||
class="top-0 h-full w-full -translate-y-0 border-none p-0 shadow-xl sm:top-[20%] sm:h-[unset] sm:w-[600px] sm:rounded-2xl"
|
||||
@close="handleClose"
|
||||
>
|
||||
<DialogDescription />
|
||||
<DialogHeader>
|
||||
<DialogTitle
|
||||
class="border-border flex h-8 items-center px-5 font-normal"
|
||||
>
|
||||
{{ $t('widgets.lockScreen.title') }}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div
|
||||
class="mb-10 flex w-full flex-col items-center"
|
||||
@keypress.enter.prevent="handleSubmit"
|
||||
>
|
||||
<div class="w-2/3">
|
||||
<div class="ml-2 flex w-full flex-col items-center">
|
||||
<VbenAvatar
|
||||
:src="avatar"
|
||||
class="size-24"
|
||||
dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
|
||||
/>
|
||||
<div class="text-foreground my-6 flex items-center font-medium">
|
||||
{{ text }}
|
||||
</div>
|
||||
</div>
|
||||
<VbenInputPassword
|
||||
v-model="formState.lockScreenPassword"
|
||||
:error-tip="$t('widgets.lockScreen.placeholder')"
|
||||
:label="$t('widgets.lockScreen.password')"
|
||||
:placeholder="$t('widgets.lockScreen.placeholder')"
|
||||
:status="passwordStatus"
|
||||
name="password"
|
||||
required
|
||||
type="password"
|
||||
/>
|
||||
<VbenButton class="w-full" @click="handleSubmit">
|
||||
{{ $t('widgets.lockScreen.screenButton') }}
|
||||
</VbenButton>
|
||||
<Modal
|
||||
:footer="false"
|
||||
:fullscreen-button="false"
|
||||
:title="$t('widgets.lockScreen.title')"
|
||||
>
|
||||
<div
|
||||
class="mb-10 flex w-full flex-col items-center px-10"
|
||||
@keypress.enter.prevent="handleSubmit"
|
||||
>
|
||||
<div class="w-full">
|
||||
<div class="ml-2 flex w-full flex-col items-center">
|
||||
<VbenAvatar
|
||||
:src="avatar"
|
||||
class="size-20"
|
||||
dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
|
||||
/>
|
||||
<div class="text-foreground my-6 flex items-center font-medium">
|
||||
{{ text }}
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<VbenInputPassword
|
||||
v-model="formState.lockScreenPassword"
|
||||
:error-tip="$t('widgets.lockScreen.placeholder')"
|
||||
:label="$t('widgets.lockScreen.password')"
|
||||
:placeholder="$t('widgets.lockScreen.placeholder')"
|
||||
:status="passwordStatus"
|
||||
name="password"
|
||||
required
|
||||
type="password"
|
||||
/>
|
||||
<VbenButton class="w-full" @click="handleSubmit">
|
||||
{{ $t('widgets.lockScreen.screenButton') }}
|
||||
</VbenButton>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
@@ -15,7 +15,7 @@ const shortcutKeysGlobalSearch = defineModel<boolean>(
|
||||
'shortcutKeysGlobalSearch',
|
||||
);
|
||||
const shortcutKeysLogout = defineModel<boolean>('shortcutKeysLogout');
|
||||
const shortcutKeysPreferences = defineModel<boolean>('shortcutKeysPreferences');
|
||||
// const shortcutKeysPreferences = defineModel<boolean>('shortcutKeysPreferences');
|
||||
const shortcutKeysLockScreen = defineModel<boolean>('shortcutKeysLockScreen');
|
||||
|
||||
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
|
||||
@@ -39,10 +39,10 @@ const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
|
||||
{{ $t('preferences.shortcutKeys.logout') }}
|
||||
<template #shortcut> {{ altView }} Q </template>
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="shortcutKeysPreferences" :disabled="!shortcutKeysEnable">
|
||||
<!-- <SwitchItem v-model="shortcutKeysPreferences" :disabled="!shortcutKeysEnable">
|
||||
{{ $t('preferences.shortcutKeys.preferences') }}
|
||||
<template #shortcut> {{ altView }} , </template>
|
||||
</SwitchItem>
|
||||
</SwitchItem> -->
|
||||
<SwitchItem v-model="shortcutKeysLockScreen" :disabled="!shortcutKeysEnable">
|
||||
{{ $t('widgets.lockScreen.title') }}
|
||||
<template #shortcut> {{ altView }} L </template>
|
||||
|
@@ -14,7 +14,7 @@ import type { SegmentedItem } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { Copy, RotateCw, Settings } from '@vben/icons';
|
||||
import { Copy, RotateCw } from '@vben/icons';
|
||||
import { $t, loadLocaleMessages } from '@vben/locales';
|
||||
import {
|
||||
clearPreferencesCache,
|
||||
@@ -22,12 +22,12 @@ import {
|
||||
resetPreferences,
|
||||
usePreferences,
|
||||
} from '@vben/preferences';
|
||||
import { useVbenDrawer } from '@vben-core/popup-ui';
|
||||
import {
|
||||
useToast,
|
||||
VbenButton,
|
||||
VbenIconButton,
|
||||
VbenSegmented,
|
||||
VbenSheet,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
@@ -52,7 +52,6 @@ import {
|
||||
Theme,
|
||||
Widget,
|
||||
} from './blocks';
|
||||
import { useOpenPreferences } from './use-open-preferences';
|
||||
|
||||
const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
|
||||
const { toast } = useToast();
|
||||
@@ -134,9 +133,7 @@ const shortcutKeysGlobalSearch = defineModel<boolean>(
|
||||
const shortcutKeysGlobalLogout = defineModel<boolean>(
|
||||
'shortcutKeysGlobalLogout',
|
||||
);
|
||||
const shortcutKeysGlobalPreferences = defineModel<boolean>(
|
||||
'shortcutKeysGlobalPreferences',
|
||||
);
|
||||
|
||||
const shortcutKeysGlobalLockScreen = defineModel<boolean>(
|
||||
'shortcutKeysGlobalLockScreen',
|
||||
);
|
||||
@@ -161,6 +158,8 @@ const {
|
||||
} = usePreferences();
|
||||
const { copy } = useClipboard();
|
||||
|
||||
const [Drawer] = useVbenDrawer();
|
||||
|
||||
const activeTab = ref('appearance');
|
||||
|
||||
const tabs = computed((): SegmentedItem[] => {
|
||||
@@ -193,8 +192,6 @@ const showBreadcrumbConfig = computed(() => {
|
||||
);
|
||||
});
|
||||
|
||||
const { openPreferences } = useOpenPreferences();
|
||||
|
||||
async function handleCopy() {
|
||||
await copy(JSON.stringify(diffPreference.value, null, 2));
|
||||
|
||||
@@ -225,21 +222,11 @@ async function handleReset() {
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VbenSheet
|
||||
v-model:open="openPreferences"
|
||||
<Drawer
|
||||
:description="$t('preferences.subtitle')"
|
||||
:title="$t('preferences.title')"
|
||||
class="sm:max-w-sm"
|
||||
>
|
||||
<template #trigger>
|
||||
<slot name="trigger">
|
||||
<VbenButton
|
||||
:title="$t('preferences.title')"
|
||||
class="bg-primary flex-col-center size-10 cursor-pointer rounded-l-lg rounded-r-none border-none"
|
||||
>
|
||||
<Settings class="size-5" />
|
||||
</VbenButton>
|
||||
</slot>
|
||||
</template>
|
||||
<template #extra>
|
||||
<div class="flex items-center">
|
||||
<VbenIconButton
|
||||
@@ -256,7 +243,7 @@ async function handleReset() {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="p-4 pt-4">
|
||||
<div class="p-1">
|
||||
<VbenSegmented v-model="activeTab" :tabs="tabs">
|
||||
<template #general>
|
||||
<Block :title="$t('preferences.general')">
|
||||
@@ -402,9 +389,6 @@ async function handleReset() {
|
||||
v-model:shortcut-keys-global-search="shortcutKeysGlobalSearch"
|
||||
v-model:shortcut-keys-lock-screen="shortcutKeysGlobalLockScreen"
|
||||
v-model:shortcut-keys-logout="shortcutKeysGlobalLogout"
|
||||
v-model:shortcut-keys-preferences="
|
||||
shortcutKeysGlobalPreferences
|
||||
"
|
||||
/>
|
||||
</Block>
|
||||
</template>
|
||||
@@ -433,6 +417,6 @@ async function handleReset() {
|
||||
{{ $t('preferences.clearAndLogout') }}
|
||||
</VbenButton>
|
||||
</template>
|
||||
</VbenSheet>
|
||||
</Drawer>
|
||||
</div>
|
||||
</template>
|
@@ -1,11 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { loadLocaleMessages } from '@vben/locales';
|
||||
import { Settings } from '@vben/icons';
|
||||
import { $t, loadLocaleMessages } from '@vben/locales';
|
||||
import { preferences, updatePreferences } from '@vben/preferences';
|
||||
import { capitalizeFirstLetter } from '@vben/utils';
|
||||
import { useVbenDrawer } from '@vben-core/popup-ui';
|
||||
import { VbenButton } from '@vben-core/shadcn-ui';
|
||||
|
||||
import PreferencesSheet from './preferences-sheet.vue';
|
||||
import PreferencesDrawer from './preferences-drawer.vue';
|
||||
|
||||
const [Drawer, drawerApi] = useVbenDrawer({
|
||||
connectedComponent: PreferencesDrawer,
|
||||
});
|
||||
|
||||
/**
|
||||
* preferences 转成 vue props
|
||||
@@ -47,9 +54,18 @@ const listen = computed(() => {
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<PreferencesSheet v-bind="attrs" v-on="listen">
|
||||
<template #trigger>
|
||||
<slot></slot>
|
||||
</template>
|
||||
</PreferencesSheet>
|
||||
<div>
|
||||
<Drawer v-bind="attrs" v-on="listen" />
|
||||
|
||||
<div @click="() => drawerApi.open()">
|
||||
<slot>
|
||||
<VbenButton
|
||||
:title="$t('preferences.title')"
|
||||
class="bg-primary flex-col-center size-10 cursor-pointer rounded-l-lg rounded-r-none border-none"
|
||||
>
|
||||
<Settings class="size-5" />
|
||||
</VbenButton>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -4,11 +4,12 @@ import type { AnyFunction } from '@vben/types';
|
||||
import type { Component } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { LockKeyhole, LogOut, SwatchBook } from '@vben/icons';
|
||||
import { LockKeyhole, LogOut } from '@vben/icons';
|
||||
import { $t } from '@vben/locales';
|
||||
import { preferences, usePreferences } from '@vben/preferences';
|
||||
import { useLockStore } from '@vben/stores';
|
||||
import { isWindowsOs } from '@vben/utils';
|
||||
import { useVbenModal } from '@vben-core/popup-ui';
|
||||
import {
|
||||
Badge,
|
||||
DropdownMenu,
|
||||
@@ -18,7 +19,6 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger,
|
||||
VbenAlertDialog,
|
||||
VbenAvatar,
|
||||
VbenIcon,
|
||||
} from '@vben-core/shadcn-ui';
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
import { useMagicKeys, whenever } from '@vueuse/core';
|
||||
|
||||
import { LockScreenModal } from '../lock-screen';
|
||||
import { useOpenPreferences } from '../preferences';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
@@ -72,16 +71,18 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
|
||||
const emit = defineEmits<{ logout: [] }>();
|
||||
const openPopover = ref(false);
|
||||
const openDialog = ref(false);
|
||||
const openLock = ref(false);
|
||||
|
||||
const {
|
||||
globalLockScreenShortcutKey,
|
||||
globalLogoutShortcutKey,
|
||||
globalPreferencesShortcutKey,
|
||||
} = usePreferences();
|
||||
const { globalLockScreenShortcutKey, globalLogoutShortcutKey } =
|
||||
usePreferences();
|
||||
const lockStore = useLockStore();
|
||||
const { handleOpenPreference } = useOpenPreferences();
|
||||
const [LockModal, lockModalApi] = useVbenModal({
|
||||
connectedComponent: LockScreenModal,
|
||||
});
|
||||
const [LogoutModal, logoutModalApi] = useVbenModal({
|
||||
onConfirm() {
|
||||
handleSubmitLogout();
|
||||
},
|
||||
});
|
||||
|
||||
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
|
||||
|
||||
@@ -97,12 +98,8 @@ const enableShortcutKey = computed(() => {
|
||||
return props.enableShortcutKey && preferences.shortcutKeys.enable;
|
||||
});
|
||||
|
||||
const enablePreferencesShortcutKey = computed(() => {
|
||||
return props.enableShortcutKey && globalPreferencesShortcutKey.value;
|
||||
});
|
||||
|
||||
function handleOpenLock() {
|
||||
openLock.value = true;
|
||||
lockModalApi.open();
|
||||
}
|
||||
|
||||
function handleSubmitLock({
|
||||
@@ -110,18 +107,19 @@ function handleSubmitLock({
|
||||
}: {
|
||||
lockScreenPassword: string;
|
||||
}) {
|
||||
openLock.value = false;
|
||||
lockModalApi.close();
|
||||
lockStore.lockScreen(lockScreenPassword);
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
// emit
|
||||
openDialog.value = true;
|
||||
logoutModalApi.open();
|
||||
openPopover.value = false;
|
||||
}
|
||||
|
||||
function handleSubmitLogout() {
|
||||
emit('logout');
|
||||
openDialog.value = false;
|
||||
logoutModalApi.close();
|
||||
}
|
||||
|
||||
if (enableShortcutKey.value) {
|
||||
@@ -132,12 +130,6 @@ if (enableShortcutKey.value) {
|
||||
}
|
||||
});
|
||||
|
||||
whenever(keys['Alt+Comma']!, () => {
|
||||
if (enablePreferencesShortcutKey.value) {
|
||||
handleOpenPreference();
|
||||
}
|
||||
});
|
||||
|
||||
whenever(keys['Alt+KeyL']!, () => {
|
||||
if (enableLockScreenShortcutKey.value) {
|
||||
handleOpenLock();
|
||||
@@ -147,21 +139,25 @@ if (enableShortcutKey.value) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LockScreenModal
|
||||
<LockModal
|
||||
v-if="preferences.widget.lockScreen"
|
||||
v-model:open="openLock"
|
||||
:avatar="avatar"
|
||||
:text="text"
|
||||
@submit="handleSubmitLock"
|
||||
/>
|
||||
<VbenAlertDialog
|
||||
v-model:open="openDialog"
|
||||
|
||||
<LogoutModal
|
||||
:cancel-text="$t('common.cancel')"
|
||||
:content="$t('widgets.logoutTip')"
|
||||
:submit-text="$t('common.confirm')"
|
||||
:confirm-text="$t('common.confirm')"
|
||||
:fullscreen-button="false"
|
||||
:title="$t('common.prompt')"
|
||||
@submit="handleSubmitLogout"
|
||||
/>
|
||||
centered
|
||||
content-class="px-8 min-h-10"
|
||||
footer-class="border-none mb-4 mr-4"
|
||||
header-class="border-none"
|
||||
>
|
||||
{{ $t('widgets.logoutTip') }}
|
||||
</LogoutModal>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
@@ -205,17 +201,6 @@ if (enableShortcutKey.value) {
|
||||
{{ menu.text }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
v-if="preferences.app.enablePreferences"
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="handleOpenPreference"
|
||||
>
|
||||
<SwatchBook class="mr-2 size-4" />
|
||||
{{ $t('preferences.title') }}
|
||||
<DropdownMenuShortcut v-if="enablePreferencesShortcutKey">
|
||||
{{ altView }} ,
|
||||
</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
v-if="preferences.widget.lockScreen"
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
|
Reference in New Issue
Block a user