refactor(详情页+S8): 详情页减重(导航互斥/入口去重/i18n去重) + 品牌标识入库
Regression / regression (push) Canceled after 0s

本提交含两条并行工作线,因互相咬合(package.json scripts、regression.yml、
npm run build 链)无法按文件干净拆分,故合并为一次自洽提交。

## 详情页减重(本轮主任务:修复「AI 干太重」)

- 导航收敛:宽屏只用右侧目录、≤1200px 只用页内 sticky 导航,纯 CSS 媒体查询
  实现(不引入 JS 宽度监听)。此前两套导航同时可见,active 状态互相打架。
- 入口去重:标题区由「查看示例/在线测试/契约 JSON」三个减为「在线测试」一个;
  契约 JSON 归入实现资源;删除示例底部重复的「在线测试」。
- 示例工具栏:删除与目录锚点重复的示例下拉选择器;「全部展开代码」只在
  示例数 >1 时出现(103 个组件里 49 个仅 1 个示例,此前恒显示)。
- 重复文案:示例区两句同义导语合并为一句。
- 首页 CTA 由 5 个减为 2 个(浏览组件/快速开始),测试总览入口挂到已有的
  通过率统计卡上,不再另占 Hero 按钮。
- 统一详情取数:抽出 fetchDetail/loadDetail 作为 details/*.json 的唯一路径,
  FAQ 不再自行 fetch 一遍,与组件页共用缓存与失败兜底。

## i18n

- 删除 12 组重复键(含整段 FAQ 说明),字典 604 → 585 唯一键。
- 删除本次改动产生的 6 个死键。
- verify-i18n.mjs 新增 `unique dictionary keys` 断言:重复键在对象字面量里
  是静默的后值覆盖,此前无从发现;现由门禁拦住。

## 文档事实修正(实测为准)

- TESTING/CONTRIBUTING:79 → 103 组件;旧断言数改为回指 tests/report.json。
- PLATFORMS:移动端 108 文件/18 端 → 282 文件/47 端;契约 5 → 47;
  令牌 17 → 15;uni-app SFC 21 → 50。
- AGENTS:断言 1405/18 页 → 1464/103 页(PC)、807/47 页(移动端)。
- package.json:YOUR-ACCOUNT 占位 → gitea 实址与 kole-ui.mymoyu.top。

## 品牌标识(并行会话成果,一并入库)

- brand-mark.json 收归真源,build:brand 生成 favicon 与单色 SVG;
  PC 与移动端共用资产,verify:brand 24 条断言。
- regression.yml 增加 verify:brand 步骤。

## 门禁与验收

新增工具:verify-component-page.mjs(86 条真实浏览器断言,随详情页改造同步
更新为「只允许一套导航可见」)、verify-brand-mark.mjs、lib/i18n-dead-keys.mjs
(只读诊断)。

回归:PC 100%(1464/1464,103 页,N/A 50)· 移动端 100%(807/807,47 页)。
门禁:component-page 86 · i18n 17 · brand 24 · routes all · smoke all ·
theme OK · isolation 31 · nav all · examples 9 · api-docs 10 · mobile-docs 12。

已知未做:i18n 另有约 44 条历史死键(非本次产生),已记为 ROADMAP S8-P6;
顶栏与悬浮区的两个主题入口为刻意设计(verify-theme 断言其互斥),未删。
This commit is contained in:
aurora-admin
2026-09-22 23:56:05 +08:00
parent f1fbfc2ddb
commit 5ee5d829a4
92 changed files with 1320 additions and 463 deletions
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env node
/**
* i18n-dead-keys.mjs — 精确列出「确定死亡」的字典键,供人工确认后删除。
*
* 判定分两档(避免误删用拼接方式消费的键):
* DEAD — 键串在 site/ 任何源文件(除 i18n.js)中都不出现,也不作为任何文件的子串。
* REVIEW — 键串只作为更长字符串的一部分出现(典型是 T('前缀') + x 拼出来的),
* 必须人工判断,工具不当作可删。
*
* 只读:不修改任何文件。
*/
import { readFileSync, readdirSync } from 'node:fs';
import { join, extname } from 'node:path';
const ROOT = join(import.meta.dirname, '..', '..');
const SITE = join(ROOT, 'site');
const i18n = readFileSync(join(SITE, 'i18n.js'), 'utf8');
const block = i18n.match(/var\s+EN\s*=\s*\{([\s\S]*?)\n\s*\};/);
if (!block) { console.error('FAIL: 没找到 EN 字典块'); process.exit(1); }
const keys = [];
const re = /^[ \t]*(["'])((?:\\.|(?!\1)[\s\S])*?)\1[ \t]*:/gm;
let m;
while ((m = re.exec(block[1])) !== null) keys.push(m[2].replace(/\\(["'])/g, '$1'));
/* 消费方:site 下的 js / html(i18n.js 本身除外);changelog.json、data.json 是构建产物,
其中的中文是历史记录,不代表 i18n 键被消费,故不纳入。 */
const consumers = readdirSync(SITE)
.filter((f) => (extname(f) === '.js' && f !== 'i18n.js') || extname(f) === '.html')
.map((f) => readFileSync(join(SITE, f), 'utf8'))
.join('\n');
const dead = [];
const review = [];
for (const key of keys) {
if (consumers.includes(key)) continue; // 精确命中:在用
/* 是否作为更长字符串的一部分出现 —— 拼接消费的迹象 */
const probe = key.length > 8 ? key.slice(0, 8) : key;
if (consumers.includes(probe)) review.push(key); // 疑似拼接消费,人工判断
else dead.push(key);
}
console.log(`字典 ${keys.length} 键 · 确定死亡 ${dead.length} · 待人工判断 ${review.length}\n`);
console.log('=== DEAD(键串在 site/ 源文件中完全不出现)===');
for (const k of dead) console.log(` ${k}`);
console.log('\n=== REVIEW(疑似以拼接方式消费,不要自动删)===');
for (const k of review) console.log(` ${k}`);