151 lines
5.3 KiB
JavaScript
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}`);
|
|
}
|