75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
/**
|
||
* 主题色工具:根据取色器选中的主色,计算 hover/light 并写入 :root CSS 变量
|
||
* 用于导航栏、侧边菜单、按钮等公共颜色统一切换
|
||
*/
|
||
|
||
const STORAGE_KEY = 'app-theme-color';
|
||
|
||
export function getStoredThemeColor(): string | null {
|
||
try {
|
||
return localStorage.getItem(STORAGE_KEY);
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
export function setStoredThemeColor(hex: string): void {
|
||
try {
|
||
localStorage.setItem(STORAGE_KEY, hex);
|
||
} catch {
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
/** 将 hex 转为 r,g,b (0-255) */
|
||
function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
|
||
const m = hex.replace(/^#/, '').match(/^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);
|
||
if (!m) return null;
|
||
return {
|
||
r: parseInt(m[1], 16),
|
||
g: parseInt(m[2], 16),
|
||
b: parseInt(m[3], 16),
|
||
};
|
||
}
|
||
|
||
/** 将 r,g,b 转为 #rrggbb */
|
||
function rgbToHex(r: number, g: number, b: number): string {
|
||
return '#' + [r, g, b].map((x) => Math.round(Math.max(0, Math.min(255, x))).toString(16).padStart(2, '0')).join('');
|
||
}
|
||
|
||
/** 在 hex 颜色基础上按比例变暗(用于 hover) */
|
||
function darkenHex(hex: string, ratio: number): string {
|
||
const rgb = hexToRgb(hex);
|
||
if (!rgb) return hex;
|
||
return rgbToHex(rgb.r * (1 - ratio), rgb.g * (1 - ratio), rgb.b * (1 - ratio));
|
||
}
|
||
|
||
/** 生成浅色背景(用于 menu hover 等) */
|
||
function lightenHex(hex: string, mixWhite = 0.92): string {
|
||
const rgb = hexToRgb(hex);
|
||
if (!rgb) return hex;
|
||
const r = Math.round(rgb.r * (1 - mixWhite) + 255 * mixWhite);
|
||
const g = Math.round(rgb.g * (1 - mixWhite) + 255 * mixWhite);
|
||
const b = Math.round(rgb.b * (1 - mixWhite) + 255 * mixWhite);
|
||
return rgbToHex(r, g, b);
|
||
}
|
||
|
||
/**
|
||
* 将主题色应用到页面:设置 :root 上的 CSS 变量
|
||
* @param primaryHex 主色,如 #2D8C8C
|
||
*/
|
||
export function applyThemeColor(primaryHex: string): void {
|
||
const hex = primaryHex.startsWith('#') ? primaryHex : `#${primaryHex}`;
|
||
const root = document.documentElement;
|
||
|
||
const primary = hex;
|
||
const primaryHover = darkenHex(hex, 0.05);
|
||
const primaryLight = lightenHex(hex, 0.92);
|
||
|
||
root.style.setProperty('--app-primary-color', primary);
|
||
root.style.setProperty('--app-primary-color-hover', primaryHover);
|
||
root.style.setProperty('--app-primary-color-light', primaryLight);
|
||
root.style.setProperty('--app-navbar-bg', primary);
|
||
root.style.setProperty('--app-sidebar-bg', primary);
|
||
}
|