Files
novalon-website/scripts/audit/logo-dark-verify.mjs
T
zhangxiang 2593599862 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 ✓
2026-09-02 11:23:47 +08:00

56 lines
2.6 KiB
JavaScript

// 验证 header logo 明暗双版:浅色应显示 logo.svg(黑字),深色应显示 logo-white.svg(白字)
// 用法:node scripts/audit/logo-dark-verify.mjs
import { chromium } from 'playwright';
const BASE = 'http://127.0.0.1:3000';
const OUT = 'dogfood-output/logo-dark-verify';
const shots = [];
async function run() {
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1280, height: 800 } });
const page = await ctx.newPage();
// 浅色(默认)
await page.goto(BASE, { waitUntil: 'networkidle' });
await page.waitForTimeout(800);
const lightSrc = await page.$eval('header img', (el) => el.getAttribute('src'));
const visibleLight = await getVisible(page);
await page.screenshot({ path: `${OUT}/header-light.png` });
shots.push({ theme: 'light', htmlDataTheme: await page.getAttribute('html', 'data-theme'), firstImgSrc: lightSrc, visible: visibleLight });
// 深色:设 localStorage 后 reload(与站点内联脚本一致)
await page.evaluate(() => localStorage.setItem('novalon-theme', 'dark'));
await page.goto(BASE, { waitUntil: 'networkidle' });
await page.waitForTimeout(800);
const visibleDark = await getVisible(page);
const darkSrc = await page.$eval('header img', (el) => el.getAttribute('src')).catch(() => 'N/A');
await page.screenshot({ path: `${OUT}/header-dark.png` });
shots.push({ theme: 'dark', htmlDataTheme: await page.getAttribute('html', 'data-theme'), firstImgSrc: darkSrc, visible: visibleDark });
await browser.close();
console.log(JSON.stringify(shots, null, 2));
// 断言:浅色无 data-theme 属性(null),可见 logo.svg;深色 data-theme=dark,可见 logo-white.svg
const lightOk = shots[0].visible === 'logo.svg' && shots[0].htmlDataTheme !== 'dark';
const darkOk = shots[1].visible === 'logo-white.svg' && shots[1].htmlDataTheme === 'dark';
console.log(`\n[assert] light shows logo.svg: ${lightOk}`);
console.log(`[assert] dark shows logo-white.svg: ${darkOk}`);
console.log(`[result] ${lightOk && darkOk ? 'PASS' : 'FAIL'}`);
}
// 返回当前实际可见(display !== none)的 logo img 的 src
async function getVisible(page) {
return page.evaluate(() => {
const imgs = Array.from(document.querySelectorAll('header img'));
const vis = imgs.filter((i) => {
const s = getComputedStyle(i);
return s.display !== 'none' && s.visibility !== 'hidden' && Number(s.opacity) > 0;
});
return vis.length ? vis[0].getAttribute('src') : 'NONE_VISIBLE';
});
}
run().catch((e) => { console.error(e); process.exit(1); });