wx/src/styles/theme.js

151 lines
5.3 KiB
JavaScript

// 使用 import.meta.glob 动态导入 themes 目录下的所有 .js 文件
// { eager: true } 表示同步导入,立即获取模块内容
const themeModules = import.meta.glob('./themes/*.js', { eager: true });
// 构建 themes 对象,确保 default 优先
export const themes = {};
const defaultPath = './themes/default.js';
// 1. 首先处理 default 主题
if (themeModules[defaultPath] && themeModules[defaultPath].default) {
themes['default'] = themeModules[defaultPath].default;
}
// 2. 处理其他主题
for (const path in themeModules) {
// 跳过已经处理过的 default 主题
if (path === defaultPath) continue;
// 从路径中提取主题名称 (e.g., './themes/default.js' -> 'default')
const themeName = path.replace('./themes/', '').replace('.js', '');
// 获取模块的默认导出 (即主题配置对象)
if (themeModules[path].default) {
themes[themeName] = themeModules[path].default;
}
}
// --- Color Manipulation Helpers ---
/** Converts HEX color to RGB object */
function hexToRgb(hex) {
let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
/** Converts RGB object to HEX color */
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
}
/** Mixes two colors (RGB objects) */
function mixColors(rgb1, rgb2, weight) {
weight = Math.max(0, Math.min(1, weight));
let w1 = weight;
let w2 = 1 - weight;
return {
r: Math.round(rgb1.r * w1 + rgb2.r * w2),
g: Math.round(rgb1.g * w1 + rgb2.g * w2),
b: Math.round(rgb1.b * w1 + rgb2.b * w2)
};
}
// --- End Color Helpers ---
// Helper function to apply display mode
export function applyDisplayMode(mode) {
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
let darkModeEnabled = false;
if (mode === 'dark') {
darkModeEnabled = true;
} else if (mode === 'system') {
darkModeEnabled = prefersDark;
} // else mode === 'light', darkModeEnabled remains false
if (darkModeEnabled) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
// --- Modified setTheme Function ---
export function setTheme(themeName) {
// 确保 themeName 是字符串类型
const themeKey = typeof themeName === 'string' ? themeName : 'default';
const theme = themes[themeKey] || themes.default // Fallback to default
if (!theme) {
console.error(`Theme "${themeKey}" not found.`);
return;
}
const root = document.documentElement
const white = { r: 255, g: 255, b: 255 }; // RGB for white
const black = { r: 0, g: 0, b: 0 }; // RGB for black
// 设置主题色变量 (包括 primary 的派生色)
Object.keys(theme).forEach(key => {
const colorHex = theme[key];
if (!colorHex) return; // Skip if color is undefined
root.style.setProperty(`--el-color-${key}`, colorHex);
// Calculate and set shades/darken for primary color
if (key === 'primary') {
try {
const primaryRgb = hexToRgb(colorHex);
if (!primaryRgb) throw new Error('Invalid primary hex color');
// Set light shades (mix with white)
for (let i = 1; i <= 9; i++) {
const mixedRgb = mixColors(white, primaryRgb, i / 10);
root.style.setProperty(`--el-color-primary-light-${i}`, rgbToHex(mixedRgb.r, mixedRgb.g, mixedRgb.b));
}
// Set dark shade - dark-2 (mix with black, 20%)
const dark2Rgb = mixColors(black, primaryRgb, 0.2);
root.style.setProperty(`--el-color-primary-dark-2`, rgbToHex(dark2Rgb.r, dark2Rgb.g, dark2Rgb.b));
// Set dark shade - dark-1 (mix with black, 10%) - NEW
const dark1Rgb = mixColors(black, primaryRgb, 0.1);
root.style.setProperty(`--el-color-primary-dark-1`, rgbToHex(dark1Rgb.r, dark1Rgb.g, dark1Rgb.b));
} catch (error) {
console.error(`Failed to generate shades for primary color ${colorHex}:`, error);
}
}
// --- TODO: Optionally add shade generation for success, warning, danger, info here ---
// Example for success:
/*
else if (key === 'success') {
try {
const successRgb = hexToRgb(colorHex);
if (!successRgb) throw new Error('Invalid success hex color');
for (let i = 1; i <= 9; i++) {
const mixedRgb = mixColors(white, successRgb, i / 10);
root.style.setProperty(`--el-color-success-light-${i}`, rgbToHex(mixedRgb.r, mixedRgb.g, mixedRgb.b));
}
// Add dark-2 if needed
} catch (error) {
console.error(`Failed to generate shades for success color ${colorHex}:`, error);
}
}
*/
// Repeat for warning, danger, info if necessary based on your themes
});
// 设置主题类名
const currentThemeClass = Array.from(document.body.classList).find(cls => cls.startsWith('theme-'));
if (currentThemeClass) {
document.body.classList.remove(currentThemeClass);
}
document.body.classList.add(`theme-${themeKey}`);
}