Files
blog/.spec/specs/2026-11-02_blog-5h-content-social/tasks.md
T
wait4xandGLM-5.3 63c9c8ad4a feat(counts): 浏览/评论徽标接入文章与瞬间页,修同载双计(5h T4)
用户要「加一个访客数量、评论数量,采用类似于开源页面从 GitHub 移植过来的那个
眼睛图标」——落地为 ViewMeta 本地 SVG 徽标,无第三方图片依赖。

接入(op-artalk 车道):
- 文章详情页 reading/tech 两分支各挂一枚 mode="page"(两分支互斥,同页仅一处计数)
- ArtalkComments 顶部旧的纯文本 pv 行与自成一套的 bumpPv 脚本整段删除,改为
  readonly chip:评论区只读展示,不再各计一次
- 瞬间页顶部整页 pv 行同样改 chip;每条瞬间卡片底部为 readonly 徽标

组件修复(本人,op-artalk 实测揪出):
- **同载双计**:脚本既注册 astro:page-load 又立即调用 run(),首屏两者都会触发
  → 每元素 POST 两次、浏览量翻倍(实测 15→17→19 每载 +2)。加每元素一次性
  守卫后 1/2/3 每载 +1;软导航新元素仍照常计数
- **同页两枚数字差 1**:readonly 实例独立 GET 到的 pv 可能比计过数的少 1;
  改为同键存在 page 实例时 readonly 让位,由 page 实例回填同一份结果
- page 实例请求失败时释放兄弟自读,避免评论区永远停在「–」

验证: 构建 exit 0;E2E 37/37;Playwright 拦截对账——
      每载 POST=1、同页两枚徽标文本一致(101/101)、刷新后累计 2、
      接口全挂时两枚均显示占位「–」不报错

Spec: 2026-11-02_blog-5h-content-social (T4)

Co-authored-by: GLM-5.3
2026-11-02 20:29:44 +08:00

5.8 KiB
Raw Blame History

Phase 5h:内容表达能力与社交反馈 - 任务拆解

使用规则

  • boundary/verify 齐备;verify 只读断言;车道工作树开发禁 git,收编由 orchestrator 统一提交
  • 构建一律 export PATH="$HOME/.local/node/bin:$PATH"(Node 26)+ pnpm astro build
  • 契约先行:src/content.config.ts 与 public/admin/config.yml 由 orchestrator 先落契约(T1 时一并提交),车道不得再改这两个文件;需要新字段一律回报 orchestrator
  • E2E 口径:pnpm astro build → cp -a dist /tmp/dist-e2e → 用 18925 端口起快照服务 → E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs

