提交 3d1681ee 作者: vben

feat: theme color switch

上级 85729f0f
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
### ✨ Features ### ✨ Features
- `ApiSelect`新增 `numberToString`属性,用于将 value 为`number`的值全部转化为`string` - `ApiSelect`新增 `numberToString`属性,用于将 value 为`number`的值全部转化为`string`
- 新增主题色切换
### ⚡ Performance Improvements ### ⚡ Performance Improvements
......
/**
* less global variable
*/
const primaryColor = '#0084f4';
// const primaryColor = '#018ffb';
// const primaryColor = '#0065cc';
//{
const modifyVars = {
'primary-color': primaryColor, // Global dominant color
'success-color': '#55D187', // Success color
'error-color': '#ED6F6F', // False color
'warning-color': '#EFBD47', // Warning color
'link-color': primaryColor, // Link color
'disabled-color': 'rgba(0, 0, 0, 0.25)', // Failure color
'heading-color': 'rgba(0, 0, 0, 0.85)', // Title color
'text-color': 'rgba(0, 0, 0, 0.85)', // Main text color
'text-color-secondary ': 'rgba(0, 0, 0, 0.45)', // Subtext color
'font-size-base': '14px', // Main font size
'box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)', // Floating shadow
'border-color-base': '#d9d9d9', // Border color,
'border-radius-base': '2px', // Component/float fillet
};
//}
export { modifyVars, primaryColor };
import { generate } from '@ant-design/colors';
export const primaryColor = '#0084f4';
export const themeMode = 'light';
export type ThemeMode = 'dark' | 'light';
type Fn = (...arg: any) => any;
export interface GenerateColorsParams {
mixLighten: Fn;
mixDarken: Fn;
tinycolor: any;
color?: string;
}
export function generateAntColors(color: string, mode: ThemeMode) {
return generate(color, {
theme: mode == 'dark' ? 'dark' : 'default',
});
}
export function getThemeColors(color?: string, theme?: ThemeMode) {
const tc = color || primaryColor;
const tm = theme || themeMode;
const colors = generateAntColors(tc, tm);
const primary = colors[5];
const modeColors = generateAntColors(primary, tm === 'dark' ? 'light' : 'dark');
return [...colors, ...modeColors];
}
export function generateColors({
color = primaryColor,
mixLighten,
mixDarken,
tinycolor,
}: GenerateColorsParams) {
const lightens = new Array(19).fill(0).map((t, i) => {
return mixLighten(color, i / 5);
});
const darkens = new Array(19).fill(0).map((t, i) => {
return mixDarken(color, i / 5);
});
const alphaColors = new Array(19).fill(0).map((t, i) => {
return tinycolor(color)
.setAlpha(i / 20)
.toRgbString();
});
const tinycolorLightens = new Array(19)
.fill(0)
.map((t, i) => {
return tinycolor(color)
.lighten(i * 5)
.toHexString();
})
.filter((item) => item !== '#ffffff');
const tinycolorDarkens = new Array(19)
.fill(0)
.map((t, i) => {
return tinycolor(color)
.darken(i * 5)
.toHexString();
})
.filter((item) => item !== '#000000');
return [...lightens, ...darkens, ...alphaColors, ...tinycolorDarkens, ...tinycolorLightens];
}
/**
* less global variable
*/
export function generateModifyVars() {
const palettes = generateAntColors(primaryColor, themeMode);
const primary = palettes[5];
const primaryColorObj: Record<string, string> = {};
for (let index = 0; index < 10; index++) {
primaryColorObj[`primary-${index}`] = palettes[index];
}
return {
'primary-color': primary,
...primaryColorObj,
'info-color': primary,
'alert-info-bg-color': palettes[0],
'alert-info-border-color': palettes[2],
'processing-color': primary,
'success-color': '#55D187', // Success color
'error-color': '#ED6F6F', // False color
'warning-color': '#EFBD47', // Warning color
'disabled-color': 'rgba(0, 0, 0, 0.25)', // Failure color
'heading-color': 'rgba(0, 0, 0, 0.85)', // Title color
'text-color': 'rgba(0, 0, 0, 0.85)', // Main text color
'text-color-secondary ': 'rgba(0, 0, 0, 0.45)', // Subtext color
'font-size-base': '14px', // Main font size
'box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)', // Floating shadow
'border-color-base': '#d9d9d9', // Border color,
'border-radius-base': '2px', // Component/float fillet
'link-color': primary, // Link color
};
}
...@@ -9,8 +9,9 @@ import { configHtmlPlugin } from './html'; ...@@ -9,8 +9,9 @@ import { configHtmlPlugin } from './html';
import { configPwaConfig } from './pwa'; import { configPwaConfig } from './pwa';
import { configMockPlugin } from './mock'; import { configMockPlugin } from './mock';
import { configGzipPlugin } from './gzip'; import { configGzipPlugin } from './gzip';
import { configStyleImportConfig } from './styleImport'; import { configStyleImportPlugin } from './styleImport';
import { configVisualizerConfig } from './visualizer'; import { configVisualizerConfig } from './visualizer';
import { configThemePlugin } from './theme';
// gen vite plugins // gen vite plugins
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
...@@ -29,7 +30,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { ...@@ -29,7 +30,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
vitePlugins.push(PurgeIcons()); vitePlugins.push(PurgeIcons());
// vite-plugin-style-import // vite-plugin-style-import
vitePlugins.push(configStyleImportConfig()); vitePlugins.push(configStyleImportPlugin());
// rollup-plugin-gzip // rollup-plugin-gzip
vitePlugins.push(configGzipPlugin(isBuild)); vitePlugins.push(configGzipPlugin(isBuild));
...@@ -37,5 +38,8 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { ...@@ -37,5 +38,8 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
// rollup-plugin-visualizer // rollup-plugin-visualizer
vitePlugins.push(configVisualizerConfig()); vitePlugins.push(configVisualizerConfig());
//vite-plugin-theme
vitePlugins.push(configThemePlugin());
return vitePlugins; return vitePlugins;
} }
import styleImport from 'vite-plugin-style-import'; import styleImport from 'vite-plugin-style-import';
export function configStyleImportConfig() { export function configStyleImportPlugin() {
const pwaPlugin = styleImport({ const pwaPlugin = styleImport({
libs: [ libs: [
{ {
......
import { viteThemePlugin, mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme';
import { getThemeColors, generateColors } from '../../config/themeConfig';
export function configThemePlugin() {
const colors = generateColors({
mixDarken,
mixLighten,
tinycolor,
});
const plugin = viteThemePlugin({
colorVariables: [...getThemeColors(), ...colors],
});
return plugin;
}
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
}, },
"dependencies": { "dependencies": {
"@iconify/iconify": "^2.0.0-rc.6", "@iconify/iconify": "^2.0.0-rc.6",
"@vueuse/core": "^4.0.11", "@vueuse/core": "^4.0.12",
"ant-design-vue": "2.0.0-rc.9", "ant-design-vue": "2.0.0-rc.9",
"apexcharts": "^3.23.1", "apexcharts": "^3.24.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"crypto-es": "^1.2.6", "crypto-es": "^1.2.6",
"echarts": "^4.9.0", "echarts": "^4.9.0",
...@@ -33,12 +33,12 @@ ...@@ -33,12 +33,12 @@
"path-to-regexp": "^6.2.0", "path-to-regexp": "^6.2.0",
"qrcode": "^1.4.4", "qrcode": "^1.4.4",
"sortablejs": "^1.13.0", "sortablejs": "^1.13.0",
"vditor": "^3.7.7", "vditor": "^3.8.0",
"vue": "^3.0.5", "vue": "^3.0.5",
"vue-i18n": "9.0.0-rc.2", "vue-i18n": "9.0.0-rc.2",
"vue-router": "^4.0.3", "vue-router": "^4.0.3",
"vue-types": "^3.0.1", "vue-types": "^3.0.2",
"vuex": "^4.0.0-rc.2", "vuex": "^4.0.0",
"vuex-module-decorators": "^1.0.1", "vuex-module-decorators": "^1.0.1",
"xlsx": "^0.16.9", "xlsx": "^0.16.9",
"zxcvbn": "^4.4.2" "zxcvbn": "^4.4.2"
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^11.0.0", "@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0", "@commitlint/config-conventional": "^11.0.0",
"@iconify/json": "^1.1.294", "@iconify/json": "^1.1.296",
"@ls-lint/ls-lint": "^1.9.2", "@ls-lint/ls-lint": "^1.9.2",
"@purge-icons/generated": "^0.6.0", "@purge-icons/generated": "^0.6.0",
"@types/echarts": "^4.9.3", "@types/echarts": "^4.9.3",
...@@ -61,10 +61,10 @@ ...@@ -61,10 +61,10 @@
"@types/sortablejs": "^1.10.6", "@types/sortablejs": "^1.10.6",
"@types/yargs": "^16.0.0", "@types/yargs": "^16.0.0",
"@types/zxcvbn": "^4.4.0", "@types/zxcvbn": "^4.4.0",
"@typescript-eslint/eslint-plugin": "^4.14.1", "@typescript-eslint/eslint-plugin": "^4.14.2",
"@typescript-eslint/parser": "^4.14.1", "@typescript-eslint/parser": "^4.14.2",
"@vitejs/plugin-legacy": "^1.2.2", "@vitejs/plugin-legacy": "^1.2.3",
"@vitejs/plugin-vue": "^1.1.3", "@vitejs/plugin-vue": "^1.1.4",
"@vitejs/plugin-vue-jsx": "^1.0.2", "@vitejs/plugin-vue-jsx": "^1.0.2",
"@vue/compiler-sfc": "^3.0.5", "@vue/compiler-sfc": "^3.0.5",
"@vuedx/typecheck": "^0.6.3", "@vuedx/typecheck": "^0.6.3",
...@@ -74,14 +74,14 @@ ...@@ -74,14 +74,14 @@
"conventional-changelog-cli": "^2.1.1", "conventional-changelog-cli": "^2.1.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"eslint": "^7.18.0", "eslint": "^7.19.0",
"eslint-config-prettier": "^7.2.0", "eslint-config-prettier": "^7.2.0",
"eslint-plugin-prettier": "^3.3.1", "eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.5.0", "eslint-plugin-vue": "^7.5.0",
"esno": "^0.4.0", "esno": "^0.4.3",
"fs-extra": "^9.1.0", "fs-extra": "^9.1.0",
"husky": "^4.3.8", "husky": "^4.3.8",
"less": "^4.1.0", "less": "^4.1.1",
"lint-staged": "^10.5.3", "lint-staged": "^10.5.3",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
...@@ -93,12 +93,13 @@ ...@@ -93,12 +93,13 @@
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
"ts-node": "^9.1.1", "ts-node": "^9.1.1",
"typescript": "^4.1.3", "typescript": "^4.1.3",
"vite": "2.0.0-beta.59", "vite": "2.0.0-beta.62",
"vite-plugin-html": "^2.0.0-rc.3", "vite-plugin-html": "^2.0.0-rc.3",
"vite-plugin-mock": "^2.0.0-rc.2", "vite-plugin-mock": "^2.0.0-rc.2",
"vite-plugin-purge-icons": "^0.6.0", "vite-plugin-purge-icons": "^0.6.0",
"vite-plugin-pwa": "^0.4.1", "vite-plugin-pwa": "^0.4.2",
"vite-plugin-style-import": "^0.5.5", "vite-plugin-style-import": "^0.5.5",
"vite-plugin-theme": "0.3.2",
"vue-eslint-parser": "^7.4.1", "vue-eslint-parser": "^7.4.1",
"yargs": "^16.2.0" "yargs": "^16.2.0"
}, },
...@@ -118,6 +119,6 @@ ...@@ -118,6 +119,6 @@
} }
}, },
"engines": { "engines": {
"node": ">=10.16.1" "node": "^12 || ^14"
} }
} }
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
&:hover, &:hover,
&:focus { &:focus {
color: @white; color: @white !important;
background-color: @button-primary-hover-color; background-color: @button-primary-hover-color;
} }
......
...@@ -34,6 +34,8 @@ const getShowFooter = computed(() => unref(getRootSetting).showFooter); ...@@ -34,6 +34,8 @@ const getShowFooter = computed(() => unref(getRootSetting).showFooter);
const getShowBreadCrumb = computed(() => unref(getRootSetting).showBreadCrumb); const getShowBreadCrumb = computed(() => unref(getRootSetting).showBreadCrumb);
const getThemeColor = computed(() => unref(getRootSetting).themeColor);
const getShowBreadCrumbIcon = computed(() => unref(getRootSetting).showBreadCrumbIcon); const getShowBreadCrumbIcon = computed(() => unref(getRootSetting).showBreadCrumbIcon);
const getFullContent = computed(() => unref(getRootSetting).fullContent); const getFullContent = computed(() => unref(getRootSetting).fullContent);
...@@ -74,5 +76,6 @@ export function useRootSetting() { ...@@ -74,5 +76,6 @@ export function useRootSetting() {
getShowFooter, getShowFooter,
getContentMode, getContentMode,
getLockTime, getLockTime,
getThemeColor,
}; };
} }
...@@ -31,7 +31,11 @@ import { ...@@ -31,7 +31,11 @@ import {
mixSidebarTriggerOptions, mixSidebarTriggerOptions,
} from './enum'; } from './enum';
import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST } from '/@/settings/designSetting'; import {
HEADER_PRESET_BG_COLOR_LIST,
SIDE_BAR_BG_COLOR_LIST,
APP_PRESET_COLOR_LIST,
} from '/@/settings/designSetting';
const { t } = useI18n(); const { t } = useI18n();
...@@ -48,6 +52,7 @@ export default defineComponent({ ...@@ -48,6 +52,7 @@ export default defineComponent({
getColorWeak, getColorWeak,
getGrayMode, getGrayMode,
getLockTime, getLockTime,
getThemeColor,
} = useRootSetting(); } = useRootSetting();
const { const {
...@@ -129,6 +134,16 @@ export default defineComponent({ ...@@ -129,6 +134,16 @@ export default defineComponent({
); );
} }
function renderMainTheme() {
return (
<ThemePicker
colorList={APP_PRESET_COLOR_LIST}
def={unref(getThemeColor)}
event={HandlerEnum.CHANGE_THEME_COLOR}
/>
);
}
/** /**
* @description: * @description:
*/ */
...@@ -391,6 +406,8 @@ export default defineComponent({ ...@@ -391,6 +406,8 @@ export default defineComponent({
> >
<Divider>{() => t('layout.setting.navMode')}</Divider> <Divider>{() => t('layout.setting.navMode')}</Divider>
{renderSidebar()} {renderSidebar()}
<Divider>{() => t('layout.setting.sysTheme')}</Divider>
{renderMainTheme()}
<Divider>{() => t('layout.setting.headerTheme')}</Divider> <Divider>{() => t('layout.setting.headerTheme')}</Divider>
{renderHeaderTheme()} {renderHeaderTheme()}
<Divider>{() => t('layout.setting.sidebarTheme')}</Divider> <Divider>{() => t('layout.setting.sidebarTheme')}</Divider>
......
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
import { useMessage } from '/@/hooks/web/useMessage'; import { useMessage } from '/@/hooks/web/useMessage';
import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
import { useRootSetting } from '/@/hooks/setting/useRootSetting'; import { useRootSetting } from '/@/hooks/setting/useRootSetting';
import { updateColorWeak, updateGrayMode } from '/@/logics/theme'; import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
export default defineComponent({ export default defineComponent({
name: 'SettingFooter', name: 'SettingFooter',
......
...@@ -13,6 +13,7 @@ const { t } = useI18n(); ...@@ -13,6 +13,7 @@ const { t } = useI18n();
export enum HandlerEnum { export enum HandlerEnum {
CHANGE_LAYOUT, CHANGE_LAYOUT,
CHANGE_THEME_COLOR,
// menu // menu
MENU_HAS_DRAG, MENU_HAS_DRAG,
MENU_ACCORDION, MENU_ACCORDION,
......
import { HandlerEnum } from './enum'; import { HandlerEnum } from './enum';
import { import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
updateColorWeak, import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
updateGrayMode, import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
updateHeaderBgColor,
updateSidebarBgColor,
} from '/@/logics/theme';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { ProjectConfig } from '/@/types/config'; import { ProjectConfig } from '/@/types/config';
import { changeTheme } from '/@/logics/theme';
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
export function baseHandler(event: HandlerEnum, value: any) { export function baseHandler(event: HandlerEnum, value: any) {
const config = handler(event, value); const config = handler(event, value);
...@@ -14,6 +14,7 @@ export function baseHandler(event: HandlerEnum, value: any) { ...@@ -14,6 +14,7 @@ export function baseHandler(event: HandlerEnum, value: any) {
} }
export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> { export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> {
const { getThemeColor } = useRootSetting();
switch (event) { switch (event) {
case HandlerEnum.CHANGE_LAYOUT: case HandlerEnum.CHANGE_LAYOUT:
const { mode, type, split } = value; const { mode, type, split } = value;
...@@ -30,6 +31,13 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf ...@@ -30,6 +31,13 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
}, },
}; };
case HandlerEnum.CHANGE_THEME_COLOR:
if (getThemeColor.value === value) {
return {};
}
changeTheme(value);
return { themeColor: value };
case HandlerEnum.MENU_HAS_DRAG: case HandlerEnum.MENU_HAS_DRAG:
return { menuSetting: { canDrag: value } }; return { menuSetting: { canDrag: value } };
......
...@@ -37,6 +37,7 @@ export default { ...@@ -37,6 +37,7 @@ export default {
splitMenu: 'Split menu', splitMenu: 'Split menu',
closeMixSidebarOnChange: 'Switch page to close menu', closeMixSidebarOnChange: 'Switch page to close menu',
sysTheme: 'System theme',
headerTheme: 'Header theme', headerTheme: 'Header theme',
sidebarTheme: 'Menu theme', sidebarTheme: 'Menu theme',
......
...@@ -36,6 +36,7 @@ export default { ...@@ -36,6 +36,7 @@ export default {
splitMenu: '分割菜单', splitMenu: '分割菜单',
closeMixSidebarOnChange: '切换页面关闭菜单', closeMixSidebarOnChange: '切换页面关闭菜单',
sysTheme: '系统主题',
headerTheme: '顶栏主题', headerTheme: '顶栏主题',
sidebarTheme: '菜单主题', sidebarTheme: '菜单主题',
......
...@@ -8,15 +8,14 @@ import { PROJ_CFG_KEY } from '/@/enums/cacheEnum'; ...@@ -8,15 +8,14 @@ import { PROJ_CFG_KEY } from '/@/enums/cacheEnum';
import projectSetting from '/@/settings/projectSetting'; import projectSetting from '/@/settings/projectSetting';
import { getLocal } from '/@/utils/helper/persistent'; import { getLocal } from '/@/utils/helper/persistent';
import { import { updateHeaderBgColor, updateSidebarBgColor } from '/@/logics/theme/updateBackground';
updateGrayMode, import { updateColorWeak } from '/@/logics/theme/updateColorWeak';
updateColorWeak, import { updateGrayMode } from '/@/logics/theme/updateGrayMode';
updateHeaderBgColor, import { changeTheme } from '/@/logics/theme';
updateSidebarBgColor,
} from '/@/logics/theme';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { deepMerge } from '/@/utils'; import { deepMerge } from '/@/utils';
import { primaryColor } from '../../build/config/themeConfig';
// Initial project configuration // Initial project configuration
export function initAppConfigStore() { export function initAppConfigStore() {
...@@ -26,16 +25,13 @@ export function initAppConfigStore() { ...@@ -26,16 +25,13 @@ export function initAppConfigStore() {
const { const {
colorWeak, colorWeak,
grayMode, grayMode,
themeColor,
headerSetting: { bgColor: headerBgColor } = {}, headerSetting: { bgColor: headerBgColor } = {},
menuSetting: { bgColor } = {}, menuSetting: { bgColor } = {},
} = projCfg; } = projCfg;
// if ( if (themeColor && themeColor !== primaryColor) {
// themeColor !== primaryColor && changeTheme(themeColor);
// themeColor && }
// process.env.VUE_APP_USE_THEME_REPLACER !== 'TRUE'
// ) {
// updateTheme(themeColor);
// }
headerBgColor && updateHeaderBgColor(headerBgColor); headerBgColor && updateHeaderBgColor(headerBgColor);
bgColor && updateSidebarBgColor(bgColor); bgColor && updateSidebarBgColor(bgColor);
grayMode && updateGrayMode(grayMode); grayMode && updateGrayMode(grayMode);
......
import { isHexColor, colorIsDark, lighten, darken } from '/@/utils/color'; import { getThemeColors, ThemeMode, generateColors } from '../../../build/config/themeConfig';
import { appStore } from '/@/store/modules/app';
import { ThemeEnum } from '/@/enums/appEnum';
const HEADER_BG_COLOR_VAR = '--header-bg-color'; import { replaceStyleVariables } from 'vite-plugin-theme/es/client';
const HEADER_BG_HOVER_COLOR_VAR = '--header-bg-hover-color'; import { mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme/es/colorUtils';
const HEADER_MENU_ACTIVE_BG_COLOR_VAR = '--header-active-menu-bg-color';
const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color'; export async function changeTheme(color: string, theme?: ThemeMode) {
const SIDER_DARK_DARKEN_BG_COLOR = '--sider-dark-darken-bg-color'; const colors = generateColors({
const SIDER_LIGHTEN_1_BG_COLOR = '--sider-dark-lighten-1-bg-color'; mixDarken,
const SIDER_LIGHTEN_2_BG_COLOR = '--sider-dark-lighten-2-bg-color'; mixLighten,
tinycolor,
export function setCssVar(prop: string, val: any, dom = document.documentElement) { color,
dom.style.setProperty(prop, val);
}
function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
const targetEl = target || document.body;
let { className } = targetEl;
className = className.replace(clsName, '');
targetEl.className = flag ? `${className} ${clsName} ` : className;
}
/**
* Change the status of the project's color weakness mode
* @param colorWeak
*/
export const updateColorWeak = (colorWeak: boolean) => {
toggleClass(colorWeak, 'color-weak', document.documentElement);
};
/**
* Change project gray mode status
* @param gray
*/
export const updateGrayMode = (gray: boolean) => {
toggleClass(gray, 'gray-mode', document.documentElement);
};
/**
* Change the background color of the top header
* @param color
*/
export function updateHeaderBgColor(color: string) {
if (!isHexColor(color)) return;
// bg color
setCssVar(HEADER_BG_COLOR_VAR, color);
// hover color
const hoverColor = lighten(color, 6);
setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor);
setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor);
// Determine the depth of the color value and automatically switch the theme
const isDark = colorIsDark(color);
appStore.commitProjectConfigState({
headerSetting: {
theme: isDark ? ThemeEnum.DARK : ThemeEnum.LIGHT,
},
}); });
}
/**
* Change the background color of the left menu
* @param color bg color
*/
export function updateSidebarBgColor(color: string) {
if (!isHexColor(color)) return;
setCssVar(SIDER_DARK_BG_COLOR, color);
setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color, 6));
setCssVar(SIDER_LIGHTEN_1_BG_COLOR, lighten(color, 5));
setCssVar(SIDER_LIGHTEN_2_BG_COLOR, lighten(color, 8));
// only #ffffff is light
// Only when the background color is #fff, the theme of the menu will be changed to light
const isLight = ['#fff', '#ffffff'].includes(color.toLowerCase());
appStore.commitProjectConfigState({ return await replaceStyleVariables({
menuSetting: { colorVariables: [...getThemeColors(color, theme), ...colors],
theme: isLight ? ThemeEnum.LIGHT : ThemeEnum.DARK,
},
}); });
} }
import { isHexColor, colorIsDark, lighten, darken } from '/@/utils/color';
import { appStore } from '/@/store/modules/app';
import { ThemeEnum } from '/@/enums/appEnum';
import { setCssVar } from './util';
const HEADER_BG_COLOR_VAR = '--header-bg-color';
const HEADER_BG_HOVER_COLOR_VAR = '--header-bg-hover-color';
const HEADER_MENU_ACTIVE_BG_COLOR_VAR = '--header-active-menu-bg-color';
const SIDER_DARK_BG_COLOR = '--sider-dark-bg-color';
const SIDER_DARK_DARKEN_BG_COLOR = '--sider-dark-darken-bg-color';
const SIDER_LIGHTEN_1_BG_COLOR = '--sider-dark-lighten-1-bg-color';
const SIDER_LIGHTEN_2_BG_COLOR = '--sider-dark-lighten-2-bg-color';
/**
* Change the background color of the top header
* @param color
*/
export function updateHeaderBgColor(color: string) {
if (!isHexColor(color)) return;
// bg color
setCssVar(HEADER_BG_COLOR_VAR, color);
// hover color
const hoverColor = lighten(color, 6);
setCssVar(HEADER_BG_HOVER_COLOR_VAR, hoverColor);
setCssVar(HEADER_MENU_ACTIVE_BG_COLOR_VAR, hoverColor);
// Determine the depth of the color value and automatically switch the theme
const isDark = colorIsDark(color);
appStore.commitProjectConfigState({
headerSetting: {
theme: isDark ? ThemeEnum.DARK : ThemeEnum.LIGHT,
},
});
}
/**
* Change the background color of the left menu
* @param color bg color
*/
export function updateSidebarBgColor(color: string) {
if (!isHexColor(color)) return;
setCssVar(SIDER_DARK_BG_COLOR, color);
setCssVar(SIDER_DARK_DARKEN_BG_COLOR, darken(color, 6));
setCssVar(SIDER_LIGHTEN_1_BG_COLOR, lighten(color, 5));
setCssVar(SIDER_LIGHTEN_2_BG_COLOR, lighten(color, 8));
// only #ffffff is light
// Only when the background color is #fff, the theme of the menu will be changed to light
const isLight = ['#fff', '#ffffff'].includes(color.toLowerCase());
appStore.commitProjectConfigState({
menuSetting: {
theme: isLight ? ThemeEnum.LIGHT : ThemeEnum.DARK,
},
});
}
import { toggleClass } from './util';
/**
* Change the status of the project's color weakness mode
* @param colorWeak
*/
export function updateColorWeak(colorWeak: boolean) {
toggleClass(colorWeak, 'color-weak', document.documentElement);
}
import { toggleClass } from './util';
/**
* Change project gray mode status
* @param gray
*/
export function updateGrayMode(gray: boolean) {
toggleClass(gray, 'gray-mode', document.documentElement);
}
const docEle = document.documentElement;
export function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
const targetEl = target || document.body;
let { className } = targetEl;
className = className.replace(clsName, '');
targetEl.className = flag ? `${className} ${clsName} ` : className;
}
export function setCssVar(prop: string, val: any, dom = docEle) {
dom.style.setProperty(prop, val);
}
...@@ -3,14 +3,24 @@ export default { ...@@ -3,14 +3,24 @@ export default {
}; };
// header preset color // header preset color
export const APP_PRESET_COLOR_LIST: string[] = [
'#0084f4',
'#009688',
'#536dfe',
'#ff5c93',
'#ee4f12',
'#0096c7',
'#9c27b0',
'#ff9800',
];
// header preset color
export const HEADER_PRESET_BG_COLOR_LIST: string[] = [ export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
'#ffffff', '#ffffff',
'#009688', '#009688',
'#5172DC', '#5172DC',
'#1E9FFF',
'#018ffb', '#018ffb',
'#409eff', '#409eff',
'#4e73df',
'#e74c3c', '#e74c3c',
'#24292e', '#24292e',
'#394664', '#394664',
......
...@@ -3,7 +3,7 @@ import type { ProjectConfig } from '/@/types/config'; ...@@ -3,7 +3,7 @@ import type { ProjectConfig } from '/@/types/config';
import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '/@/enums/menuEnum'; import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '/@/enums/menuEnum';
import { CacheTypeEnum } from '/@/enums/cacheEnum'; import { CacheTypeEnum } from '/@/enums/cacheEnum';
import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
import { primaryColor } from '../../build/config/lessModifyVars'; import { primaryColor, themeMode } from '../../build/config/themeConfig';
import { isProdMode } from '/@/utils/env'; import { isProdMode } from '/@/utils/env';
// ! You need to clear the browser cache after the change // ! You need to clear the browser cache after the change
...@@ -20,6 +20,8 @@ const setting: ProjectConfig = { ...@@ -20,6 +20,8 @@ const setting: ProjectConfig = {
// color // color
// TODO Theme color // TODO Theme color
themeColor: primaryColor, themeColor: primaryColor,
// TODO dark theme
themeMode: themeMode,
// Website gray mode, open for possible mourning dates // Website gray mode, open for possible mourning dates
grayMode: false, grayMode: false,
......
...@@ -2,6 +2,7 @@ import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from ' ...@@ -2,6 +2,7 @@ import { MenuTypeEnum, MenuModeEnum, TriggerEnum, MixSidebarTriggerEnum } from '
import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum'; import { ContentEnum, PermissionModeEnum, ThemeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
import { CacheTypeEnum } from '/@/enums/cacheEnum'; import { CacheTypeEnum } from '/@/enums/cacheEnum';
import type { LocaleType } from '/@/locales/types'; import type { LocaleType } from '/@/locales/types';
import { ThemeMode } from '../../build/config/lessModifyVars';
export interface MenuSetting { export interface MenuSetting {
bgColor: string; bgColor: string;
...@@ -95,6 +96,7 @@ export interface ProjectConfig { ...@@ -95,6 +96,7 @@ export interface ProjectConfig {
colorWeak: boolean; colorWeak: boolean;
// 主题色 // 主题色
themeColor: string; themeColor: string;
themeMode: ThemeMode;
// 全屏显示主界面,不显示菜单,及顶部 // 全屏显示主界面,不显示菜单,及顶部
fullContent: boolean; fullContent: boolean;
// 区域宽度 // 区域宽度
......
...@@ -3,3 +3,23 @@ declare module '*.vue' { ...@@ -3,3 +3,23 @@ declare module '*.vue' {
const Component: ReturnType<typeof defineComponent>; const Component: ReturnType<typeof defineComponent>;
export default Component; export default Component;
} }
import type { ComponentRenderProxy, VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
type Element = VNode;
// tslint:disable no-empty-interface
type ElementClass = ComponentRenderProxy;
interface ElementAttributesProperty {
$props: any;
}
interface IntrinsicElements {
[elem: string]: any;
}
interface IntrinsicAttributes {
[elem: string]: any;
}
}
}
...@@ -6,7 +6,7 @@ import legacy from '@vitejs/plugin-legacy'; ...@@ -6,7 +6,7 @@ import legacy from '@vitejs/plugin-legacy';
import { loadEnv } from 'vite'; import { loadEnv } from 'vite';
import { modifyVars } from './build/config/lessModifyVars'; import { generateModifyVars } from './build/config/themeConfig';
import { createProxy } from './build/vite/proxy'; import { createProxy } from './build/vite/proxy';
import { wrapperEnv } from './build/utils'; import { wrapperEnv } from './build/utils';
...@@ -67,7 +67,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => { ...@@ -67,7 +67,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
modifyVars: { modifyVars: {
// reference: Avoid repeated references // reference: Avoid repeated references
hack: `true; @import (reference) "${resolve('src/design/config.less')}";`, hack: `true; @import (reference) "${resolve('src/design/config.less')}";`,
...modifyVars, ...generateModifyVars(),
}, },
javascriptEnabled: true, javascriptEnabled: true,
}, },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论