本提交含两条并行工作线,因互相咬合(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:
+20
-33
@@ -31,6 +31,7 @@ import {
|
||||
import { createHash } from 'node:crypto';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join, relative, sep } from 'node:path';
|
||||
import { generatedData, readBrandSpec, validateBrandSpec } from './lib/brand-mark.mjs';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(__dirname, '..');
|
||||
@@ -44,6 +45,18 @@ const TESTS = join(ROOT, 'tests', 'mobile');
|
||||
const WEBSITE = join(ROOT, 'site', 'm');
|
||||
const DIST = join(ROOT, 'dist', 'mobile');
|
||||
const PC_INDEX = join(ROOT, '.design_library', 'kole-ui', 'components', 'index.json');
|
||||
const BRAND_SPEC = readBrandSpec(ROOT);
|
||||
const BRAND_ERRORS = validateBrandSpec(BRAND_SPEC);
|
||||
if (BRAND_ERRORS.length) {
|
||||
throw new Error(`[build-mobile] 品牌图标规格无效:${BRAND_ERRORS.join(';')}`);
|
||||
}
|
||||
if (!existsSync(join(ROOT, 'site', 'assets', 'kole-mark.svg')) || !existsSync(join(ROOT, 'site', 'assets', 'kole-mark-mono.svg'))) {
|
||||
throw new Error('[build-mobile] 缺品牌 SVG 产物,请先运行 npm run build:brand');
|
||||
}
|
||||
const brandDataFile = join(ROOT, 'site', 'brand-mark.generated.json');
|
||||
if (!existsSync(brandDataFile) || JSON.stringify(JSON.parse(readFileSync(brandDataFile, 'utf8')), null, 2) + '\n' !== JSON.stringify(generatedData(BRAND_SPEC), null, 2) + '\n') {
|
||||
throw new Error('[build-mobile] brand-mark.generated.json 与品牌规格不同步,请先运行 npm run build:brand');
|
||||
}
|
||||
|
||||
/** 允许写入的前缀(相对仓库根,POSIX 风格) */
|
||||
const ALLOWED_PREFIXES = ['site/m/', 'tests/mobile/', 'dist/mobile/'];
|
||||
@@ -327,37 +340,10 @@ function tokensOf(slug) {
|
||||
平台切换**不在顶栏**:PC 顶栏也没有它 —— 两端的唯一入口都是左栏「平台」组。
|
||||
2026-09-20 去重:此前顶栏另有一个 [PC 端][移动端] 胶囊,与左栏指向同一跳转
|
||||
(实测两条链接 href 均为 ../index.html),是重复入口,已删。 */
|
||||
/* ---------- 品牌标识(与 PC 站同源几何)----------
|
||||
几何真源:24 网格三个互不接触的笔画组成的 K。同一份路径同时用于:
|
||||
① favicon(BRAND_FAVICON,内联 data-URI)
|
||||
② 两端顶栏标记(BRAND_MARK_*,内联 SVG,走 currentColor)
|
||||
描边 2.25 @24 网格 → 16px 下正好 1.5px,等于规范原文「线性图标,描边1.5px」
|
||||
(.design_library/kole-ui/specs/组件1.txt)。
|
||||
favicon 里硬编码品牌蓝/白而不用令牌:它渲染在**浏览器标签栏**,不继承 html.kole-dark;
|
||||
顶栏标记必须走 currentColor 才会随主题令牌反色 —— 两者分工不同,不要混。 */
|
||||
const BRAND_PATHS = [
|
||||
'M7 5.5V18.5',
|
||||
'M17 5.5l-6.25 4.06',
|
||||
'M10.75 14.44L17 18.5',
|
||||
]
|
||||
.map((d) => `<path d="${d}"/>`)
|
||||
.join('');
|
||||
const BRAND_SW = '2.25';
|
||||
/* 移动端顶栏盒 26×26(PC 是 32×32 / 20px 标记),标记取 17px 保持同视觉重量 */
|
||||
const BRAND_MARK = `<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="${BRAND_SW}" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${BRAND_PATHS}</svg>`;
|
||||
const BRAND_FAVICON = (() => {
|
||||
const svg =
|
||||
`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'>` +
|
||||
`<rect width='24' height='24' rx='6' fill='#2F54EB'/>` +
|
||||
`<g fill='none' stroke='#FFFFFF' stroke-width='${BRAND_SW}' stroke-linecap='round' stroke-linejoin='round'>` +
|
||||
BRAND_PATHS.split('"').join("'") +
|
||||
`</g></svg>`;
|
||||
/* 与 site/index.html 的 favicon 同编码规则:只转义 < > 空格 #,属性单引号原样 */
|
||||
return (
|
||||
'data:image/svg+xml,' +
|
||||
svg.replace(/</g, '%3C').replace(/>/g, '%3E').replace(/ /g, '%20').replace(/#/g, '%23')
|
||||
);
|
||||
})();
|
||||
/* ---------- 品牌标识(brand-mark.json 唯一真源)----------
|
||||
移动端静态页使用相对站点根的独立 SVG favicon;顶栏标记由 site/m/style.css
|
||||
以同一规格生成的单色 SVG mask 渲染。这样构建器不再复制或拼接一套几何路径。 */
|
||||
const BRAND_FAVICON_HREF = '../assets/kole-mark.svg';
|
||||
|
||||
function headerHtml(activeKey, isComp) {
|
||||
const toRoot = isComp ? '../' : '';
|
||||
@@ -370,7 +356,7 @@ function headerHtml(activeKey, isComp) {
|
||||
return ` <header class="m-top">
|
||||
<div class="m-top-inner">
|
||||
<a class="m-logo" href="${toRoot}index.html">
|
||||
<span class="m-logo-mark" aria-hidden="true">${BRAND_MARK}</span>
|
||||
<span class="m-logo-mark" data-brand-mark="mono" aria-hidden="true"></span>
|
||||
<span class="m-logo-text">Kole UI<em>移动端</em></span>
|
||||
</a>
|
||||
<div class="m-ver-picker" id="m-ver-picker">
|
||||
@@ -856,11 +842,12 @@ function renderSitePage(templateName, repl) {
|
||||
__BRAND_HEAD__ 由模板放在 <head> 里(本站此前完全没有 favicon,浏览器标签页是
|
||||
默认地球图标);theme-color 取 --kole-color-card-bg —— .m-top 的 background 就是它。 */
|
||||
function shellRepl(activeKey, isComp) {
|
||||
const faviconHref = isComp ? '../../assets/kole-mark.svg' : BRAND_FAVICON_HREF;
|
||||
return {
|
||||
__HEADER__: headerHtml(activeKey, isComp),
|
||||
__THEME_BOOT__: THEME_BOOT,
|
||||
__BRAND_HEAD__: [
|
||||
`<link rel="icon" href="${BRAND_FAVICON}">`,
|
||||
`<link rel="icon" href="${faviconHref}">`,
|
||||
'<meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)">',
|
||||
'<meta name="theme-color" content="#1C1F26" media="(prefers-color-scheme: dark)">',
|
||||
].join('\n'),
|
||||
|
||||
Reference in New Issue
Block a user