阶段一:实现

  • T1 文章置顶(契约 + 排序 + 标记 + 后台)

    • claim: orchestrator
    • boundary: src/content.config.ts(postsSchema 加 pinned: z.boolean().optional(),posts/postsEn 共用)、src/components/PostList.astro(置顶优先排序 + pin 标记)、src/pages/archives/index.astro(排序)、src/components/pages/{HomePage,BooksPage}.astro(排序)、public/admin/config.yml(posts 集合 pinned 开关 + 中文 hint)、src/i18n/ui.ts(置顶标签)
    • verify: E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && grep -q "pinned" src/content.config.ts && grep -q "pinned" src/components/PostList.astro && grep -q "pinned" public/admin/config.yml
  • T2 瞬间富文本(字体可换 / 颜色可换 / 多形式)

    • claim: worker-one
    • boundary: src/components/pages/MomentsPage.astro(text 由纯文本 <p> 改为走 renderRich 净化+排版类管线,保留 inline 语义;空文本老数据零回归)、public/admin/config.yml 中 moments 集合 text 字段改 markdown widget + 提示可用排版类(仅在 orchestrator 提交的字段块内改 widget 类型,不改结构)、docs 提示留给 T7
    • verify: E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS" && grep -qE "renderRich|renderMarkdown" src/components/pages/MomentsPage.astro && python3 -c "import yaml;d=yaml.safe_load(open('public/admin/config.yml'));m=[c for c in d['collections'] if c['name']=='moments'][0];t=[f for f in m['fields'] if f['name']=='text'][0];assert t['widget']=='markdown',t"
  • T3 瞬间逐条评论(Artalk 独立 page_key + 折叠懒挂载)

    • claim: worker-one
    • boundary: 新增 src/components/MomentComments.astro(折叠 disclosure,展开时首次挂载 Artalk;page_key 约定 /moments/#<slug>,en 页同一 key 不分裂;评论数徽标复用 T4 的 ViewMeta 计数接口)、src/components/pages/MomentsPage.astro(每条卡片挂评论区)
    • verify: test -f src/components/MomentComments.astro && grep -q "MomentComments" src/components/pages/MomentsPage.astro && grep -q "moments/#" src/components/MomentComments.astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS"
  • T4 计数徽标(眼睛图标 = 浏览数,气泡图标 = 评论数)

    • claim: op-artalk
    • boundary: src/components/geek/ViewMeta.astro(契约组件,由 orchestrator 在 T1 提交时一并落盘,车道只消费不改语义)、src/components/ArtalkComments.astro(pv 小字行改为 ViewMeta,评论数取 comments?limit=1 的 count)、src/pages/archives/[...slug].astro、src/pages/en/archives/[...slug].astro(挂 ViewMeta)
    • verify: test -f src/components/geek/ViewMeta.astro && grep -q "ViewMeta" src/components/ArtalkComments.astro && grep -q "ViewMeta" src/pages/archives/[...slug].astro && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS"
  • T5 开源页重构(原生 GitHub 档案卡,去外链图依赖)

    • claim: op-gitea
    • boundary: 新增 src/components/geek/GithubProfile.astro(头像/名字/简介/关注者/总星标/语言占比,数据来自 projects.ts 与 GraphQL;零第三方图片与徽章)、src/lib/projects.ts(补统计聚合:followers/stars/language 汇总,失败降级不炸构建)、src/pages/opensource.astro、src/pages/en/opensource.astro(用 GithubProfile 替换 readme 渲染段;README 通道保留开关但默认 off 且标注不推荐)、content/site/opensource.yaml(注释说明 intro_from 现状)
    • verify: grep -q "GithubProfile" src/pages/opensource.astro && python3 -c "import re,pathlib;p=pathlib.Path('dist/opensource/index.html').read_text();bad=[u for u in ['img.shields.io','readme-typing-svg','github-readme-stats','streak-stats','komarev','github-readme-activity-graph'] if u in p];assert not bad,bad"
  • T6 关于页承接 README 的个人叙述

    • claim: op-gitea
    • boundary: content/site/about.yaml(新增 blocks:关于/兴趣 prose、站点与项目 linklist、Find Me 社交块;双语 zh/en;测试值不得留在文件里)、src/pages/about.astro 与 en(仅当块渲染需要时改,优先零改动)
    • verify: python3 -c "import yaml;d=yaml.safe_load(open('content/site/about.yaml'));types=[b['type'] for b in d.get('blocks') or []];assert 'prose' in types and ('linklist' in types or 'cards' in types),types" && E2E_BASE=http://127.0.0.1:18925 node tests/e2e.mjs 2>&1 | grep -q "37/37 PASS"
  • T7 写作模板示例文章 + 文档与 hint 收尾

    • claim: orchestrator
    • boundary: content/posts/writing-template.md、content/posts-en/writing-template.md(en 手写 locked:true 直译,不交给 TMT 重译)、docs/写作指南.md(模板用法 + 排版类清单去重指引)、docs/管理台.md(瞬间富文本/逐条评论/置顶/徽标说明)、public/admin/config.yml(moments text hint、posts pinned 已含)
    • verify: test -f content/posts/writing-template.md && test -f content/posts-en/writing-template.md && grep -q "pinned: true" content/posts/writing-template.md && grep -qE "font-kai|c-blue" content/posts/writing-template.md && grep -q "写作模板" docs/写作指南.md