feat: add shortcut keys preferencs

This commit is contained in:
vben 2024-06-16 13:43:33 +08:00
parent 5d829a6d9a
commit 222c73963d
38 changed files with 1449 additions and 887 deletions

2
.gitignore vendored
View File

@ -4,7 +4,7 @@ dist
dist-ssr
coverage
*.local
**/*/.vitepress/cache/deps
**/.vitepress/cache
.cache
.turbo
.stylelintcache

View File

@ -3,5 +3,5 @@ import { Fallback } from '@vben/common-ui';
</script>
<template>
<Fallback :show-back="false" status="500" />
<Fallback status="500" />
</template>

View File

@ -33,7 +33,7 @@
"eslint-plugin-command": "^0.2.3"
},
"devDependencies": {
"@eslint/js": "^9.4.0",
"@eslint/js": "^9.5.0",
"@types/eslint": "^8.56.10",
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
@ -41,18 +41,18 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-i": "^2.29.1",
"eslint-plugin-jsdoc": "^48.2.11",
"eslint-plugin-jsdoc": "^48.2.12",
"eslint-plugin-jsonc": "^2.16.0",
"eslint-plugin-n": "^17.9.0",
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-perfectionist": "^2.11.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-regexp": "^2.6.0",
"eslint-plugin-unicorn": "^53.0.0",
"eslint-plugin-unicorn": "^54.0.0",
"eslint-plugin-unused-imports": "^4.0.0",
"eslint-plugin-vitest": "^0.5.4",
"eslint-plugin-vue": "^9.26.0",
"globals": "^15.4.0",
"globals": "^15.5.0",
"jsonc-eslint-parser": "^2.4.0",
"vue-eslint-parser": "^9.4.3"
}

View File

@ -20,6 +20,6 @@
],
"dependencies": {
"@vben/types": "workspace:*",
"vite": "6.0.0-alpha.17"
"vite": "5.3.0"
}
}

View File

@ -48,7 +48,7 @@
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.77.5",
"unplugin-turbo-console": "^1.8.6",
"vite": "6.0.0-alpha.17",
"vite": "5.3.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-dts": "^3.9.1",
"vite-plugin-html": "^3.2.2",

View File

@ -65,10 +65,10 @@
"jsdom": "^24.1.0",
"rimraf": "^5.0.7",
"taze": "^0.13.8",
"turbo": "^2.0.3",
"turbo": "^2.0.4",
"typescript": "^5.4.5",
"unbuild": "^2.0.0",
"vite": "6.0.0-alpha.17",
"vite": "5.3.0",
"vitest": "^2.0.0-beta.3",
"vue-tsc": "^2.0.21"
},

View File

