diff --git a/apps/web-antd/src/layouts/basic.vue b/apps/web-antd/src/layouts/basic.vue
index 1d4cccef..2a574b3f 100644
--- a/apps/web-antd/src/layouts/basic.vue
+++ b/apps/web-antd/src/layouts/basic.vue
@@ -4,7 +4,7 @@ import { useRouter } from 'vue-router';
import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
import { LOGIN_PATH } from '@vben/constants';
-import { IcRoundCreditScore, MdiDriveDocument, MdiGithub } from '@vben/icons';
+import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons';
import {
BasicLayout,
LockScreen,
@@ -61,7 +61,7 @@ const menus = computed(() => [
target: '_blank',
});
},
- icon: MdiDriveDocument,
+ icon: BookOpenText,
text: $t('widgets.document'),
},
{
@@ -79,7 +79,7 @@ const menus = computed(() => [
target: '_blank',
});
},
- icon: IcRoundCreditScore,
+ icon: CircleHelp,
text: $t('widgets.qa'),
},
]);
diff --git a/apps/web-antd/src/router/routes/modules/dashboard.ts b/apps/web-antd/src/router/routes/modules/dashboard.ts
index ecfcbe0c..4f7585e2 100644
--- a/apps/web-antd/src/router/routes/modules/dashboard.ts
+++ b/apps/web-antd/src/router/routes/modules/dashboard.ts
@@ -7,6 +7,7 @@ const routes: RouteRecordRaw[] = [
{
component: BasicLayout,
meta: {
+ icon: 'lucide:layout-dashboard',
order: -1,
title: $t('page.dashboard.title'),
},
@@ -20,6 +21,7 @@ const routes: RouteRecordRaw[] = [
component: () => import('#/views/dashboard/analytics/index.vue'),
meta: {
affixTab: true,
+ icon: 'lucide:area-chart',
title: $t('page.dashboard.analytics'),
},
},
diff --git a/apps/web-antd/src/router/routes/modules/vben.ts b/apps/web-antd/src/router/routes/modules/vben.ts
index 21d0c58e..802824cc 100644
--- a/apps/web-antd/src/router/routes/modules/vben.ts
+++ b/apps/web-antd/src/router/routes/modules/vben.ts
@@ -24,7 +24,7 @@ const routes: RouteRecordRaw[] = [
component: () => import('#/views/_core/vben/about/index.vue'),
meta: {
badgeType: 'dot',
- icon: 'mdi:creative-commons',
+ icon: 'lucide:copyright',
title: $t('page.vben.about'),
},
},
@@ -33,7 +33,7 @@ const routes: RouteRecordRaw[] = [
path: 'document',
component: IFrameView,
meta: {
- icon: 'mdi:flame-circle',
+ icon: 'lucide:book-open-text',
iframeSrc: 'https://doc.vvbin.cn/',
keepAlive: true,
title: $t('page.vben.document'),
diff --git a/package.json b/package.json
index a99019c1..b685ec8a 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
"@vue/test-utils": "^2.4.6",
"cross-env": "^7.0.3",
"cspell": "^8.11.0",
- "husky": "^9.0.11",
+ "husky": "^9.1.0",
"is-ci": "^3.0.1",
"jsdom": "^24.1.0",
"rimraf": "^6.0.1",
diff --git a/packages/@core/forward/preferences/src/preferences.ts b/packages/@core/forward/preferences/src/preferences.ts
index ae8cb118..f2f4d668 100644
--- a/packages/@core/forward/preferences/src/preferences.ts
+++ b/packages/@core/forward/preferences/src/preferences.ts
@@ -4,12 +4,7 @@ import type { Preferences } from './types';
import { markRaw, reactive, readonly, watch } from 'vue';
-import {
- StorageManager,
- generatorColorVariables,
- merge,
- updateCSSVariables,
-} from '@vben-core/toolkit';
+import { StorageManager, merge } from '@vben-core/toolkit';
import {
breakpointsTailwind,
@@ -18,7 +13,7 @@ import {
} from '@vueuse/core';
import { defaultPreferences } from './config';
-import { BUILT_IN_THEME_PRESETS } from './constants';
+import { updateCSSVariables } from './update-css-variables';
const STORAGE_KEY = 'preferences';
const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;
@@ -48,11 +43,10 @@ class PreferenceManager {
});
constructor() {
this.cache = new StorageManager();
- // this.flattenedState = reactive(flattenObject(this.state));
this.savePreferences = useDebounceFn(
(preference: Preferences) => this._savePreferences(preference),
- 100,
+ 200,
);
}
@@ -76,7 +70,7 @@ class PreferenceManager {
const themeUpdates = updates.theme || {};
const appUpdates = updates.app || {};
if (themeUpdates && Object.keys(themeUpdates).length > 0) {
- this.updateTheme(this.state);
+ updateCSSVariables(this.state);
}
if (
@@ -130,7 +124,7 @@ class PreferenceManager {
this.updatePreferences({
theme: { mode: isDark ? 'dark' : 'light' },
});
- this.updateTheme(this.state);
+ updateCSSVariables(this.state);
});
}
@@ -153,101 +147,6 @@ class PreferenceManager {
}
}
- /**
- * 更新 CSS 变量
- * @param preference - 当前偏好设置对象,它的颜色值将被转换成 HSL 格式并设置为 CSS 变量。
- */
- private updateMainColors(preference: Preferences) {
- if (!preference.theme) {
- return;
- }
- const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =
- preference.theme;
-
- const colorVariables = generatorColorVariables([
- { color: colorPrimary, name: 'primary' },
- { alias: 'warning', color: colorWarning, name: 'yellow' },
- { alias: 'success', color: colorSuccess, name: 'green' },
- { alias: 'destructive', color: colorDestructive, name: 'red' },
- ]);
-
- if (colorPrimary) {
- document.documentElement.style.setProperty(
- '--primary',
- colorVariables['--primary-500'],
- );
- }
-
- if (colorVariables['--green-500']) {
- colorVariables['--success'] = colorVariables['--green-500'];
- }
- if (colorVariables['--yellow-500']) {
- colorVariables['--warning'] = colorVariables['--yellow-500'];
- }
- if (colorVariables['--red-500']) {
- colorVariables['--destructive'] = colorVariables['--red-500'];
- }
- updateCSSVariables(colorVariables);
- }
-
- /**
- * 更新主题
- * @param preferences - 当前偏好设置对象,它的主题值将被用来设置文档的主题。
- */
- private updateTheme(preferences: Preferences) {
- // 当修改到颜色变量时,更新 css 变量
- const root = document.documentElement;
- if (!root) {
- return;
- }
-
- const theme = preferences?.theme ?? {};
-
- const { builtinType, colorPrimary, mode, radius } = theme;
-
- if (Reflect.has(theme, 'mode')) {
- const dark = isDarkTheme(mode);
- root.classList.toggle('dark', dark);
- }
-
- if (Reflect.has(theme, 'builtinType')) {
- const rootTheme = root.dataset.theme;
- if (rootTheme !== builtinType) {
- root.dataset.theme = builtinType;
- }
- }
-
- const currentBuiltType = BUILT_IN_THEME_PRESETS.find(
- (item) => item.type === builtinType,
- );
-
- let builtinTypeColorPrimary: string | undefined = '';
-
- if (currentBuiltType) {
- const isDark = isDarkTheme(this.state.theme.mode);
-
- const color = isDark
- ? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor
- : currentBuiltType.primaryColor;
- builtinTypeColorPrimary = color || currentBuiltType.color;
- }
-
- if (
- builtinTypeColorPrimary ||
- Reflect.has(theme, 'colorPrimary') ||
- Reflect.has(theme, 'colorDestructive') ||
- Reflect.has(theme, 'colorSuccess') ||
- Reflect.has(theme, 'colorWarning')
- ) {
- preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
- this.updateMainColors(preferences);
- }
-
- if (Reflect.has(theme, 'radius')) {
- document.documentElement.style.setProperty('--radius', `${radius}rem`);
- }
- }
-
clearCache() {
[STORAGE_KEY, STORAGE_KEY_LOCALE, STORAGE_KEY_THEME].forEach((key) => {
this.cache?.removeItem(key);
diff --git a/packages/@core/forward/preferences/src/update-css-variables.ts b/packages/@core/forward/preferences/src/update-css-variables.ts
new file mode 100644
index 00000000..9f1823f8
--- /dev/null
+++ b/packages/@core/forward/preferences/src/update-css-variables.ts
@@ -0,0 +1,118 @@
+import type { Preferences } from './types';
+
+import {
+ updateCSSVariables as executeUpdateCSSVariables,
+ generatorColorVariables,
+} from '@vben-core/toolkit';
+
+import { BUILT_IN_THEME_PRESETS } from './constants';
+
+/**
+ * 更新主题的 CSS 变量以及其他 CSS 变量
+ * @param preferences - 当前偏好设置对象,它的主题值将被用来设置文档的主题。
+ */
+function updateCSSVariables(preferences: Preferences) {
+ // 当修改到颜色变量时,更新 css 变量
+ const root = document.documentElement;
+ if (!root) {
+ return;
+ }
+
+ const theme = preferences?.theme ?? {};
+
+ const { builtinType, colorPrimary, mode, radius } = theme;
+
+ // html 设置 dark 类
+ if (Reflect.has(theme, 'mode')) {
+ const dark = isDarkTheme(mode);
+ root.classList.toggle('dark', dark);
+ }
+
+ // html 设置 data-theme=[builtinType]
+ if (Reflect.has(theme, 'builtinType')) {
+ const rootTheme = root.dataset.theme;
+ if (rootTheme !== builtinType) {
+ root.dataset.theme = builtinType;
+ }
+ }
+
+ // 获取当前的内置主题
+ const currentBuiltType = BUILT_IN_THEME_PRESETS.find(
+ (item) => item.type === builtinType,
+ );
+
+ let builtinTypeColorPrimary: string | undefined = '';
+
+ if (currentBuiltType) {
+ const isDark = isDarkTheme(preferences.theme.mode);
+ // 设置不同主题的主要颜色
+ const color = isDark
+ ? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor
+ : currentBuiltType.primaryColor;
+ builtinTypeColorPrimary = color || currentBuiltType.color;
+ }
+
+ // 如果内置主题颜色和自定义颜色都不存在,则不更新主题颜色
+ if (
+ builtinTypeColorPrimary ||
+ Reflect.has(theme, 'colorPrimary') ||
+ Reflect.has(theme, 'colorDestructive') ||
+ Reflect.has(theme, 'colorSuccess') ||
+ Reflect.has(theme, 'colorWarning')
+ ) {
+ preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
+ updateMainColorVariables(preferences);
+ }
+
+ // 更新圆角
+ if (Reflect.has(theme, 'radius')) {
+ document.documentElement.style.setProperty('--radius', `${radius}rem`);
+ }
+}
+
+/**
+ * 更新主要的 CSS 变量
+ * @param preference - 当前偏好设置对象,它的颜色值将被转换成 HSL 格式并设置为 CSS 变量。
+ */
+function updateMainColorVariables(preference: Preferences) {
+ if (!preference.theme) {
+ return;
+ }
+ const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =
+ preference.theme;
+
+ const colorVariables = generatorColorVariables([
+ { color: colorPrimary, name: 'primary' },
+ { alias: 'warning', color: colorWarning, name: 'yellow' },
+ { alias: 'success', color: colorSuccess, name: 'green' },
+ { alias: 'destructive', color: colorDestructive, name: 'red' },
+ ]);
+
+ if (colorPrimary) {
+ document.documentElement.style.setProperty(
+ '--primary',
+ colorVariables['--primary-500'],
+ );
+ }
+
+ if (colorVariables['--green-500']) {
+ colorVariables['--success'] = colorVariables['--green-500'];
+ }
+ if (colorVariables['--yellow-500']) {
+ colorVariables['--warning'] = colorVariables['--yellow-500'];
+ }
+ if (colorVariables['--red-500']) {
+ colorVariables['--destructive'] = colorVariables['--red-500'];
+ }
+ executeUpdateCSSVariables(colorVariables);
+}
+
+function isDarkTheme(theme: string) {
+ let dark = theme === 'dark';
+ if (theme === 'auto') {
+ dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+ }
+ return dark;
+}
+
+export { updateCSSVariables };
diff --git a/packages/@core/forward/preferences/src/use-preferences.ts b/packages/@core/forward/preferences/src/use-preferences.ts
index e6a20903..e3b6e9cc 100644
--- a/packages/@core/forward/preferences/src/use-preferences.ts
+++ b/packages/@core/forward/preferences/src/use-preferences.ts
@@ -27,6 +27,10 @@ function usePreferences() {
return isDarkTheme(preferences.theme.mode);
});
+ const isMobile = computed(() => {
+ return appPreferences.value.isMobile;
+ });
+
const theme = computed(() => {
return isDark.value ? 'dark' : 'light';
});
@@ -35,7 +39,7 @@ function usePreferences() {
* @zh_CN 布局方式
*/
const layout = computed(() =>
- appPreferences.value.isMobile ? 'sidebar-nav' : appPreferences.value.layout,
+ isMobile.value ? 'sidebar-nav' : appPreferences.value.layout,
);
/**
@@ -109,6 +113,16 @@ function usePreferences() {
return appPreferences.value.authPageLayout === 'panel-center';
});
+ /**
+ * @zh_CN 内容是否已经最大化
+ * 排除 full-content模式
+ */
+ const contentIsMaximize = computed(() => {
+ const headerIsHidden = preferences.header.hidden;
+ const sidebarIsHidden = preferences.sidebar.hidden;
+ return headerIsHidden && sidebarIsHidden && !isFullContent.value;
+ });
+
/**
* @zh_CN 是否启用全局搜索快捷键
*/
@@ -138,17 +152,6 @@ function usePreferences() {
return enable && globalPreferences;
});
- /**
- * @zh_CN 内容是否已经最大化
- * 排除 full-content模式
- */
- const contentIsMaximize = computed(() => {
- const headerIsHidden = preferences.header.hidden;
- const sidebarIsHidden = preferences.sidebar.hidden;
-
- return headerIsHidden && sidebarIsHidden && !isFullContent.value;
- });
-
return {
authPanelCenter,
authPanelLeft,
@@ -163,6 +166,7 @@ function usePreferences() {
isFullContent,
isHeaderNav,
isMixedNav,
+ isMobile,
isSideMixedNav,
isSideMode,
isSideNav,
diff --git a/packages/@core/shared/design/src/design-tokens/dark/index.css b/packages/@core/shared/design/src/design-tokens/dark/index.css
index 97ff7a98..79f84b4e 100644
--- a/packages/@core/shared/design/src/design-tokens/dark/index.css
+++ b/packages/@core/shared/design/src/design-tokens/dark/index.css
@@ -15,7 +15,7 @@
--card-foreground: 210 40% 98%;
/* Background color for popovers such as