Skip to content

Commit

Permalink
feat(projects): element-plus theme color and dark mode
Browse files Browse the repository at this point in the history
  • Loading branch information
honghuangdc committed Oct 21, 2023
1 parent e0612bf commit 464b54b
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 30 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"dependencies": {
"@iconify/vue": "4.1.1",
"@sa/color-palette": "workspace:*",
"@sa/hooks": "workspace:*",
"@sa/materials": "workspace:*",
"@sa/utils": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions src/plugins/assets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'virtual:svg-icons-register';
import 'element-plus/es/components/message/style/css';
import 'element-plus/es/components/message-box/style/css';
import 'element-plus/theme-chalk/dark/css-vars.css';
import 'nprogress/nprogress.css';
import 'uno.css';
import '../styles/global.css';
66 changes: 66 additions & 0 deletions src/store/modules/theme/element-plus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
type ElementPlusThemeColor = App.Theme.ThemeColorKey | 'danger';

type ElementPlusThemeColorLightNumber = 3 | 5 | 7 | 8 | 9;

type GetElementThemeColorVarsKey<T extends string> =
| `--el-color-${T}`
| `--el-color-${T}-rgb`
| `--el-color-${T}-light-${ElementPlusThemeColorLightNumber}`
| `--el-color-${T}-dark-2`;

type ElementPlusThemeVars = {
[key in GetElementThemeColorVarsKey<ElementPlusThemeColor>]: string;
};

type ElementPlusThemeVarsMap = {
[key in keyof ElementPlusThemeVars]: keyof App.Theme.ThemePaletteColor;
};

function createElementPlusThemeColorMap<T extends ElementPlusThemeColor>(color: T, dark = false) {
const colorKey = color === 'danger' ? 'error' : color;

const colorMap: Partial<ElementPlusThemeVarsMap> = {
[`--el-color-${color}`]: colorKey,
[`--el-color-${color}-rgb`]: colorKey,
[`--el-color-${color}-light-3`]: dark ? 'primary-600' : 'primary-400',
[`--el-color-${color}-light-5`]: dark ? 'primary-700' : 'primary-300',
[`--el-color-${color}-light-7`]: dark ? 'primary-800' : 'primary-200',
[`--el-color-${color}-light-8`]: dark ? 'primary-900' : 'primary-100',
[`--el-color-${color}-light-9`]: dark ? 'primary-950' : 'primary-50',
[`--el-color-${color}-dark-2`]: dark ? 'primary-900' : 'primary-100'
};

return colorMap as unknown as GetElementThemeColorVarsKey<T>;
}

function createElementPlusThemeColorsMap(dark = false) {
const map = {} as ElementPlusThemeVarsMap;

const colorKeys: ElementPlusThemeColor[] = ['primary', 'info', 'success', 'warning', 'error', 'danger'];

colorKeys.forEach(key => {
const colorMap = createElementPlusThemeColorMap(key, dark);

Object.assign(map, colorMap);
});

return map;
}

export function getElementPlusThemeVars(themeTokenVars: App.Theme.ThemeTokenVars, dark = false) {
const colorMap = createElementPlusThemeColorsMap(dark);

const { colors } = themeTokenVars;

const colorVarsArray: string[] = [];

for (const [key, value] of Object.entries(colorMap)) {
const { cssVarsKey } = colors[value];

colorVarsArray.push(`${key}: rgb(var(${cssVarsKey}))`);
}

const cssVarStr = colorVarsArray.join(';');

return cssVarStr;
}
100 changes: 81 additions & 19 deletions src/store/modules/theme/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { getColorPalette } from '@sa/color-palette';
import { getRgbOfColor } from '@sa/utils';
import { themeVars } from '@/theme/vars';
import { getElementPlusThemeVars } from './element-plus';

const DARK_CLASS = 'dark';

Expand Down Expand Up @@ -30,11 +33,13 @@ export function initThemeSettings(colors: App.Theme.ThemeTokenColor) {
export function createThemeToken() {
const themeTokens: App.Theme.ThemeToken = {
colors: {
primary: '#646cff',
info: '#2080f0',
success: '#52c41a',
warning: '#faad14',
error: '#f5222d',
...createThemePaletteColors({
primary: '#646cff',
info: '#2080f0',
success: '#52c41a',
warning: '#faad14',
error: '#f5222d'
}),
container: 'rgba(255, 255, 255, 0.8)',
layout: 'rgba(247, 250, 252, 1)',
base_text: 'rgba(0, 0, 0, 0.88)'
Expand Down Expand Up @@ -64,45 +69,102 @@ export function createThemeToken() {
};
}

function getCssVarByTokens(tokens: App.Theme.BaseToken) {
const style: string[] = [];
/**
* create theme palette colors
* @param colors theme colors
*/
function createThemePaletteColors(colors: App.Theme.ThemeColor) {
const colorKeys = Object.keys(colors) as App.Theme.ThemeColorKey[];
const colorPaletteVar = {} as App.Theme.ThemePaletteColor;

colorKeys.forEach(key => {
const { palettes, main } = getColorPalette(colors[key], key);

colorPaletteVar[key] = main.hexcode;

palettes.forEach(item => {
colorPaletteVar[`${key}-${item.number}`] = item.hexcode;
});
});

return colorPaletteVar;
}

/**
* get theme token vars
* @param tokens
*/
function getThemeTokenVars(tokens: App.Theme.BaseToken) {
const themeTokenVars = {} as App.Theme.BaseTokenVars;
const themeTokenVarsArray: string[] = [];

function removeVarPrefix(value: string) {
return value.replace('var(', '').replace(')', '');
}

for (const item of Object.entries(themeVars)) {
const [tokenKey, vars] = item;
function removeRgbPrefix(value: string) {
return value.replace('rgb(', '').replace(')', '');
}

for (const [key, tokenValues] of Object.entries(themeVars as unknown as App.Theme.BaseToken)) {
themeTokenVars[key] = {};

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}`;
}

for (const varsItem of Object.entries(vars)) {
const [key, value] = varsItem;
themeTokenVars[key][tokenKey] = {
cssVarsKey,
cssValue
};

style.push(`${removeVarPrefix(value)}: ${tokens[tokenKey][key]}`);
themeTokenVarsArray.push(`${cssVarsKey}: ${cssValue}`);
}
}

const styleStr = style.join(';');
const themeTokenVarStr = themeTokenVarsArray.join(';');

return styleStr;
const result = {
themeTokenVars,
themeTokenVarStr
} as {
themeTokenVars: App.Theme.ThemeTokenVars;
themeTokenVarStr: string;
};

return result;
}

/**
* add theme vars to html
* @param tokens
*/
export function setupThemeVarsToHtml(tokens: App.Theme.BaseToken, darkTokens: App.Theme.BaseToken) {
const cssVarStr = getCssVarByTokens(tokens);
const darkCssVarStr = getCssVarByTokens(darkTokens);
export function setupThemeVarsToHtml<T extends App.Theme.BaseToken>(tokens: T, darkTokens: T) {
const { themeTokenVars, themeTokenVarStr: cssVarStr } = getThemeTokenVars(tokens);
const { themeTokenVarStr: darkCssVarStr } = getThemeTokenVars(darkTokens);
const elementPlusCssVarStr = getElementPlusThemeVars(themeTokenVars);
const elementPlusDarkCssVarStr = getElementPlusThemeVars(themeTokenVars, true);

const css = `
:root {
${elementPlusCssVarStr}
}
html {
${cssVarStr}
${cssVarStr};
}
`;

const darkCss = `
html.${DARK_CLASS} {
${darkCssVarStr}
${darkCssVarStr};
${elementPlusDarkCssVarStr};
`;

const style = document.createElement('style');
Expand Down
34 changes: 26 additions & 8 deletions src/theme/vars.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
/**
* create color palette vars
*/
function createColorPaletteVars() {
const colors: App.Theme.ThemeColorKey[] = ['primary', 'info', 'success', 'warning', 'error'];
const colorPaletteNumbers: App.Theme.ColorPaletteNumber[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];

const colorPaletteVar = {} as App.Theme.ThemePaletteColor;

colors.forEach(color => {
colorPaletteVar[color] = `rgb(var(--${color}-color))`;
colorPaletteNumbers.forEach(number => {
colorPaletteVar[`${color}-${number}`] = `rgb(var(--${color}-${number}-color))`;
});
});

return colorPaletteVar;
}

/**
* theme vars
*/
export const themeVars: App.Theme.ThemeToken = {
colors: {
primary: 'var(--primary-color)',
info: 'var(--info-color)',
success: 'var(--success-color)',
warning: 'var(--warning-color)',
error: 'var(--error-color)',
container: 'var(--container-bg-color)',
layout: 'var(--layout-bg-color)',
base_text: 'var(--base-text-color)'
...createColorPaletteVars(),
container: 'rgb(var(--container-bg-color))',
layout: 'rgb(var(--layout-bg-color))',
base_text: 'rgb(var(--base-text-color))'
},
boxShadow: {
header: 'var(--header-box-shadow)',
Expand Down
31 changes: 28 additions & 3 deletions src/typings/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ declare namespace App {
* theme namespace
*/
namespace Theme {
type ColorPaletteNumber = import('@sa/color-palette').ColorPaletteNumber;

/**
* color scheme
*/
Expand Down Expand Up @@ -36,15 +38,25 @@ declare namespace App {
error: string;
}

interface ThemeColor extends OtherColor {
primary: string;
}

type ThemeColorKey = keyof ThemeColor;

type ThemePaletteColor = {
[key in ThemeColorKey | `${ThemeColorKey}-${ColorPaletteNumber}`]: string;
};

type BaseToken = Record<string, Record<string, string>>;

interface ThemeTokenColor extends OtherColor {
primary: string;
type ThemeTokenColor = ThemePaletteColor & {
container: string;
layout: string;
base_text: string;
} & {
[key: string]: string;
}
};

type ThemeToken = {
colors: ThemeTokenColor;
Expand All @@ -53,7 +65,20 @@ declare namespace App {
sider: string;
tab: string;
};
} & { [key: string]: Record<string, string> };

interface CssVarsItem {
cssVarsKey: string;
cssValue: string;
}

type ThemeTokenVars = {
[key in keyof ThemeToken]: {
[k in keyof ThemeToken[key]]: CssVarsItem;
};
};

type BaseTokenVars = Record<string, Record<string, CssVarsItem>>;
}

namespace Global {
Expand Down

0 comments on commit 464b54b

Please sign in to comment.