UNPKG

@_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
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; }