@_lan/web-libs
Version:
<div align="center"> <img src="./public/favicon.svg" width="160" /> <h1>SoybeanAdmin AntDesign</h1> <span>中文 | <a href="./README.en_US.md">English</a></span> </div>
233 lines (189 loc) • 5.76 kB
text/typescript
import { theme as antdTheme } from 'ant-design-vue';
import type { ConfigProviderProps } from 'ant-design-vue';
import { getColorPalette } from '@sa/color';
import { getRgbOfColor } from '@sa/utils';
import { defu } from 'defu';
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 localSettings = localStg.get('themeSettings');
let settings = defu(localSettings, themeSettings);
const isOverride = localStg.get('overrideThemeFlag') === BUILD_TIME;
if (!isOverride) {
settings = defu(overrideThemeSettings, settings);
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 } = getRgbOfColor(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(' ');
}
/**
* Get antd theme
*
* @param colors Theme colors
* @param darkMode Is dark mode
*/
export function getAntdTheme(colors: App.Theme.ThemeColor, darkMode: boolean) {
const { defaultAlgorithm, darkAlgorithm } = antdTheme;
const { primary, info, success, warning, error } = colors;
const theme: ConfigProviderProps['theme'] = {
token: {
colorPrimary: primary,
colorInfo: info,
colorSuccess: success,
colorWarning: warning,
colorError: error
},
algorithm: [darkMode ? darkAlgorithm : defaultAlgorithm],
components: {
Button: {
controlHeightSM: 28
},
Menu: {
colorSubItemBg: 'transparent'
}
}
};
return theme;
}