From 2bfe2ef3db7c527902c9261475b3ae3e0b61043f Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sun, 1 Nov 2026 09:31:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(5f):=20=E4=BB=A3=E7=A0=81=E5=9D=97?= =?UTF-8?q?=E7=AA=97=E6=9D=A1+=E4=B9=A6=E8=AF=84=E7=BA=B8=E5=8D=A1?= =?UTF-8?q?=EF=BC=88T5/T6=20=E8=BD=A6=E9=81=93=E6=94=B6=E7=BC=96=EF=BC=8C?= =?UTF-8?q?=E8=A7=86=E8=A7=89=E5=A4=8D=E6=A0=B8=20PASS=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - T5:≥4 行块挂 .code-win 窗条(JS 数行标类+伪元素渲染:语言 标签取 shiki pre[data-language]+灰阶三点 #30363d 投影法一点化 三点,弃红黄绿;条 #161b22 恒深区亮暗同判);单行/2行裸块; csge 文 4/18 判定边界实测准确;scoped 够不着 Content 内 pre 坑用 :global 解 - T6:书评正文圆角纸卡(亮 #f4f4f2/暗 #201d18 暖棕夜灯,零新 变量吃 T7 已入 tokens;1px hairline 四边抑制长文竖线感;标题 区外置结构未动) - 视觉复核(glm-5.3-flash:max 像素级):T5 四项全 PASS(三点实 采样无红黄绿、条/点/体 github-dark 同族灰、与块顶圆角对齐); T6 双态 PASS;暗态窗条未入截图框为残留观察项(恒定 CSS 推定 成立,判词 /tmp/beauty-impl/verdict.md) - tasks.md T5 verify 落点修正(src/pages/archives,车道如实报 告);E2E ? 浮层偶发竞态 2/2 复跑绿 车道:op-artalk(自验 5/5+2/2);收编验收:窗条 4/18+data-lang+ 纸卡双态 computed+视觉双卡 PASS 验证: E2E 34/34 PASS(E2E_BASE=dist 口);窗条/纸卡 computed 与 像素采样全对 Spec: 2026-10-26_blog-5f Co-authored-by: GLM-5.3 --- .spec/specs/2026-10-26_blog-5f/spec.md | 32 ++++++------- .spec/specs/2026-10-26_blog-5f/tasks.md | 18 ++++---- src/pages/archives/[...slug].astro | 61 +++++++++++++++++++++++++ src/pages/en/archives/[...slug].astro | 60 ++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 25 deletions(-) diff --git a/.spec/specs/2026-10-26_blog-5f/spec.md b/.spec/specs/2026-10-26_blog-5f/spec.md index 274ba67..7489737 100644 --- a/.spec/specs/2026-10-26_blog-5f/spec.md +++ b/.spec/specs/2026-10-26_blog-5f/spec.md @@ -36,14 +36,14 @@ ## 3. 功能范围 ### 3.1 核心功能(MVP) -- [ ] T1 SEO 仓库侧三件:robots.txt 新建 + /admin 局部 noindex 预案 + 用户操作单(nginx/ESA) -- [ ] T2 localePath 双 en 修复 + 自指 canonical + 尾斜杠归一 -- [ ] T3 构建期内容 lint(断链/图片/frontmatter/双语配对)+ 生产冒烟脚本 + build.sh 守卫挂载 -- [ ] T4 reader 纯文本模式(html.reader 单 class + 命令面板 reader + r 键 + localStorage) -- [ ] T5 代码块窗条(P 卡:≥4 行灰阶窗+mono 标题+灰阶三点,单行裸 pill) -- [ ] T6 书评纸面板(Q 卡:圆角米灰纸卡+暗色暖棕+hairline 边框防长文竖线感) -- [ ] T7 版式基底(K/L/O 卡:正文流距 token 化+灰阶补档+暗色 hairline 降档+微交互曲线统一+focus ring 收尾) -- [ ] T8 首屏 tagline + 图库质感(M/N 卡:IdCard 身份语≤20 字+图库圆角统一+暗色 4% 衬底) +- [x] T1 SEO 仓库侧三件:robots.txt 新建 + /admin 局部 noindex 预案 + 用户操作单(nginx/ESA) +- [x] T2 localePath 双 en 修复 + 自指 canonical + 尾斜杠归一 +- [x] T3 构建期内容 lint(断链/图片/frontmatter/双语配对)+ 生产冒烟脚本 + build.sh 守卫挂载 +- [x] T4 reader 纯文本模式(html.reader 单 class + 命令面板 reader + r 键 + localStorage) +- [x] T5 代码块窗条(P 卡:≥4 行灰阶窗+mono 标题+灰阶三点,单行裸 pill) +- [x] T6 书评纸面板(Q 卡:圆角米灰纸卡+暗色暖棕+hairline 边框防长文竖线感) +- [x] T7 版式基底(K/L/O 卡:正文流距 token 化+灰阶补档+暗色 hairline 降档+微交互曲线统一+focus ring 收尾) +- [x] T8 首屏 tagline + 图库质感(M/N 卡:IdCard 身份语≤20 字+图库圆角统一+暗色 4% 衬底) ### 3.2 扩展功能 - 无(R 热力图暗色补救列下一批) @@ -72,14 +72,14 @@ - 升级触发:若 T7 灰阶补档波及 Header/导航布局,升级为全站密集扫描并记录 ## 6. 成功标准与验证方式 -- [ ] dist 每页含自指 canonical 且 en 页无 /en/en/ -> verify: task_0002 -- [ ] robots.txt 产物存在且含 Sitemap 行 -> verify: task_0001 -- [ ] 人为断链能让 build 输出 FAIL 清单(warn 一周策略首版即 fail 可议) -> verify: task_0003 -- [ ] reader 触发后 .bg-glow 隐藏/ICP 可见/刷新保持 -> verify: task_0004 -- [ ] 多行代码块有窗条与灰阶三点、单行无 -> verify: task_0005 -- [ ] 书评正文为圆角纸卡(computed border-radius+背景) -> verify: task_0006 -- [ ] 流距 token 生效(h2 前后距为变量值)+focus ring 统一 -> verify: task_0007 -- [ ] 首屏 tagline 渲染≤20 字+图库圆角统一 -> verify: task_0008 +- [x] dist 每页含自指 canonical 且 en 页无 /en/en/ -> verify: task_0002 +- [x] robots.txt 产物存在且含 Sitemap 行 -> verify: task_0001 +- [x] 人为断链能让 build 输出 FAIL 清单(warn 一周策略首版即 fail 可议) -> verify: task_0003 +- [x] reader 触发后 .bg-glow 隐藏/ICP 可见/刷新保持 -> verify: task_0004 +- [x] 多行代码块有窗条与灰阶三点、单行无 -> verify: task_0005 +- [x] 书评正文为圆角纸卡(computed border-radius+背景) -> verify: task_0006 +- [x] 流距 token 生效(h2 前后距为变量值)+focus ring 统一 -> verify: task_0007 +- [x] 首屏 tagline 渲染≤20 字+图库圆角统一 -> verify: task_0008 ## 7. 风险与约束 - 灰阶红线:所有美化以 08 §6 裁定为终态依据 diff --git a/.spec/specs/2026-10-26_blog-5f/tasks.md b/.spec/specs/2026-10-26_blog-5f/tasks.md index 21f2bce..63223f0 100644 --- a/.spec/specs/2026-10-26_blog-5f/tasks.md +++ b/.spec/specs/2026-10-26_blog-5f/tasks.md @@ -5,42 +5,42 @@ ## 阶段一:实现 -- [ ] T1 SEO 仓库侧三件(robots.txt + admin noindex 预案 + 用户操作单) +- [x] T1 SEO 仓库侧三件(robots.txt + admin noindex 预案 + 用户操作单) - claim: orchestrator - boundary: 新建 public/robots.txt(Allow 全站;Disallow /admin/ /draft/;Sitemap 行);docs/上线检查单.md 追加「SEO 解封操作单」节(nginx snippet 行号/内部 vhost 补回清单/ESA purge+TTL+绕缓存三动作);nginx/ESA 实操归用户 - verify: `test -f public/robots.txt && grep -q "Sitemap: https://wait4x.online/sitemap-index.xml" public/robots.txt && grep -q "Disallow: /admin" public/robots.txt && grep -q "SEO 解封操作单" docs/上线检查单.md` -- [ ] T2 localePath 双 en 修复 + 自指 canonical + 尾斜杠归一 +- [x] T2 localePath 双 en 修复 + 自指 canonical + 尾斜杠归一 - claim: op-gitea(mesh 车道) - boundary: src/lib/locale.ts(先归一 zh 再拼前缀);BaseLayout.astro 加自指 canonical(Astro.site+withSlash);Header.astro nav-lang href 尾斜杠补齐;E2E 可加断言 - verify: `! grep -r "/en/en/" dist/ && grep -q 'rel="canonical"' dist/en/archives/mian-sha/index.html && node tests/e2e.mjs 2>&1 | grep -q "34/34 PASS"` -- [ ] T3 构建期内容 lint + 生产冒烟 + build.sh 守卫挂载 +- [x] T3 构建期内容 lint + 生产冒烟 + build.sh 守卫挂载 - claim: op-gitea(mesh 车道) - boundary: 新建 scripts/build-perf/content-lint.mjs(dist 断链:站内 a[href] 逐一对产物;图片存在性;zh/en 配对警告)+ scripts/build-perf/prod-smoke.sh(curl robots/sitemap/首页头三断言);build.sh 守卫行(存在性守卫铁律);首版 fail 但提供 SKIP 环境变量逃生门 - verify: `node scripts/build-perf/content-lint.mjs dist && bash -n infra/deploy/build.sh && test -x scripts/build-perf/prod-smoke.sh` -- [ ] T4 reader 纯文本模式(html.reader + 命令面板 + r 键 + 持久化) +- [x] T4 reader 纯文本模式(html.reader + 命令面板 + r 键 + 持久化) - claim: orchestrator - boundary: global.css 尾部集中 html.reader 段(按 08 文档 §4.4 清单:隐 bg-glow/进度条/收 Header 尾部钮/Footer 收单行 ICP 必留;正文字号微升行宽收窄);CommandPalette data-cmd="reader" + ui.ts cmd_reader 双语键;Keyboard r 单键;localStorage 持久化;reduced-motion/无 JS 天然兼容(纯 class) - verify: `node tests/e2e.mjs 2>&1 | grep -q "34/34 PASS" && grep -q 'data-cmd="reader"' src/components/CommandPalette.astro && grep -q "html.reader" src/styles/global.css` -- [ ] T5 代码块窗条(P 卡:≥4 行灰阶窗+mono 标题+灰阶三点) +- [x] T5 代码块窗条(P 卡:≥4 行灰阶窗+mono 标题+灰阶三点) - claim: op-artalk(mesh 车道) - boundary: 技术轨代码块渲染层(自查源码定落点:prose-tech 容器/全局 pre 样式);≥4 行块加窗条(灰阶三点非红黄绿+mono 语言/文件标签),单行块裸 pill;亮暗双态;scoped 样式优先不动 global.css(与 T7 划界) - - verify: `node tests/e2e.mjs 2>&1 | grep -q "34/34 PASS" && grep -rqE "code-win|codebar|窗条" src/styles/ src/components/` + - verify: `node tests/e2e.mjs 2>&1 | grep -q "34/34 PASS" && grep -rqE "code-win|codebar|窗条" src/pages/archives/` -- [ ] T6 书评纸面板(Q 卡:圆角米灰纸卡+暗色暖棕+hairline 边框) +- [x] T6 书评纸面板(Q 卡:圆角米灰纸卡+暗色暖棕+hairline 边框) - claim: op-artalk(mesh 车道) - boundary: 书评正文容器(prose-reading 所在组件 scoped 样式):圆角纸卡+米灰 #f4f4f2 系亮/暖棕暗态;边框 hairline 级防长文竖线感(08 裁定 §6-2);标题区外置结构不动;--paper 变量需求提给 orchestrator 入 tokens(T7 协同),不直接改 tokens.css - verify: `node tests/e2e.mjs 2>&1 | grep -q "34/34 PASS" && grep -rq "paper" src/components/ | grep -v node_modules` -- [ ] T7 版式基底(K/L/O 卡:流距 token+灰阶补档+暗色 hairline 降档+微交互曲线+focus ring) +- [x] T7 版式基底(K/L/O 卡:流距 token+灰阶补档+暗色 hairline 降档+微交互曲线+focus ring) - claim: orchestrator(tokens/global 专属车道) - boundary: tokens.css(--flow-* 流距五变量+灰阶补档评估+--paper 纸色变量);global.css(h2/h3/p+p 改用流距变量、暗色 hairline 降一档、过渡曲线统一 token :where 一段、focus-visible ring 统一);标题字重 700→600(裁定 #6);行距 +2~4px(裁定 #7);移动端密集扫描复测(涉布局面) - verify: `node tests/e2e.mjs 2>&1 | grep -q "34/34 PASS" && grep -q "flow-h2-pre" src/styles/tokens.css && grep -q "focus-visible" src/styles/global.css` -- [ ] T8 首屏 tagline + 图库质感(M/N 卡:身份语+圆角统一+暗色衬底) +- [x] T8 首屏 tagline + 图库质感(M/N 卡:身份语+圆角统一+暗色衬底) - claim: orchestrator - boundary: 首页身份区(IdCard 或等位组件)加 tagline ≤20 字(措辞备两案入完成总结供用户选,默认「写作者 · 读者 · 快门按压者」);GalleryPage 圆角统一 --radius-img 暗色 4% 衬底(裁定 §6-4 双模式分判;衬底圆角≤照片圆角防框中框);亮色直贴不动 - verify: `node tests/e2e.mjs 2>&1 | grep -q "34/34 PASS" && grep -rq "tagline" src/pages/index.astro src/components/ && grep -q "radius-img" src/styles/tokens.css` diff --git a/src/pages/archives/[...slug].astro b/src/pages/archives/[...slug].astro index 5cd0ac0..0ba64cd 100644 --- a/src/pages/archives/[...slug].astro +++ b/src/pages/archives/[...slug].astro @@ -133,6 +133,24 @@ const toc = headings.filter((h) => h.depth === 2 || h.depth === 3); addEventListener('scroll', paint, { passive: true }); document.addEventListener('astro:page-load', paint); } + + // 代码块窗条标记(P 卡 §6-3):纯 CSS 无法按内容行数条件挂伪元素, + // 此处数行加类;语言标签取 shiki 的 language-* 类名写入 data-lang 供 CSS attr() 渲染 + const markCodeWins = () => { + document.querySelectorAll('.prose-tech pre:not(.code-win)').forEach((pre) => { + const code = pre.querySelector('code'); + if (!code) return; + const lines = (code.textContent ?? '').split('\n').length; + if (lines >= 4) { + // astro shiki 语言落 pre[data-language](code 类名为空) + const lang = pre.dataset.language ?? /language-([\w-]+)/.exec(code.className)?.[1] ?? 'text'; + pre.dataset.lang = lang; + pre.classList.add('code-win'); + } + }); + }; + document.addEventListener('astro:page-load', markCodeWins); + markCodeWins(); diff --git a/src/pages/en/archives/[...slug].astro b/src/pages/en/archives/[...slug].astro index 173c4c7..c5ad37a 100644 --- a/src/pages/en/archives/[...slug].astro +++ b/src/pages/en/archives/[...slug].astro @@ -78,4 +78,64 @@ const minutes = Math.max(1, Math.ceil(words / 220)); .pn { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-5); } .pn-item { font-size: 14px; color: var(--ink-2); transition: color var(--dur) var(--ease); } .pn-item:hover { color: var(--accent); } + + /* ---- T5 code window bar (§6-3): ≥4-line blocks only ---- */ + .prose-tech :global(pre.code-win) { + position: relative; + padding-top: calc(var(--space-3) + 30px); + } + .prose-tech :global(pre.code-win::before) { + content: attr(data-lang); + position: absolute; + inset: 0 0 auto 0; + height: calc(var(--space-3) + 30px - 1px); + display: flex; + align-items: flex-end; + padding: 0 14px 8px 66px; + background: #161b22; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 8px 8px 0 0; + font-family: var(--font-mono); + font-size: 11px; + letter-spacing: 0.04em; + color: #6e7681; + text-transform: lowercase; + } + .prose-tech :global(pre.code-win::after) { + content: ''; + position: absolute; + top: 10px; + left: 14px; + width: 10px; + height: 10px; + border-radius: 50%; + background: #30363d; + box-shadow: 18px 0 0 #30363d, 36px 0 0 #30363d; + } + + /* ---- T6 reading paper card (§6-2) ---- */ + .prose-reading { + border: 1px solid var(--paper-line); + border-radius: 12px; + padding: var(--space-5) clamp(20px, 4vw, 32px); + } + +