Files
BYW-VoiceHub/fix-colors.mjs
T
Henry_Du 9fc5e3e607
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Canceled after 1m27s
fix(ui): 批量替换所有组件中残留的硬编码深色值以彻底支持浅色主题
2026-09-12 15:56:10 +08:00

129 lines
5.1 KiB
JavaScript

import fs from 'fs/promises';
import path from 'path';
async function walk(dir) {
const files = await fs.readdir(dir, { withFileTypes: true });
let results = [];
for (const file of files) {
const res = path.resolve(dir, file.name);
if (file.isDirectory()) {
results = results.concat(await walk(res));
} else if (file.name.endsWith('.vue')) {
results.push(res);
}
}
return results;
}
async function fixColors() {
const dirs = [path.resolve('app', 'components'), path.resolve('app', 'pages'), path.resolve('app', 'layouts')];
let files = [];
for (const dir of dirs) {
try {
files = files.concat(await walk(dir));
} catch (e) {
// Ignore if dir doesn't exist
}
}
for (const file of files) {
let content = await fs.readFile(file, 'utf-8');
let original = content;
// Generic regex for hardcoded grayscales in styles
const grayscales = {
'#000000': 'var(--bg-primary, #111111)',
'#000': 'var(--bg-primary, #111111)',
'#111111': 'var(--bg-primary, #111111)',
'#111': 'var(--bg-primary, #111111)',
'#1a1a1a': 'var(--bg-secondary, #1a1a1a)',
'#222222': 'var(--bg-tertiary, #222222)',
'#222': 'var(--bg-tertiary, #222222)',
'#2a2a2a': 'var(--bg-tertiary, #2a2a2a)',
'#333333': 'var(--bg-quaternary, #333333)',
'#333': 'var(--bg-quaternary, #333333)',
'#3a3a3a': 'var(--bg-quaternary, #3a3a3a)',
'#444444': 'var(--text-disabled, #444444)',
'#444': 'var(--text-disabled, #444444)',
'#666666': 'var(--text-quaternary, #666666)',
'#666': 'var(--text-quaternary, #666666)',
'#888888': 'var(--text-tertiary, #888888)',
'#888': 'var(--text-tertiary, #888888)',
'#999999': 'var(--text-tertiary, #999999)',
'#999': 'var(--text-tertiary, #999999)',
'#aaaaaa': 'var(--text-secondary, #aaaaaa)',
'#aaa': 'var(--text-secondary, #aaaaaa)',
'#cccccc': 'var(--text-secondary, #cccccc)',
'#ccc': 'var(--text-secondary, #cccccc)',
'#dddddd': 'var(--border-secondary, #dddddd)',
'#ddd': 'var(--border-secondary, #dddddd)',
'#eeeeee': 'var(--border-primary, #eeeeee)',
'#eee': 'var(--border-primary, #eeeeee)',
'#ffffff': 'var(--text-primary, #ffffff)',
'#fff': 'var(--text-primary, #ffffff)'
};
// We only want to replace inside <style> blocks.
const styleBlocks = content.match(/<style[^>]*>[\s\S]*?<\/style>/gi);
if (styleBlocks) {
for (const block of styleBlocks) {
let newBlock = block;
// Match CSS properties like background: #1a1a1a;
newBlock = newBlock.replace(/(background(-color)?|color|border(-color)?|border-(top|right|bottom|left)(-color)?|fill|stroke):\s*([^;}]*?)(#[0-9a-fA-F]{3,6})/gi, (match, p1, p2, p3, p4, p5, p6, hex) => {
const hexLower = hex.toLowerCase();
// Don't replace if it's already inside a var()
if (p6.includes('var(')) return match;
let replacement = hex;
if (grayscales[hexLower]) {
// Determine if it's a background, border, or text color
if (p1.startsWith('border')) {
replacement = `var(--border-secondary, ${hexLower})`;
} else if (p1.startsWith('background')) {
if (hexLower === '#ffffff' || hexLower === '#fff') {
replacement = `var(--card-bg, ${hexLower})`; // White background is usually a card
} else {
replacement = grayscales[hexLower].replace('text', 'bg'); // Force bg variables for background
}
} else if (p1 === 'color') {
if (['#000000', '#000', '#111111', '#111', '#1a1a1a', '#222222', '#222', '#2a2a2a'].includes(hexLower)) {
replacement = `var(--text-primary, ${hexLower})`;
} else {
replacement = grayscales[hexLower].replace('bg', 'text'); // Force text variables for color
}
} else {
replacement = grayscales[hexLower];
}
} else {
// Heuristic for unknown grayscales or dark colors
// Check if it's a dark shade (e.g. #040e15, #242f38)
if (p1.startsWith('background') && match.match(/#0[0-9a-f]{5}/i)) {
replacement = `var(--bg-secondary, ${hexLower})`;
} else if (p1.startsWith('background') && match.match(/#1[0-9a-f]{5}/i)) {
replacement = `var(--bg-secondary, ${hexLower})`;
} else if (p1.startsWith('background') && match.match(/#2[0-9a-f]{5}/i)) {
replacement = `var(--bg-tertiary, ${hexLower})`;
} else if (p1.startsWith('border') && match.match(/#[1-4][0-9a-f]{5}/i)) {
replacement = `var(--border-secondary, ${hexLower})`;
}
}
return `${p1}: ${p6}${replacement}`;
});
content = content.replace(block, newBlock);
}
}
if (content !== original) {
await fs.writeFile(file, content, 'utf-8');
console.log('Fixed', file);
}
}
}
fixColors().catch(console.error);