修复 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 ✓
56 lines
2.6 KiB
JavaScript
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); });
|