fix(ui,a11y): 修 logo 深色模式不可见 + 补 tailwind font-calligraphy 工具类
修复 A:header logo 深色模式字被吞 - logo.svg 右侧公司名(睿新致遠 + NOVALON)硬编码 fill='#0A0E14', 深色背景下 background 同色不可见,红色印章下书法字与英文全部被吞。 - 复用既有 logo-white.svg(白字 + 红印章)作为深色版, header 渲染双 <Image>,按 html[data-theme] CSS 显隐。 - 双 Image 不占位(display:none),零 JS 闪烁,未来主题切换器自动生效。 修复 B:font-calligraphy 工具类不生成 - tailwind.config.js 的 fontFamily 此前未声明 calligraphy key, 导致 font-calligraphy utility 永不生成,4 处装饰书法字 (BrandStamp「值得信赖」/ ChallengeSection「使命」/ WhyUsSection「睿」「我们」) 静默回退 sans。 - fontFamily 加 calligraphy: ['var(--font-calligraphy-system)']。 审计脚本: - logo-compare*.mjs:生产 vs 本地 logo 对比定位 - logo-dark-verify.mjs:明暗双版渲染验证 - font-calligraphy-verify.mjs:合成探针验证 utility 生效 验证: - type-check 0 error · lint 0 error(127 warnings 既有项与本次无关) - 深浅色 header 截图:明暗版正确切换,书法字 + NOVALON 清晰可见 - font-calligraphy 合成探针 computed fontFamily = STKaiti, KaiTi, 楷体, SimKai, serif ✓
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Logo 对比诊断:生产环境 vs 本地 dev
|
||||
*
|
||||
* 用法:node scripts/audit/logo-compare.mjs
|
||||
* 输出:dogfood-ui-audit/logo-compare/{prod,local}-header.png + logo-meta.json
|
||||
*/
|
||||
import { chromium } from 'playwright';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const OUT = path.join(process.cwd(), 'dogfood-ui-audit', 'logo-compare');
|
||||
fs.mkdirSync(OUT, { recursive: true });
|
||||
|
||||
const TARGETS = [
|
||||
{ tag: 'prod', url: 'https://www.novalon.cn/' },
|
||||
{ tag: 'local', url: 'http://127.0.0.1:3000/' },
|
||||
];
|
||||
|
||||
const browser = await chromium.launch();
|
||||
const meta = {};
|
||||
|
||||
for (const t of TARGETS) {
|
||||
const ctx = await browser.newContext({
|
||||
viewport: { width: 1440, height: 900 },
|
||||
deviceScaleFactor: 2,
|
||||
});
|
||||
const page = await ctx.newPage();
|
||||
const errors = [];
|
||||
page.on('requestfailed', r => errors.push('FAILED ' + r.url()));
|
||||
page.on('console', m => { if (m.type() === 'error') errors.push('CONSOLE ' + m.text()); });
|
||||
|
||||
try {
|
||||
await page.goto(t.url, { waitUntil: 'networkidle', timeout: 60000 });
|
||||
await page.waitForTimeout(1500);
|
||||
|
||||
// header logo 元素探测
|
||||
const info = await page.evaluate(() => {
|
||||
const imgs = [...document.querySelectorAll('img')]
|
||||
.filter(i => /logo/i.test(i.getAttribute('src') || ''));
|
||||
return imgs.map(i => {
|
||||
const r = i.getBoundingClientRect();
|
||||
const cs = getComputedStyle(i);
|
||||
return {
|
||||
src: i.getAttribute('src'),
|
||||
currentSrc: i.currentSrc,
|
||||
renderedW: Math.round(r.width),
|
||||
renderedH: Math.round(r.height),
|
||||
naturalW: i.naturalWidth,
|
||||
naturalH: i.naturalHeight,
|
||||
complete: i.complete,
|
||||
fontFamily: cs.fontFamily,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// 截 header 区域(放大到 logo 可见)
|
||||
const header = page.locator('header').first();
|
||||
await header.screenshot({ path: path.join(OUT, `${t.tag}-header.png`) }).catch(async () => {
|
||||
await page.screenshot({ path: path.join(OUT, `${t.tag}-header.png`), clip: { x: 0, y: 0, width: 1440, height: 80 } });
|
||||
});
|
||||
|
||||
meta[t.tag] = { url: t.url, logos: info, errors };
|
||||
console.log(`[${t.tag}] OK logos=${info.length} errors=${errors.length}`);
|
||||
for (const l of info) {
|
||||
console.log(` src=${l.src} currentSrc=${l.currentSrc}`);
|
||||
console.log(` rendered=${l.renderedW}x${l.renderedH} natural=${l.naturalW}x${l.naturalH} complete=${l.complete}`);
|
||||
}
|
||||
} catch (e) {
|
||||
meta[t.tag] = { url: t.url, error: e.message.slice(0, 200), errors };
|
||||
console.log(`[${t.tag}] FAILED ${e.message.slice(0, 120)}`);
|
||||
}
|
||||
await ctx.close();
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(OUT, 'logo-meta.json'), JSON.stringify(meta, null, 2));
|
||||
await browser.close();
|
||||
console.log('\n✓ 输出目录:' + OUT);
|
||||
Reference in New Issue
Block a user