@ -45,7 +45,12 @@ const defaultPreferences: Preferences = {
split: true,
styleType: 'rounded',
},
shortcutKeys: { enable: true },
shortcutKeys: {
enable: true,
globalLogout: true,
globalPreferences: true,
globalSearch: true,
},
sidebar: {
collapsed: false,
collapsedShowTitle: true,

View File

@ -112,6 +112,12 @@ interface SidebarPreferences {
interface ShortcutKeyPreferences {
/** 是否启用快捷键-全局 */
enable: boolean;
/** 是否启用全局注销快捷键 */
globalLogout: boolean;
/** 是否启用全局偏好设置快捷键 */
globalPreferences: boolean;
/** 是否启用全局搜索快捷键 */
globalSearch: boolean;
}
interface TabbarPreferences {

View File

@ -16,6 +16,8 @@ function usePreferences() {
const appPreferences = computed(() => preferences.app);
const shortcutKeysPreferences = computed(() => preferences.shortcutKeys);
/**
* @zh_CN
* @param preferences -
@ -107,11 +109,38 @@ function usePreferences() {
return appPreferences.value.authPageLayout === 'panel-center';
});
/**
* @zh_CN
*/
const globalSearchShortcutKey = computed(() => {
const { enable, globalSearch } = shortcutKeysPreferences.value;
return enable && globalSearch;
});
/**
* @zh_CN
*/
const globalLogoutShortcutKey = computed(() => {
const { enable, globalLogout } = shortcutKeysPreferences.value;
return enable && globalLogout;
});
/**
* @zh_CN
*/
const globalPreferencesShortcutKey = computed(() => {
const { enable, globalPreferences } = shortcutKeysPreferences.value;
return enable && globalPreferences;
});
return {
authPanelCenter,
authPanelLeft,
authPanelRight,
diffPreference,
globalLogoutShortcutKey,
globalPreferencesShortcutKey,
globalSearchShortcutKey,
isDark,
isFullContent,
isHeaderNav,

View File

@ -40,7 +40,7 @@
},
"dependencies": {
"@ctrl/tinycolor": "4.1.0",
"@vue/shared": "^3.4.27",
"@vue/shared": "^3.4.29",
"dayjs": "^1.11.11",
"defu": "^6.1.4",
"nprogress": "^0.2.0"

View File

@ -13,16 +13,10 @@ interface FallbackProps {
* @default pageNotFoundSvg
*/
image?: string;
/**
* @zh_CN
* @default true
*/
showBack?: boolean;
/**
* @zh_CN
*/
status?: '403' | '404' | '500' | 'offline';
status?: '403' | '404' | '500' | 'hello' | 'offline';
/**
* @zh_CN
*/

View File

@ -5,7 +5,7 @@ import { computed, defineAsyncComponent } from 'vue';
import { useRouter } from 'vue-router';
import { $t } from '@vben/locales';
import { IcRoundArrowBackIosNew } from '@vben-core/iconify';
import { IcRoundArrowBackIosNew, IcRoundRefresh } from '@vben-core/iconify';
import { VbenButton } from '@vben-core/shadcn-ui';
interface Props extends FallbackProps {}
@ -19,13 +19,14 @@ const props = withDefaults(defineProps<Props>(), {
homePath: '/',
image: '',
showBack: true,
status: '404',
status: 'hello',
title: '',
});
const Icon403 = defineAsyncComponent(() => import('./icons/icon-403.vue'));
const Icon404 = defineAsyncComponent(() => import('./icons/icon-404.vue'));
const Icon500 = defineAsyncComponent(() => import('./icons/icon-500.vue'));
const IconHello = defineAsyncComponent(() => import('./icons/icon-hello.vue'));
const IconOffline = defineAsyncComponent(
() => import('./icons/icon-offline.vue'),
);
@ -39,6 +40,9 @@ const titleText = computed(() => {
case '403': {
return $t('fallback.forbidden');
}
case '404': {
return $t('fallback.page-not-found');
}
case '500': {
return $t('fallback.internal-error');
}
@ -46,7 +50,7 @@ const titleText = computed(() => {
return $t('fallback.offline-error');
}
default: {
return $t('fallback.page-not-found');
return '';
}
}
});
@ -59,6 +63,9 @@ const descText = computed(() => {
case '403': {
return $t('fallback.forbidden-desc');
}
case '404': {
return $t('fallback.page-not-found-desc');
}
case '500': {
return $t('fallback.internal-error-desc');
}
@ -66,7 +73,7 @@ const descText = computed(() => {
return $t('fallback.offline-error-desc');
}
default: {
return $t('fallback.page-not-found-desc');
return '';
}
}
});
@ -76,47 +83,76 @@ const fallbackIcon = computed(() => {
case '403': {
return Icon403;
}
case '404': {
return Icon404;
}
case '500': {
return Icon500;
}
case 'offline': {
return IconOffline;
}
case 'hello': {
return IconHello;
}
default: {
return Icon404;
return null;
}
}
});
const showBack = computed(() => {
return ['403', '404'].includes(props.status);
});
const showRefresh = computed(() => {
return ['500', 'offline'].includes(props.status);
});
const { push } = useRouter();
//
function back() {
push(props.homePath);
}
function refresh() {
location.reload();
}
</script>
<template>
<div class="flex size-full flex-col items-center justify-center duration-300">
<img v-if="image" :src="image" class="md:1/3 w-1/2 lg:w-1/4" />
<component :is="fallbackIcon" v-else class="md:1/3 h-1/3 w-1/2 lg:w-1/4" />
<component
:is="fallbackIcon"
v-else-if="fallbackIcon"
class="md:1/3 h-1/3 w-1/2 lg:w-1/4"
/>
<div class="flex-col-center">
<slot v-if="$slots.title" name="title"></slot>
<p
v-if="titleText"
v-else-if="titleText"
class="text-foreground mt-12 text-3xl md:text-4xl lg:text-5xl"
>
{{ titleText }}
</p>
<slot v-if="$slots.describe" name="describe"></slot>
<p
v-if="descText"
v-else-if="descText"
class="text-muted-foreground md:text-md my-6 lg:text-lg"
>
{{ descText }}
</p>
<VbenButton v-if="showBack" size="lg" @click="back">
<slot v-if="$slots.action" name="action"></slot>
<VbenButton v-else-if="showBack" size="lg" @click="back">
<IcRoundArrowBackIosNew class="mr-2" />
{{ $t('common.back-to-home') }}
</VbenButton>
<VbenButton v-else-if="showRefresh" size="lg" @click="refresh">
<IcRoundRefresh class="mr-2" />
{{ $t('common.refresh') }}
</VbenButton>
</div>
</div>
</template>

View File

@ -0,0 +1,262 @@
<template>
<svg
data-name="Layer 1"
height="424.8366"
viewBox="0 0 979.32677 424.8366"
width="979.32677"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<path
d="M993.71816,412.83936H419.142a9.19888,9.19888,0,0,0,0,18.39776H435.417V651.3026a9.19888,9.19888,0,0,0,18.39776,0l.1398-220.06548h461.1557l42.52,220.06548a9.19887,9.19887,0,1,0,18.39775,0l2.67633-220.06548h15.01383a9.19888,9.19888,0,0,0,0-18.39776Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M518.73716,371.85047v38.9547H421.141a19.48915,19.48915,0,1,1-1.35523-38.95474q.67739-.02358,1.35523,0Z"
fill="#f2f2f2"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M521.13449,410.50552a1.49881,1.49881,0,0,1-1.49822,1.49822H419.40273a20.52615,20.52615,0,0,1,0-41.05229H519.63627a1.49827,1.49827,0,1,1,0,2.99653H419.40273a17.52964,17.52964,0,0,0,0,35.05924H519.63627A1.49883,1.49883,0,0,1,521.13449,410.50552Z"
fill="hsl(var(--color-primary))"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M518.73716,380.84H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M518.73716,388.03169H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M518.73716,395.22332H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M518.73716,402.41487H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M500.33941,330.80932v38.95474H402.74324a19.48915,19.48915,0,0,1-1.35522-38.95474q.67737-.02358,1.35522,0Z"
fill="#f2f2f2"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M502.73673,369.46442a1.49885,1.49885,0,0,1-1.49822,1.49826H401.005a20.52614,20.52614,0,0,1,0-41.05229H501.23851a1.49826,1.49826,0,1,1,0,2.99652H401.005a17.52964,17.52964,0,0,0,0,35.05928H501.23851A1.49884,1.49884,0,0,1,502.73673,369.46442Z"
fill="#3f3d56"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M500.33941,339.79886H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M500.33941,346.99054H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M500.33941,354.18217H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M500.33941,361.37376H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M613.87355,550.68347V516.71838a5.661,5.661,0,0,0-5.66085-5.66085H479.4284a5.661,5.661,0,0,0-5.66084,5.66085v33.96509Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<rect
fill="#ccc"
height="43.87158"
width="140.10602"
x="363.43092"
y="325.83868"
/>
<path
d="M473.76756,620.02887V653.994a5.661,5.661,0,0,0,5.66084,5.66084H608.2127a5.661,5.661,0,0,0,5.66085-5.66084V620.02887Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<circle cx="432.77633" cy="294.70402" fill="#fff" r="4.24564" />
<circle cx="432.77633" cy="351.3125" fill="#fff" r="4.24564" />
<circle cx="433.00385" cy="406.72228" fill="#fff" r="4.24564" />
<path
d="M597.989,472.33053v38.9547H500.39287a19.48916,19.48916,0,0,1-1.35647-38.9547q.678-.02358,1.35647,0Z"
fill="#f2f2f2"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M600.38637,510.98558a1.49881,1.49881,0,0,1-1.49822,1.49822H498.65461a20.52615,20.52615,0,0,1-.0247-41.05229H598.88815a1.49827,1.49827,0,1,1,0,2.99653H498.65461a17.52963,17.52963,0,0,0,0,35.05923H598.88815A1.49885,1.49885,0,0,1,600.38637,510.98558Z"
fill="#3f3d56"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M597.989,481.32H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M597.989,488.51175H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M597.989,495.70338H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M597.989,502.89493H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M483.36747,317.81415H438.90162a2.74745,2.74745,0,0,0-1.21689.28306l-11.22288,5.61835a2.0452,2.0452,0,0,0,0,3.76443l11.22288,5.61835a2.74718,2.74718,0,0,0,1.21689.28306h44.46585a2.33381,2.33381,0,0,0,2.4628-2.16532v-11.2367A2.3338,2.3338,0,0,0,483.36747,317.81415Z"
fill="#3f3d56"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M485.83027,319.97947v11.2367a2.33383,2.33383,0,0,1-2.4628,2.16532h-8.8589V317.81415h8.8589A2.33383,2.33383,0,0,1,485.83027,319.97947Z"
fill="hsl(var(--color-primary))"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M216.78083,537.99332a35.33951,35.33951,0,0,0,34.12552-6.01134c11.95262-10.03214,15.70013-26.56,18.74934-41.864q4.50949-22.63308,9.019-45.26617l-18.88217,13.00153c-13.57891,9.34993-27.46375,18.99939-36.86572,32.54233S209.42082,522.42587,216.975,537.08"
fill="#e6e6e6"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M218.39489,592.79741c-1.91113-13.92071-3.87625-28.0202-2.53572-42.09016,1.19057-12.4956,5.00277-24.70032,12.764-34.70734a57.73582,57.73582,0,0,1,14.81307-13.42309c1.48131-.935,2.84468,1.41257,1.36983,2.34348a54.88844,54.88844,0,0,0-21.71125,26.19626c-4.72684,12.02273-5.48591,25.12848-4.67135,37.90006.4926,7.72345,1.53656,15.39627,2.58859,23.05926a1.40615,1.40615,0,0,1-.94781,1.66928,1.3653,1.3653,0,0,1-1.6693-.94781Z"
fill="#f2f2f2"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M236.80246,568.16434a26.01425,26.01425,0,0,0,22.6665,11.69871c11.47417-.54466,21.04-8.55293,29.651-16.15584l25.46969-22.48783-16.85671-.80672c-12.12234-.58011-24.55745-1.12124-36.10356,2.617s-22.19457,12.73508-24.30583,24.68624"
fill="#e6e6e6"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M212.99392,600.79976c9.19853-16.27621,19.86805-34.36538,38.93262-40.14695A43.445,43.445,0,0,1,268.3022,558.962c1.73863.14991,1.30448,2.82994-.431,2.6803a40.36111,40.36111,0,0,0-26.133,6.91386c-7.36852,5.01554-13.10573,11.98848-17.96161,19.383-2.97439,4.52936-5.63867,9.25082-8.30346,13.966-.85161,1.50687-3.34078.41915-2.47922-1.10534Z"
fill="#f2f2f2"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M198.25523,617.93168a19.69836,19.69836,0,0,1,12.0709-16.49847v-9.40956h15.782v9.70608a19.68812,19.68812,0,0,1,11.41362,16.202l3.711,43.13835H194.54417Z"
fill="#f2f2f2"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M734.973,411.955l-4.69488-1.97685-3.22067-23.53551h-42.889l-3.491,23.43936-4.20031,2.10013a.99744.99744,0,0,0,.44611,1.88955h57.66283A.99739.99739,0,0,0,734.973,411.955Z"
fill="#e6e6e6"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M811.1898,389.574H600.50692a4.174,4.174,0,0,1-4.16467-4.174V355.69092H815.35446V385.4A4.17408,4.17408,0,0,1,811.1898,389.574Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M815.57469,369.73213H596.15V242.61337a5.0375,5.0375,0,0,1,5.03186-5.03167h209.361a5.03755,5.03755,0,0,1,5.03191,5.03167Z"
fill="#3f3d56"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M802.46932,360.50584h-193.214a3.88344,3.88344,0,0,1-3.87919-3.87908V250.68707a3.88365,3.88365,0,0,1,3.87919-3.87932h193.214a3.88366,3.88366,0,0,1,3.8792,3.87932V356.62676A3.88345,3.88345,0,0,1,802.46932,360.50584Z"
fill="#fff"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M751.57964,397.88662a11.6159,11.6159,0,0,1,17.666,2.27241l26.13446-4.64642,6.69716,15.19317-36.99908,6.04328a11.67883,11.67883,0,0,1-13.49855-18.86244Z"
fill="#ffb6b6"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M775.77611,417.286l27.24571-.33963,3.44882-.04668,55.43253-.69843s15.05312-14.3609,28.16068-29.1465l-1.83719-13.28833A54.29159,54.29159,0,0,0,870.023,340.1519C851.24988,352.696,840.363,377.52559,840.363,377.52559l-34.37018,8.22071-3.43848.82227-21.35608,5.10326Z"
fill="hsl(var(--color-primary))"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M915.25011,498.96167H864.39249c0,2.17915-55.59414,3.94772-55.59414,3.94772a20.30858,20.30858,0,0,0-3.33166,3.15818,19.59694,19.59694,0,0,0-4.58,12.63271v3.15818a19.74588,19.74588,0,0,0,19.73861,19.73861h94.62478a19.75579,19.75579,0,0,0,19.73862-19.73861v-3.15818A19.76607,19.76607,0,0,0,915.25011,498.96167Z"
fill="#e4e4e4"
transform="translate(-110.33661 -237.5817)"
/>
<rect
fill="#e4e4e4"
height="118.48951"
width="20.52816"
x="747.4019"
y="303.23122"
/>
<path
d="M799.31222,658.58132c0,2.218,31.10721.858,69.47992.858s69.47991,1.36012,69.47991-.858-31.1072-19.807-69.47991-19.807S799.31222,656.36323,799.31222,658.58132Z"
fill="#e4e4e4"
transform="translate(-110.33661 -237.5817)"
/>
<polygon
fill="#ffb6b6"
points="675.186 407.461 659.908 407.46 652.64 348.531 675.188 348.532 675.186 407.461"
/>
<path
d="M789.41863,659.852l-49.2623-.00183v-.62309a19.17528,19.17528,0,0,1,19.17426-19.17395h.00122l30.08773.00122Z"
fill="#2f2e41"
transform="translate(-110.33661 -237.5817)"
/>
<polygon
fill="#ffb6b6"
points="630.031 407.461 614.753 407.46 607.485 348.531 630.033 348.532 630.031 407.461"
/>
<path
d="M744.2636,659.852l-49.2623-.00183v-.62309a19.1753,19.1753,0,0,1,19.17426-19.17395h.00122l30.08773.00122Z"
fill="#2f2e41"
transform="translate(-110.33661 -237.5817)"
/>
<circle cx="766.88656" cy="41.63615" fill="#ffb6b6" r="26.56401" />
<path
d="M920.21655,461.22417s8.91308,47.1307-24.99958,53.13247-82.86639,10.21993-82.86639,10.21993L790.36706,627.14324l-29.53443-2.63675s3.928-123.46737,13.5876-133.127,70.71212-38.58282,70.71212-38.58282Z"
fill="#2f2e41"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M853.98286,441.47135,839.151,456.35062s-107.0941,17.25-111.22553,41.9852c-6.23747,37.34427-13.60493,118.552-13.60493,118.552l32.1988-2.41491,12.62647-92.31123,51.5182-11.71874L869.27729,478.5Z"
fill="#2f2e41"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M902.78526,263.36115c-2.6223-4.94751-5.95413-14.80785-11.24679-16.63657a42.07731,42.07731,0,0,0-9.05841-1.92972l-8.99618,3.46009,4.89616-3.808q-1.42988-.08519-2.85817-.13928l-6.0699,2.33453,3.10542-2.41532c-5.65883-.05808-11.5.53031-15.88468,3.9752-3.73817,2.93677-7.44169,14.06185-8.04057,18.77753a35.9171,35.9171,0,0,0,.6603,13.53055l1.53716,1.46166a18.85936,18.85936,0,0,0,1.206-3.83883,18.18056,18.18056,0,0,1,8.70263-11.80641l.08368-.0472c2.5782-1.451,5.7065-1.3841,8.66308-1.27769l14.04158.50527c3.37829.12158,7.01608.33533,9.64978,2.45443a15.888,15.888,0,0,1,3.85826,5.58929c1.30868,2.6414,3.8661,12.60418,3.8661,12.60418s1.44689-1.88062,2.1404-.48092a48.39766,48.39766,0,0,0,2.01437-11.23347A22.00877,22.00877,0,0,0,902.78526,263.36115Z"
fill="#2f2e41"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M995.69426,290.88349A11.61582,11.61582,0,0,0,985.181,305.26136l-21.3614,15.75722,6.40951,15.31674,29.8539-22.67594a11.67883,11.67883,0,0,0-4.38876-22.77589Z"
fill="#ffb6b6"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M992.25627,323.052l-53.551,59.4744s-25.60913-8.19816-45.41466-17.08624l-8.8977-27.32787a54.34329,54.34329,0,0,1-2.60112-19.66442c27.45606-7.306,59.391,19.87863,59.391,19.87863l40.08517-31.39877Z"
fill="hsl(var(--color-primary))"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M867.301,465.6169c-9.554-3.30029-19.43312-6.71277-30.08912-7.99385l-.45773-.05533.12632-.443c11.03073-38.7308,8.27761-63.50657,2.87195-100.72306a37.59072,37.59072,0,0,1,21.5483-39.50121l.06542-.02958,30.43436-1.93391.06935-.00423,22.13437,6.50989a15.18313,15.18313,0,0,1,10.86724,14.83111c-.23987,12.23937.26868,25.9043.80711,40.37114,1.20787,32.45569,2.45686,66.01647-4.63045,87.79166l-.03718.11412-.09462.07416a36.09883,36.09883,0,0,1-23.08086,8.10758C887.90057,472.73235,877.76186,469.23034,867.301,465.6169Z"
fill="hsl(var(--color-primary))"
transform="translate(-110.33661 -237.5817)"
/>
<path
d="M1088.24817,662.4183H111.75183a1.41521,1.41521,0,1,1,0-2.83042h976.49634a1.41521,1.41521,0,1,1,0,2.83042Z"
fill="#ccc"
transform="translate(-110.33661 -237.5817)"
/>
</svg>
</template>

View File

@ -23,10 +23,10 @@ function handleClick(value: string) {
<template>
<SwitchItem v-model="transitionProgress">
{{ $t('preference.page-progress') }}
{{ $t('preferences.page-progress') }}
</SwitchItem>
<SwitchItem v-model="transitionEnable">
{{ $t('preference.page-transition') }}
{{ $t('preferences.page-transition') }}
</SwitchItem>
<div
v-if="transitionEnable"

View File

@ -13,7 +13,6 @@ defineOptions({
const appLocale = defineModel<string>('appLocale');
const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
const shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');
const localeItems: SelectListItem[] = SUPPORT_LANGUAGES.map((item) => ({
label: item.text,
@ -23,12 +22,9 @@ const localeItems: SelectListItem[] = SUPPORT_LANGUAGES.map((item) => ({
<template>
<SelectItem v-model="appLocale" :items="localeItems">
{{ $t('preference.language') }}
{{ $t('preferences.language') }}
</SelectItem>
<SwitchItem v-model="appDynamicTitle">
{{ $t('preference.dynamic-title') }}
</SwitchItem>
<SwitchItem v-model="shortcutKeysEnable">
{{ $t('preference.shortcut-key') }}
{{ $t('preferences.dynamic-title') }}
</SwitchItem>
</template>

View File

@ -9,6 +9,7 @@ export { default as Layout } from './layout/layout.vue';
export { default as Navigation } from './layout/navigation.vue';
export { default as Sidebar } from './layout/sidebar.vue';
export { default as Tabbar } from './layout/tabbar.vue';
export { default as GlobalShortcutKeys } from './shortcut-keys/global.vue';
export { default as SwitchItem } from './switch-item.vue';
export { default as ThemeColor } from './theme/color.vue';
export { default as ColorMode } from './theme/color-mode.vue';

View File

@ -21,8 +21,8 @@ const breadcrumbShowHome = defineModel<boolean>('breadcrumbShowHome');
const breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');
const typeItems: SelectListItem[] = [
{ label: $t('preference.normal'), value: 'normal' },
{ label: $t('preference.breadcrumb-background'), value: 'background' },
{ label: $t('preferences.normal'), value: 'normal' },
{ label: $t('preferences.breadcrumb-background'), value: 'background' },
];
const disableItem = computed(() => {
@ -32,22 +32,22 @@ const disableItem = computed(() => {
<template>
<SwitchItem v-model="breadcrumbEnable" :disabled="disabled">
{{ $t('preference.breadcrumb-enable') }}
{{ $t('preferences.breadcrumb-enable') }}
</SwitchItem>
<SwitchItem v-model="breadcrumbHideOnlyOne" :disabled="disableItem">
{{ $t('preference.breadcrumb-hide-only-one') }}
{{ $t('preferences.breadcrumb-hide-only-one') }}
</SwitchItem>
<SwitchItem v-model="breadcrumbShowHome" :disabled="disableItem">
{{ $t('preference.breadcrumb-home') }}
{{ $t('preferences.breadcrumb-home') }}
</SwitchItem>
<SwitchItem v-model="breadcrumbShowIcon" :disabled="disableItem">
{{ $t('preference.breadcrumb-icon') }}
{{ $t('preferences.breadcrumb-icon') }}
</SwitchItem>
<ToggleItem
v-model="breadcrumbStyleType"
:disabled="disableItem"
:items="typeItems"
>
{{ $t('preference.breadcrumb-style') }}
{{ $t('preferences.breadcrumb-style') }}
</ToggleItem>
</template>

View File

@ -18,7 +18,7 @@ const components: Record<string, Component> = {
const PRESET = computed(() => [
{
name: $t('preference.wide'),
name: $t('preferences.wide'),
type: 'wide',
},
{

View File

@ -13,9 +13,9 @@ const footerFixed = defineModel<boolean>('footerFixed');
<template>
<SwitchItem v-model="footerEnable">
{{ $t('preference.footer-visible') }}
{{ $t('preferences.footer-visible') }}
</SwitchItem>
<SwitchItem v-model="footerFixed" :disabled="!footerEnable">
{{ $t('preference.footer-fixed') }}
{{ $t('preferences.footer-fixed') }}
</SwitchItem>
</template>

View File

@ -17,19 +17,19 @@ const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
const localeItems: SelectListItem[] = [
{
label: $t('preference.header-mode-static'),
label: $t('preferences.header-mode-static'),
value: 'static',
},
{
label: $t('preference.header-mode-fixed'),
label: $t('preferences.header-mode-fixed'),
value: 'fixed',
},
{
label: $t('preference.header-mode-auto'),
label: $t('preferences.header-mode-auto'),
value: 'auto',
},
{
label: $t('preference.header-mode-auto-scroll'),
label: $t('preferences.header-mode-auto-scroll'),
value: 'auto-scroll',
},
];
@ -37,13 +37,13 @@ const localeItems: SelectListItem[] = [
<template>
<SwitchItem v-model="headerEnable" :disabled="disabled">
{{ $t('preference.header-visible') }}
{{ $t('preferences.header-visible') }}
</SwitchItem>
<SelectItem
v-model="headerMode"
:disabled="!headerEnable"
:items="localeItems"
>
{{ $t('preference.mode') }}
{{ $t('preferences.mode') }}
</SelectItem>
</template>

View File

@ -13,9 +13,9 @@ const logoVisible = defineModel<boolean>('logoVisible');
<template>
<SwitchItem v-model="tabsVisible">
{{ $t('preference.tabs-visible') }}
{{ $t('preferences.tabs-visible') }}
</SwitchItem>
<SwitchItem v-model="logoVisible">
{{ $t('preference.logo-visible') }}
{{ $t('preferences.logo-visible') }}
</SwitchItem>
</template>

View File

@ -37,28 +37,28 @@ const components: Record<LayoutType, Component> = {
const PRESET = computed((): PresetItem[] => [
{
name: $t('preference.vertical'),
tip: $t('preference.vertical-tip'),
name: $t('preferences.vertical'),
tip: $t('preferences.vertical-tip'),
type: 'sidebar-nav',
},
{
name: $t('preference.two-column'),
tip: $t('preference.two-column-tip'),
name: $t('preferences.two-column'),
tip: $t('preferences.two-column-tip'),
type: 'sidebar-mixed-nav',
},
{
name: $t('preference.horizontal'),
tip: $t('preference.vertical-tip'),
name: $t('preferences.horizontal'),
tip: $t('preferences.vertical-tip'),
type: 'header-nav',
},
{
name: $t('preference.mixed-menu'),
tip: $t('preference.mixed-menu-tip'),
name: $t('preferences.mixed-menu'),
tip: $t('preferences.mixed-menu-tip'),
type: 'mixed-nav',
},
{
name: $t('preference.full-content'),
tip: $t('preference.full-content-tip'),
name: $t('preferences.full-content'),
tip: $t('preferences.full-content-tip'),
type: 'full-content',
},
]);

View File

@ -17,8 +17,8 @@ const navigationSplit = defineModel<boolean>('navigationSplit');
const navigationAccordion = defineModel<boolean>('navigationAccordion');
const stylesItems: SelectListItem[] = [
{ label: $t('preference.rounded'), value: 'rounded' },
{ label: $t('preference.plain'), value: 'plain' },
{ label: $t('preferences.rounded'), value: 'rounded' },
{ label: $t('preferences.plain'), value: 'plain' },
];
</script>
@ -28,18 +28,18 @@ const stylesItems: SelectListItem[] = [
:disabled="disabled"
:items="stylesItems"
>
{{ $t('preference.navigation-style') }}
{{ $t('preferences.navigation-style') }}
</ToggleItem>
<SwitchItem
v-model="navigationSplit"
:disabled="disabledNavigationSplit || disabled"
>
{{ $t('preference.navigation-split') }}
{{ $t('preferences.navigation-split') }}
<template #tip>
{{ $t('preference.navigation-split-tip') }}
{{ $t('preferences.navigation-split-tip') }}
</template>
</SwitchItem>
<SwitchItem v-model="navigationAccordion" :disabled="disabled">
{{ $t('preference.navigation-accordion') }}
{{ $t('preferences.navigation-accordion') }}
</SwitchItem>
</template>

View File

@ -18,15 +18,15 @@ const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
<template>
<SwitchItem v-model="sidebarEnable" :disabled="disabled">
{{ $t('preference.side-visible') }}
{{ $t('preferences.side-visible') }}
</SwitchItem>
<SwitchItem v-model="sidebarCollapsed" :disabled="!sidebarEnable || disabled">
{{ $t('preference.collapse') }}
{{ $t('preferences.collapse') }}
</SwitchItem>
<SwitchItem
v-model="sidebarCollapsedShowTitle"
:disabled="!sidebarEnable || disabled"
>
{{ $t('preference.collapse-show-title') }}
{{ $t('preferences.collapse-show-title') }}
</SwitchItem>
</template>

View File

@ -15,12 +15,12 @@ const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');
<template>
<SwitchItem v-model="tabbarEnable" :disabled="disabled">
{{ $t('preference.tabs-visible') }}
{{ $t('preferences.tabs-visible') }}
</SwitchItem>
<SwitchItem v-model="tabbarShowIcon" :disabled="!tabbarEnable">
{{ $t('preference.tabs-icon') }}
{{ $t('preferences.tabs-icon') }}
</SwitchItem>
<!-- <SwitchItem v-model="sideCollapseShowTitle" :disabled="!tabsVisible">
{{ $t('preference.collapse-show-title') }}
{{ $t('preferences.collapse-show-title') }}
</SwitchItem> -->
</template>

View File

@ -0,0 +1,42 @@
<script setup lang="ts">
import { computed } from 'vue';
import { $t } from '@vben/locales';
import { isWindowsOs } from '@vben-core/toolkit';
import SwitchItem from '../switch-item.vue';
defineOptions({
name: 'PreferenceGeneralConfig',
});
const shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');
const shortcutKeysGlobalSearch = defineModel<boolean>(
'shortcutKeysGlobalSearch',
);
const shortcutKeysLogout = defineModel<boolean>('shortcutKeysLogout');
const shortcutKeysPreferences = defineModel<boolean>('shortcutKeysPreferences');
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
</script>
<template>
<SwitchItem v-model="shortcutKeysEnable">
{{ $t('preferences.shortcut-keys.title') }}
</SwitchItem>
<SwitchItem v-if="shortcutKeysEnable" v-model="shortcutKeysGlobalSearch">
{{ $t('preferences.shortcut-keys.search') }}
<template #shortcut>
{{ isWindowsOs() ? 'Ctrl' : '⌘' }}
<kbd> K </kbd>
</template>
</SwitchItem>
<SwitchItem v-if="shortcutKeysEnable" v-model="shortcutKeysLogout">
{{ $t('preferences.shortcut-keys.logout') }}
<template #shortcut> {{ altView }} Q </template>
</SwitchItem>
<SwitchItem v-if="shortcutKeysEnable" v-model="shortcutKeysPreferences">
{{ $t('preferences.shortcut-keys.preferences') }}
<template #shortcut> {{ altView }} , </template>
</SwitchItem>
</template>

View File

@ -39,6 +39,9 @@ function handleClick() {
<slot name="tip"></slot>
</VbenTooltip>
</span>
<span v-if="$slots.shortcut" class="ml-auto mr-2 text-xs opacity-60">
<slot name="shortcut"></slot>
</span>
<Switch v-model:checked="checked" @click.stop />
</div>
</template>

View File

@ -18,9 +18,9 @@ const appColorGrayMode = defineModel<boolean>('appColorGrayMode', {
<template>
<SwitchItem v-model="appColorWeakMode">
{{ $t('preference.weak-mode') }}
{{ $t('preferences.weak-mode') }}
</SwitchItem>
<SwitchItem v-model="appColorGrayMode">
{{ $t('preference.gray-mode') }}
{{ $t('preferences.gray-mode') }}
</SwitchItem>
</template>

View File

@ -39,13 +39,13 @@ function activeClass(theme: string): string[] {
function nameView(name: string) {
switch (name) {
case 'light': {
return $t('preference.light');
return $t('preferences.light');
}
case 'dark': {
return $t('preference.dark');
return $t('preferences.dark');
}
case 'auto': {
return $t('preference.follow-system');
return $t('preferences.follow-system');
}
}
}
@ -75,7 +75,7 @@ function nameView(name: string) {
:disabled="modelValue !== 'light'"
class="mt-6"
>
{{ $t('preference.dark-menu') }}
{{ $t('preferences.dark-menu') }}
</SwitchItem>
</div>
</template>

View File

@ -32,6 +32,11 @@ import Preferences from './preferences.vue';
:navigation-split="preferences.navigation.split"
:navigation-style-type="preferences.navigation.styleType"
:shortcut-keys-enable="preferences.shortcutKeys.enable"
:shortcut-keys-global-logout="preferences.shortcutKeys.globalLogout"
:shortcut-keys-global-preferences="
preferences.shortcutKeys.globalPreferences
"
:shortcut-keys-global-search="preferences.shortcutKeys.globalSearch"
:sidebar-collapsed="preferences.sidebar.collapsed"
:sidebar-collapsed-show-title="preferences.sidebar.collapsedShowTitle"
:sidebar-enable="preferences.sidebar.enable"
@ -103,6 +108,15 @@ import Preferences from './preferences.vue';
@update:shortcut-keys-enable="
(val) => updatePreferences({ shortcutKeys: { enable: val } })
"
@update:shortcut-keys-global-logout="
(val) => updatePreferences({ shortcutKeys: { globalLogout: val } })
"
@update:shortcut-keys-global-preferences="
(val) => updatePreferences({ shortcutKeys: { globalPreferences: val } })
"
@update:shortcut-keys-global-search="
(val) => updatePreferences({ shortcutKeys: { globalSearch: val } })
"
@update:sidebar-collapsed="
(val) => updatePreferences({ sidebar: { collapsed: val } })
"

View File

@ -39,6 +39,7 @@ import {
Content,
Footer,
General,
GlobalShortcutKeys,
Header,
Layout,
Navigation,
@ -101,6 +102,15 @@ const footerEnable = defineModel<boolean>('footerEnable');
const footerFixed = defineModel<boolean>('footerFixed');
const shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');
const shortcutKeysGlobalSearch = defineModel<boolean>(
'shortcutKeysGlobalSearch',
);
const shortcutKeysGlobalLogout = defineModel<boolean>(
'shortcutKeysGlobalLogout',
);
const shortcutKeysGlobalPreferences = defineModel<boolean>(
'shortcutKeysGlobalPreferences',
);
const {
diffPreference,
@ -116,21 +126,21 @@ const { copy } = useClipboard();
const tabs = computed((): SegmentedItem[] => {
return [
{
label: $t('preference.appearance'),
label: $t('preferences.appearance'),
value: 'appearance',
},
{
label: $t('preference.layout'),
label: $t('preferences.layout'),
value: 'layout',
},
{
label: $t('preference.general'),
label: $t('preferences.general'),
value: 'general',
},
// {
// label: $t('preference.shortcut-key'),
// value: 'shortcutKey',
// },
{
label: $t('preferences.shortcut-keys.title'),
value: 'shortcutKey',
},
];
});
@ -148,7 +158,7 @@ const { openPreferences } = useOpenPreferences();
async function handleCopy() {
await copy(JSON.stringify(diffPreference.value, null, 2));
toast($t('preference.copy-success'));
toast($t('preferences.copy-success'));
}
function handleReset() {
@ -156,7 +166,7 @@ function handleReset() {
return;
}
resetPreferences();
toast($t('preference.reset-success'));
toast($t('preferences.reset-success'));
}
</script>
@ -164,8 +174,8 @@ function handleReset() {
<div class="z-100 fixed right-0 top-1/3">
<VbenSheet
v-model:open="openPreferences"
:description="$t('preference.preferences-subtitle')"
:title="$t('preference.preferences')"
:description="$t('preferences.preferences-subtitle')"
:title="$t('preferences.preferences')"
>
<template #trigger>
<Trigger />
@ -173,7 +183,7 @@ function handleReset() {
<template #extra>
<VbenIconButton
:disabled="!diffPreference"
:tooltip="$t('preference.reset-tip')"
:tooltip="$t('preferences.reset-tip')"
class="relative"
>
<span
@ -187,19 +197,19 @@ function handleReset() {
<div class="p-5 pt-4">
<VbenSegmented :tabs="tabs" default-value="appearance">
<template #appearance>
<Block :title="$t('preference.theme')">
<Block :title="$t('preferences.theme')">
<Theme
v-model="appThemeMode"
v-model:app-semi-dark-menu="appSemiDarkMenu"
/>
</Block>
<Block :title="$t('preference.theme-color')">
<Block :title="$t('preferences.theme-color')">
<ThemeColor
v-model="themeColorPrimary"
:color-primary-presets="colorPrimaryPresets"
/>
</Block>
<Block :title="$t('preference.other')">
<Block :title="$t('preferences.other')">
<ColorMode
v-model:app-color-gray-mode="appColorGrayMode"
v-model:app-color-weak-mode="appColorWeakMode"
@ -207,14 +217,14 @@ function handleReset() {
</Block>
</template>
<template #layout>
<Block :title="$t('preference.layout')">
<Block :title="$t('preferences.layout')">
<Layout v-model="appLayout" />
</Block>
<Block :title="$t('preference.content')">
<Block :title="$t('preferences.content')">
<Content v-model="appContentCompact" />
</Block>
<Block :title="$t('preference.sidebar')">
<Block :title="$t('preferences.sidebar')">
<Sidebar
v-model:sidebar-collapsed="sidebarCollapsed"
v-model:sidebar-collapsed-show-title="sidebarCollapsedShowTitle"
@ -223,7 +233,7 @@ function handleReset() {
/>
</Block>
<Block :title="$t('preference.header')">
<Block :title="$t('preferences.header')">
<Header
v-model:headerEnable="headerEnable"
v-model:headerMode="headerMode"
@ -231,7 +241,7 @@ function handleReset() {
/>
</Block>
<Block :title="$t('preference.navigation-menu')">
<Block :title="$t('preferences.navigation-menu')">
<Navigation
v-model:navigation-accordion="navigationAccordion"
v-model:navigation-split="navigationSplit"
@ -241,7 +251,7 @@ function handleReset() {
/>
</Block>
<Block :title="$t('preference.breadcrumb')">
<Block :title="$t('preferences.breadcrumb')">
<Breadcrumb
v-model:breadcrumb-enable="breadcrumbEnable"
v-model:breadcrumb-hide-only-one="breadcrumbHideOnlyOne"
@ -254,13 +264,13 @@ function handleReset() {
/>
</Block>
<Block :title="$t('preference.tabs')">
<Block :title="$t('preferences.tabs')">
<Tabbar
v-model:tabbar-enable="tabbarEnable"
v-model:tabbar-show-icon="tabbarShowIcon"
/>
</Block>
<Block :title="$t('preference.footer')">
<Block :title="$t('preferences.footer')">
<Footer
v-model:footer-enable="footerEnable"
v-model:footer-fixed="footerFixed"
@ -268,15 +278,14 @@ function handleReset() {
</Block>
</template>
<template #general>
<Block :title="$t('preference.general')">
<Block :title="$t('preferences.general')">
<General
v-model:app-dynamic-title="appDynamicTitle"
v-model:app-locale="appLocale"
v-model:shortcut-keys-enable="shortcutKeysEnable"
/>
</Block>
<Block :title="$t('preference.animation')">
<Block :title="$t('preferences.animation')">
<Animation
v-model:transition-enable="transitionEnable"
v-model:transition-name="transitionName"
@ -284,23 +293,18 @@ function handleReset() {
/>
</Block>
</template>
<!-- <template #shortcutKey>
<Block :title="$t('preference.general')">
<General
v-model:locale="locale"
v-model:dynamic-title="dynamicTitle"
v-model:shortcut-keys="shortcutKeys"
<template #shortcutKey>
<Block :title="$t('preferences.shortcut-keys.global')">
<GlobalShortcutKeys
v-model:shortcut-keys-enable="shortcutKeysEnable"
v-model:shortcut-keys-global-search="shortcutKeysGlobalSearch"
v-model:shortcut-keys-logout="shortcutKeysGlobalLogout"
v-model:shortcut-keys-preferences="
shortcutKeysGlobalPreferences
"
/>
</Block>
<Block :title="$t('preference.animation')">
<Animation
v-model:page-progress="pageProgress"
v-model:page-transition="pageTransition"
v-model:transition-enable="transitionEnable"
/>
</Block>
</template> -->
</template>
</VbenSegmented>
</div>
@ -313,7 +317,7 @@ function handleReset() {
@click="handleCopy"
>
<IcRoundFolderCopy class="mr-2 size-3" />
{{ $t('preference.copy') }}
{{ $t('preferences.copy') }}
</VbenButton>
</template>
</VbenSheet>

View File

@ -11,7 +11,7 @@ defineOptions({
<template>
<VbenButton
:title="$t('preference.preferences')"
:title="$t('preferences.preferences')"
class="bg-primary flex-col-center h-9 w-9 cursor-pointer rounded-l-md rounded-r-none border-none"
>
<IconSetting class="text-lg" />

View File

@ -39,17 +39,17 @@ const PRESETS = [
{
icon: IcRoundWbSunny,
name: 'light',
title: $t('preference.light'),
title: $t('preferences.light'),
},
{
icon: MdiMoonAndStars,
name: 'dark',
title: $t('preference.dark'),
title: $t('preferences.dark'),
},
{
icon: IcRoundMotionPhotosAuto,
name: 'auto',
title: $t('preference.follow-system'),
title: $t('preferences.follow-system'),
},
];
</script>

View File

@ -6,7 +6,7 @@ import { computed, ref } from 'vue';
import { $t } from '@vben/locales';
import { IcRoundLogout, IcRoundSettingsSuggest } from '@vben-core/iconify';
import { preferences } from '@vben-core/preferences';
import { preferences, usePreferences } from '@vben-core/preferences';
import {
Badge,
DropdownMenu,
@ -72,14 +72,24 @@ const emit = defineEmits<{ logout: [] }>();
const openPopover = ref(false);
const openDialog = ref(false);
const { globalLogoutShortcutKey, globalPreferencesShortcutKey } =
usePreferences();
const { handleOpenPreference } = useOpenPreferences();
const altView = computed(() => (isWindowsOs() ? 'Alt' : '⌥'));
const shortcutKeys = computed(() => {
const enableLogoutShortcutKey = computed(() => {
return props.enableShortcutKey && globalLogoutShortcutKey.value;
});
const enableShortcutKey = computed(() => {
return props.enableShortcutKey && preferences.shortcutKeys.enable;
});
const enablePreferencesShortcutKey = computed(() => {
return props.enableShortcutKey && globalPreferencesShortcutKey.value;
});
function handleLogout() {
// emit
openDialog.value = true;
@ -91,16 +101,16 @@ function handleSubmitLogout() {
openDialog.value = false;
}
if (shortcutKeys.value) {
if (enableShortcutKey.value) {
const keys = useMagicKeys();
whenever(keys['Alt+KeyQ'], () => {
if (shortcutKeys.value) {
if (enableLogoutShortcutKey.value) {
handleLogout();
}
});
whenever(keys['Alt+Comma'], () => {
if (shortcutKeys.value) {
if (enablePreferencesShortcutKey.value) {
handleOpenPreference();
}
});
@ -161,13 +171,12 @@ if (shortcutKeys.value) {
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
v-if="preferences.shortcutKeys.enable"
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
@click="handleOpenPreference"
>
<IcRoundSettingsSuggest class="mr-2 size-5" />
{{ $t('preference.preferences') }}
<DropdownMenuShortcut v-if="shortcutKeys">
{{ $t('preferences.preferences') }}
<DropdownMenuShortcut v-if="enablePreferencesShortcutKey">
{{ altView }} ,
</DropdownMenuShortcut>
</DropdownMenuItem>
@ -178,7 +187,7 @@ if (shortcutKeys.value) {
>
<IcRoundLogout class="mr-2 size-5" />
{{ $t('common.logout') }}
<DropdownMenuShortcut v-if="shortcutKeys">
<DropdownMenuShortcut v-if="enableLogoutShortcutKey">
{{ altView }} Q
</DropdownMenuShortcut>
</DropdownMenuItem>

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { GlobalSearch, LanguageToggle, ThemeToggle } from '@vben/common-ui';
import { preferences } from '@vben-core/preferences';
import { usePreferences } from '@vben-core/preferences';
import { VbenFullScreen } from '@vben-core/shadcn-ui';
import { useAccessStore } from '@vben-core/stores';
@ -20,6 +20,7 @@ withDefaults(defineProps<Props>(), {
});
const accessStore = useAccessStore();
const { globalSearchShortcutKey } = usePreferences();
</script>
<template>
@ -31,7 +32,7 @@ const accessStore = useAccessStore();
</div>
<div class="flex h-full min-w-0 flex-shrink-0 items-center">
<GlobalSearch
:enable-shortcut-key="preferences.shortcutKeys.enable"
:enable-shortcut-key="globalSearchShortcutKey"
:menus="accessStore.getAccessMenus"
class="mr-4"
/>

View File

@ -8,6 +8,7 @@ common:
confirm: Comfirm
search: Search
not-data: No data
refresh: Refresh
layout:
center: Align Center
@ -114,11 +115,10 @@ page:
fallback:
page: Exception Page
preference:
preferences:
preferences: Preferences
preferences-subtitle: Customize Preferences & Preview in Real Time
theme: Theme
shortcut-key: Shortcut Key
appearance: Appearance
theme-color: Theme Color
layout: Layout
@ -187,3 +187,9 @@ preference:
footer-visible: Display Footer
logo-visible: Display Logo
reset-tip: The data has changed, click to reset
shortcut-keys:
title: Shortcut Keys
global: Global
search: Global Search
logout: Logout
preferences: Preferences

View File

@ -7,6 +7,7 @@ common:
cancel: 取消
confirm: 确认
not-data: 暂无数据
refresh: 刷新
layout:
center: 居中
@ -113,10 +114,9 @@ page:
fallback:
page: 异常页面
preference:
preferences:
preferences: 偏好设置
preferences-subtitle: 自定义偏好设置 & 实时预览
shortcut-key: 快捷键
theme: 主题
appearance: 外观
theme-color: 主题色
@ -186,3 +186,9 @@ preference:
footer-fixed: 固定在底部
logo-visible: 显示 Logo
reset-tip: 数据有变化,点击可进行重置
shortcut-keys:
title: 快捷键
global: 全局
search: 全局搜索
logout: 退出登录
preferences: 偏好设置

File diff suppressed because it is too large Load Diff