mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
257 lines
6.6 KiB
TypeScript
257 lines
6.6 KiB
TypeScript
import type { GlobalThemeOverrides } from 'naive-ui';
|
|
import { addColorAlpha, getColorPalette, getPaletteColorByNumber, getRgb } from '@sa/color';
|
|
import { overrideThemeSettings, themeSettings } from '@/theme/settings';
|
|
import { themeVars } from '@/theme/vars';
|
|
import { toggleHtmlClass } from '@/utils/common';
|
|
import { localStg } from '@/utils/storage';
|
|
|
|
const DARK_CLASS = 'dark';
|
|
|
|
/** Init theme settings */
|
|
export function initThemeSettings() {
|
|
const isProd = import.meta.env.PROD;
|
|
|
|
// if it is development mode, the theme settings will not be cached, by update `themeSettings` in `src/theme/settings.ts` to update theme settings
|
|
if (!isProd) return themeSettings;
|
|
|
|
// if it is production mode, the theme settings will be cached in localStorage
|
|
// if want to update theme settings when publish new version, please update `overrideThemeSettings` in `src/theme/settings.ts`
|
|
|
|
const settings = localStg.get('themeSettings') || themeSettings;
|
|
|
|
const isOverride = localStg.get('overrideThemeFlag') === BUILD_TIME;
|
|
|
|
if (!isOverride) {
|
|
Object.assign(settings, overrideThemeSettings);
|
|
localStg.set('overrideThemeFlag', BUILD_TIME);
|
|
}
|
|
|
|
return settings;
|
|
}
|
|
|
|
/**
|
|
* create theme token css vars value by theme settings
|
|
*
|
|
* @param colors Theme colors
|
|
* @param tokens Theme setting tokens
|
|
* @param [recommended=false] Use recommended color. Default is `false`
|
|
*/
|
|
export function createThemeToken(
|
|
colors: App.Theme.ThemeColor,
|
|
tokens?: App.Theme.ThemeSetting['tokens'],
|
|
recommended = false
|
|
) {
|
|
const paletteColors = createThemePaletteColors(colors, recommended);
|
|
|
|
const { light, dark } = tokens || themeSettings.tokens;
|
|
|
|
const themeTokens: App.Theme.ThemeTokenCSSVars = {
|
|
colors: {
|
|
...paletteColors,
|
|
nprogress: paletteColors.primary,
|
|
...light.colors
|
|
},
|
|
boxShadow: {
|
|
...light.boxShadow
|
|
}
|
|
};
|
|
|
|
const darkThemeTokens: App.Theme.ThemeTokenCSSVars = {
|
|
colors: {
|
|
...themeTokens.colors,
|
|
...dark?.colors
|
|
},
|
|
boxShadow: {
|
|
...themeTokens.boxShadow,
|
|
...dark?.boxShadow
|
|
}
|
|
};
|
|
|
|
return {
|
|
themeTokens,
|
|
darkThemeTokens
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create theme palette colors
|
|
*
|
|
* @param colors Theme colors
|
|
* @param [recommended=false] Use recommended color. Default is `false`
|
|
*/
|
|
function createThemePaletteColors(colors: App.Theme.ThemeColor, recommended = false) {
|
|
const colorKeys = Object.keys(colors) as App.Theme.ThemeColorKey[];
|
|
const colorPaletteVar = {} as App.Theme.ThemePaletteColor;
|
|
|
|
colorKeys.forEach(key => {
|
|
const colorMap = getColorPalette(colors[key], recommended);
|
|
|
|
colorPaletteVar[key] = colorMap.get(500)!;
|
|
|
|
colorMap.forEach((hex, number) => {
|
|
colorPaletteVar[`${key}-${number}`] = hex;
|
|
});
|
|
});
|
|
|
|
return colorPaletteVar;
|
|
}
|
|
|
|
/**
|
|
* Get css var by tokens
|
|
*
|
|
* @param tokens Theme base tokens
|
|
*/
|
|
function getCssVarByTokens(tokens: App.Theme.BaseToken) {
|
|
const styles: string[] = [];
|
|
|
|
function removeVarPrefix(value: string) {
|
|
return value.replace('var(', '').replace(')', '');
|
|
}
|
|
|
|
function removeRgbPrefix(value: string) {
|
|
return value.replace('rgb(', '').replace(')', '');
|
|
}
|
|
|
|
for (const [key, tokenValues] of Object.entries(themeVars)) {
|
|
for (const [tokenKey, tokenValue] of Object.entries(tokenValues)) {
|
|
let cssVarsKey = removeVarPrefix(tokenValue);
|
|
let cssValue = tokens[key][tokenKey];
|
|
|
|
if (key === 'colors') {
|
|
cssVarsKey = removeRgbPrefix(cssVarsKey);
|
|
const { r, g, b } = getRgb(cssValue);
|
|
cssValue = `${r} ${g} ${b}`;
|
|
}
|
|
|
|
styles.push(`${cssVarsKey}: ${cssValue}`);
|
|
}
|
|
}
|
|
|
|
const styleStr = styles.join(';');
|
|
|
|
return styleStr;
|
|
}
|
|
|
|
/**
|
|
* Add theme vars to global
|
|
*
|
|
* @param tokens
|
|
*/
|
|
export function addThemeVarsToGlobal(tokens: App.Theme.BaseToken, darkTokens: App.Theme.BaseToken) {
|
|
const cssVarStr = getCssVarByTokens(tokens);
|
|
const darkCssVarStr = getCssVarByTokens(darkTokens);
|
|
|
|
const css = `
|
|
:root {
|
|
${cssVarStr}
|
|
}
|
|
`;
|
|
|
|
const darkCss = `
|
|
html.${DARK_CLASS} {
|
|
${darkCssVarStr}
|
|
}
|
|
`;
|
|
|
|
const styleId = 'theme-vars';
|
|
|
|
const style = document.querySelector(`#${styleId}`) || document.createElement('style');
|
|
|
|
style.id = styleId;
|
|
|
|
style.textContent = css + darkCss;
|
|
|
|
document.head.appendChild(style);
|
|
}
|
|
|
|
/**
|
|
* Toggle css dark mode
|
|
*
|
|
* @param darkMode Is dark mode
|
|
*/
|
|
export function toggleCssDarkMode(darkMode = false) {
|
|
const { add, remove } = toggleHtmlClass(DARK_CLASS);
|
|
|
|
if (darkMode) {
|
|
add();
|
|
} else {
|
|
remove();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle auxiliary color modes
|
|
*
|
|
* @param grayscaleMode
|
|
* @param colourWeakness
|
|
*/
|
|
export function toggleAuxiliaryColorModes(grayscaleMode = false, colourWeakness = false) {
|
|
const htmlElement = document.documentElement;
|
|
htmlElement.style.filter = [grayscaleMode ? 'grayscale(100%)' : '', colourWeakness ? 'invert(80%)' : '']
|
|
.filter(Boolean)
|
|
.join(' ');
|
|
}
|
|
|
|
type NaiveColorScene = '' | 'Suppl' | 'Hover' | 'Pressed' | 'Active';
|
|
type NaiveColorKey = `${App.Theme.ThemeColorKey}Color${NaiveColorScene}`;
|
|
type NaiveThemeColor = Partial<Record<NaiveColorKey, string>>;
|
|
interface NaiveColorAction {
|
|
scene: NaiveColorScene;
|
|
handler: (color: string) => string;
|
|
}
|
|
|
|
/**
|
|
* Get naive theme colors
|
|
*
|
|
* @param colors Theme colors
|
|
* @param [recommended=false] Use recommended color. Default is `false`
|
|
*/
|
|
function getNaiveThemeColors(colors: App.Theme.ThemeColor, recommended = false) {
|
|
const colorActions: NaiveColorAction[] = [
|
|
{ scene: '', handler: color => color },
|
|
{ scene: 'Suppl', handler: color => color },
|
|
{ scene: 'Hover', handler: color => getPaletteColorByNumber(color, 500, recommended) },
|
|
{ scene: 'Pressed', handler: color => getPaletteColorByNumber(color, 700, recommended) },
|
|
{ scene: 'Active', handler: color => addColorAlpha(color, 0.1) }
|
|
];
|
|
|
|
const themeColors: NaiveThemeColor = {};
|
|
|
|
const colorEntries = Object.entries(colors) as [App.Theme.ThemeColorKey, string][];
|
|
|
|
colorEntries.forEach(color => {
|
|
colorActions.forEach(action => {
|
|
const [colorType, colorValue] = color;
|
|
const colorKey: NaiveColorKey = `${colorType}Color${action.scene}`;
|
|
themeColors[colorKey] = action.handler(colorValue);
|
|
});
|
|
});
|
|
|
|
return themeColors;
|
|
}
|
|
|
|
/**
|
|
* Get naive theme
|
|
*
|
|
* @param colors Theme colors
|
|
* @param [recommended=false] Use recommended color. Default is `false`
|
|
*/
|
|
export function getNaiveTheme(colors: App.Theme.ThemeColor, recommended = false) {
|
|
const { primary: colorLoading } = colors;
|
|
|
|
const theme: GlobalThemeOverrides = {
|
|
common: {
|
|
...getNaiveThemeColors(colors, recommended),
|
|
borderRadius: '6px'
|
|
},
|
|
LoadingBar: {
|
|
colorLoading
|
|
},
|
|
Tag: {
|
|
borderRadius: '6px'
|
|
}
|
|
};
|
|
|
|
return theme;
|
|
}
|