星盘页(T5.1): - 五个体系 tab 从五枚描边药丸改成顶栏下方一条下划线式 tab 行, flex-wrap: nowrap + 容器自身横滚,375px 下仍是一行;底线画在滚动 容器的 border 上,不随内容滚走。眉标(BUG-717 的成本与速度承诺) 原文保留,位置从 tab 行上方移到下方,让 tab 行直接接住 46px 顶栏。 - 分盘 chips 保留但降一级:去描边去卡面、caption 字号、三级色, 当前项只留浅底。它是一个 tab 内部的筛选器,不是第二层导航。 - 参数从「中宫叠卡(手机两行/桌面六行)+ 盘下重复卡 + media query 三选一」收成一张八行键值表。同一组事实原本画三遍,改一处要改三处。 .chart-page-center-card / -compact / -extra / .chart-page-params-below / .chart-page-boundary-desktop 五个类连同 767/768 开关块一并删除。 view.vedic.boundary 那句准确性边界句原文未动,紧跟在表下方,且 DOM 里从出现两次变成一次。 - 三张行星表(印度宿度 / 西洋相位 / 七政十一曜)全部包上横向滚动 容器,wrap 补 min-width: 0 —— 少了它 grid item 按内容定宽,表格会 撑宽页面而不是在自己盒子里滚动。原先只有第一张有 wrap。 星历页(T5.2): - 日期导航从三个并排等宽按钮改成居中的 ‹ 日期 ›:日期是主语,两枚 44px 箭头是把手。箭头字形 aria-hidden,可访问名仍是「前一天」 「后一天」,读屏不丢方向。 - 「今天」只在非今日时以文字按钮出现在日期下方;在今日时整个不渲染, 而不是渲染成禁用按钮——灰掉的按钮仍要被读、仍要被 Tab 跳过。 - 三段统一成同一套卡片:框从内容上移到段落,.ephemeris-panchanga 的 dl 网格原样保留。收尾句原文不变,但从底部第四张卡降为页尾一行小字。 两条既有断言改动,测试文件内就地写了原值/新值/原因,进度记录成表: 参数断点开关的三条断言换成「参数只有一张键值表且那五个类不再有规则」 (更强,且避开了原写法 indexOf 未命中后静默锚错断点块的陷阱); 「今天」在场的单状态断言拆成今日/非今日两状态并加断不出现 disabled。 测试总数 3350 → 3352,失败清单与基线逐条一致(31 条无 Docker 缺口)。 tsc 0 错;lint 0 error / 118 warning(与基线同数);/ /chart /ephemeris 渲染标记均保持 ○ Static,/reports 仍 ƒ;主 CSS gzip 36,745 → 36,788 (+0.12%)。行星表 375px 横滚、tab 行横滚、读屏播报无真机验收,已在 进度记录里如实写成环境缺口。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
179 lines
14 KiB
Markdown
179 lines
14 KiB
Markdown
# PROGRESS · 星盘 + 星历 R5
|
||
|
||
任务书:`docs/tasks/TASK-cend-surfaces-claude-alignment-20260916.md` 的 R5
|
||
执行方式:**直接执行模式**(subagent)
|
||
分支:`codex/cend-chart-eph-20260916`
|
||
基线:`origin/staging` = `50ce02c8`(R4 次级页外壳合入后)
|
||
BUG 段:不占用(产品改造,未发现真实缺陷)
|
||
|
||
---
|
||
|
||
## 开工基线实测
|
||
|
||
在 `50ce02c8` 干净检出、`npm ci` 之后实测:
|
||
|
||
| 项 | 基线值 |
|
||
|---|---|
|
||
| `tsc --noEmit` | 0 错 |
|
||
| `npm run lint` | 0 error / **118 warning** |
|
||
| `npm test` | tests **3350** · pass 3304 · fail **31** · skipped 15 |
|
||
| `next build` 路由标记 | `/` `○` · `/chart` `○` · `/ephemeris` `○` · `/reports` `ƒ` |
|
||
| 主 CSS chunk | 242,608 字节(gzip **36,745**) |
|
||
|
||
31 条失败全部是无 Docker 的既有缺口,清单落在 `/tmp` 基线文件,改后逐条对比。
|
||
|
||
---
|
||
|
||
## T5.1 · 星盘页
|
||
|
||
### 做了什么
|
||
|
||
| 任务书要求 | 做法 |
|
||
|---|---|
|
||
| 五个体系 tab 改顶栏下方下划线式 tab 行 | `.chart-page-tabs` 从「五枚描边药丸 + 可换行」改成一条 `flex-wrap: nowrap` + 自身横滚的下划线行,整行 1px 底线,当前项 2px 下划线。JSX 里眉标从 tab 行**之上**移到**之下**,让 tab 行直接接住 46px 顶栏 |
|
||
| 分盘 chips 保留、视觉降一级 | `.chart-page-chip` 从与 tab 共用的药丸规则里拆出来:去描边、去卡面、caption 字号、三级文字色,当前项只留一块浅底。触摸目标仍 44px |
|
||
| 参数收进统一键值表 | 新增 `chart-param-table.tsx`(由 `chart-param-lines.tsx` 改名而来),八行 `dl` 键值表。删除 `.chart-page-center-card` / `-compact` / `-extra` / `.chart-page-params-below` / `.chart-page-boundary-desktop` 五个类及其 767/768 开关块 |
|
||
| 边界句放表下方、文案一字不改 | `{view.vedic.boundary}` 直接跟在表后。改前 DOM 里它出现**两次**(一次给手机一次给桌面,靠 CSS 藏一个),现在只渲染一次。**句子本身是服务端字符串,没有被碰过** |
|
||
| 行星表加横向滚动容器 | `.chart-page-planet-table-wrap` 加 `min-width: 0`(缺它 grid item 按内容定宽,表格撑宽页面而不是滚动),表加 `min-width: 26rem`。**三张**表全部包上:印度盘宿度、西洋相位、七政十一曜(原来只有第一张有 wrap) |
|
||
|
||
眉标 `CHART_VIEW_COPY.eyebrow`(「主盘直接算 · 分盘按需 · 不消耗点数」,BUG-717)保留,只换了位置。
|
||
|
||
按需 layer 拉取(`onNeedLayer("chara"/"western"/"qizheng"/"varga")`)、`CHART_VIEW_COPY.waitingLayer` 等待文案、`waitingChart` / `waitingVarga` 全部未动,没有引入 spinner 或骨架。
|
||
|
||
### 顺带修掉的一处错位
|
||
|
||
`.chart-page-eyebrow` 原本同时吃 `.chart-page-body` 的 `padding-inline` 和 767 块里给它自己的一份,手机上比 tab 行多缩进一个 `--space-4`。眉标移到 tab 行下方后这个错位会直接看得见,所以把 `.chart-page-eyebrow` 从那条共享选择器列表里摘掉了——**只摘这一个选择器**,同列表里 R6 的 `.report-center-body` / `.report-center-message` 一个没动。
|
||
|
||
---
|
||
|
||
## T5.2 · 星历页
|
||
|
||
| 任务书要求 | 做法 |
|
||
|---|---|
|
||
| 日期导航改居中 `‹ 日期 ›` | 两枚 `size="icon"`(44px)箭头按钮夹住日期;箭头字形 `aria-hidden`,可访问名用 `EPHEMERIS_COPY.previousDay` / `nextDay`,读屏拿到的仍是「前一天」「后一天」 |
|
||
| 「今天」非今日时以文字按钮出现在日期下方 | `isToday ? null : <Button variant="ghost">`,在日期条下方 |
|
||
| `isToday` 时不出现禁用按钮 | 整个不渲染。改前是 `disabled={isToday}`,禁用按钮仍要被读屏读、仍要被 Tab 跳过 |
|
||
| 三个 section 统一成同一套卡片 | 框从内容上移到段落:`.ephemeris-section` 自己成为卡片,`.ephemeris-transits` / `.ephemeris-events` / `.ephemeris-panchanga-item` 交出各自的描边与卡面 |
|
||
| `.ephemeris-panchanga` 的 dl 网格保留 | 桌面 `repeat(5, ...)`、手机 `1fr` 两条规则原样保留(`viewport-breakpoint-contract` 与 `ephemeris-page` 两个测试都在守) |
|
||
|
||
**`.ephemeris-footer` 的处理(与任务书原文的差异,请复核)**:任务书 T5.2 写「底部 `.ephemeris-footer` 删除」。删掉的是那张**卡片**,`EPHEMERIS_COPY.footerNote`(「这一页是天象本身,不是对你的判断。」)**原文保留**,改挂成页尾一行 `.ephemeris-outro` 三级色小字。理由:该句是这一页的定性边界句(DESIGN §16「文案」条:这一页是天象本身,不得写运势结论),连句子一起删会丢掉一条口径;而既有测试 `copy stays factual` 也在断言它在场。若产品要的是连句子一起删,请回我,这是一行的事。
|
||
|
||
四个降级分支 `natalMissing` / `panchangaUnavailable` / `transitsUnavailable` / `eventsUnavailable` 文案与可达性未动;未登录 `.ephemeris-message` 分支未动。
|
||
|
||
---
|
||
|
||
## 被改的既有断言
|
||
|
||
两条,都在下面列清「原值 / 新值 / 原因」,测试文件里也就地写了同样的三行注释。**没有静默弱化**:两条改后都比改前严格。
|
||
|
||
### 1 · `tests/chart-page-view.test.tsx`
|
||
|
||
原测试名:`mobile width keeps two centre lines and moves the full parameter card below the chart`
|
||
新测试名:`the parameters are one key/value table, not a per-breakpoint duplicate`
|
||
|
||
| | |
|
||
|---|---|
|
||
| **原值** | 断 `@media (max-width: 767px)` 块里三个开关:`.chart-page-center-compact { display: block; }`、`.chart-page-center-extra { display: none; }`、`.chart-page-params-below { display: block; }` |
|
||
| **新值** | 断参数只有一张 `.chart-page-param-row` 网格表;并断上述五个类名(含 `.chart-page-center-card`、`.chart-page-boundary-desktop`)在整份 CSS 里**都不再作为规则出现** |
|
||
| **原因** | 原断言守的正是「同一组参数按断点画三遍」,而 T5.1 要求的就是把它收成一张表,断言无法原样保留。新断言更强:不只要求当前画法对,还禁止任何按断点复制参数的写法回来 |
|
||
|
||
附带:原写法本身有个陷阱——`globalStyles.indexOf(".chart-page-center-compact")` 未命中时返回 `-1`,`- 2000` 之后 `indexOf("@media ...", -2001)` 会从文件开头重新搜,**静默锚到无关的断点块上**。新写法走 `cssDeclarations()` / 选择器集合,不做偏移量切片。
|
||
|
||
同一文件新增一条测试 `the planet table scrolls inside its own box instead of widening the page`(断 `overflow-x: auto` + `min-width: 0` + 表 `min-width`,并断三个 tab 源文件里 `<table>` 数与 `<div wrap>` 数相等)。
|
||
|
||
### 2 · `tests/ephemeris-page.test.tsx`
|
||
|
||
| | |
|
||
|---|---|
|
||
| **原值** | `copy stays factual` 里一句 `assert.match(markup, new RegExp(EPHEMERIS_COPY.today))`,只在 `date === today` 这一种渲染下断言「今天」在场 |
|
||
| **新值** | 拆成独立测试 `今天 is absent on today and present off it, never disabled`:今日断「今天」**不**在场,非今日断在场,两个状态都断 `disabled=""` 不出现 |
|
||
| **原因** | T5.2 验收标准要求「在今日时不出现『今天』按钮,而不是出现一个禁用按钮」。原断言恰好只覆盖今日那一种情况,照搬会要求今日也渲染该按钮,与验收标准直接冲突。新断言覆盖两个状态并额外禁掉禁用态,严于原来 |
|
||
|
||
注:断言用 `/disabled=""/` 而不是 `/disabled/`——`Button` 的 Tailwind 类串里本来就含 `disabled:opacity-50`,后者恒真。
|
||
|
||
测试总数 3350 → **3352**(+2,均为新增,无删除)。
|
||
|
||
---
|
||
|
||
## 收尾验收对照
|
||
|
||
| 硬约束 | 结果 | 实测 |
|
||
|---|---|---|
|
||
| 1 · 只动 `chart-page/` `ephemeris/` 与 `.chart-page-*` / `.ephemeris-*` 区段 | ✅ | 见下「改了哪些文件」。`.rectification-*` / `.settings-*` / `.membership-*` / `.report-center-*` / `.personal-report-*` 一处未改;唯一触到的共享规则只摘掉了 `.chart-page-eyebrow` 一个选择器 |
|
||
| 2 · 按需 layer 行为不变、等待文案不换 spinner | ✅ | `onNeedLayer` 调用点与 `waitingLayer` / `waitingChart` / `waitingVarga` 逐字未动;`a pending western tab uses inline waiting copy instead of a spinner` 绿 |
|
||
| 3 · 四个降级分支文案与可达性不变 | ✅ | `EPHEMERIS_COPY` 未改任何字符串;四个分支渲染路径未动 |
|
||
| 4 · `CHART_VIEW_COPY.eyebrow` 保留 | ✅ | 保留,位置从 tab 行上方移到下方 |
|
||
| 5 · `tsc` 0 错 / `lint` 0 error,warning ≤ 118 | ✅ | tsc 0 错;lint 0 error / **118 warning**,与基线同数 |
|
||
| 6 · 失败清单与基线逐条一致 | ✅ | `diff base.txt new.txt` → **完全相同**;fail 仍 31 |
|
||
| 7 · 改断言写「原值/新值/原因」三行 | ✅ | 两条,测试文件里就地注释 + 上面成表 |
|
||
| 8 · `/chart` `/ephemeris` 保持 `○ Static`,`/` 保持 `○` | ✅ | 干净重建后 `/` `○` · `/chart` `○` · `/ephemeris` `○` · `/reports` `ƒ`,与基线逐个相同 |
|
||
| 9 · 同提交更新 `DESIGN.md`;新文案对照 VOICE | ✅ | §15 §16 重写,见下 |
|
||
| 10 · 不升级依赖、不修范围外 warning | ✅ | `package.json` / `package-lock.json` 未动 |
|
||
|
||
### 改完实测
|
||
|
||
| 项 | 基线 | 改后 | 差 |
|
||
|---|---|---|---|
|
||
| `tsc --noEmit` | 0 错 | **0 错** | — |
|
||
| `npm run lint` | 0 error / 118 warning | **0 error / 118 warning** | 0 |
|
||
| `npm test` | 3350 / fail 31 | **3352 / fail 31** | +2 tests,失败清单逐条一致 |
|
||
| `next build` | `/` `○` `/chart` `○` `/ephemeris` `○` `/reports` `ƒ` | **完全相同** | — |
|
||
| 主 CSS chunk | 242,608 B(gzip 36,745) | **242,576 B(gzip 36,788)** | 原始 −32 B(−0.013%),gzip **+43 B(+0.12%)**,在 ±2% 内 |
|
||
|
||
gzip 基线是把工作树还原到 `50ce02c8` 后**干净重建**量到的,不是估算。首次改后构建复用了缓存、`.next/static` 里留着基线那份 CSS,两次数字曾一模一样——发现后两边都 `rm -rf .next` 重量,上表是重量后的值。
|
||
|
||
### 改了哪些文件
|
||
|
||
```
|
||
frontend/src/app/globals.css (.chart-page-* / .ephemeris-* 区段)
|
||
frontend/src/components/chart-page/chart-page-view.tsx
|
||
frontend/src/components/chart-page/chart-param-lines.tsx → chart-param-table.tsx(改名 + 重写)
|
||
frontend/src/components/chart-page/chart-qizheng-tab.tsx
|
||
frontend/src/components/chart-page/chart-vedic-tab.tsx
|
||
frontend/src/components/chart-page/chart-western-tab.tsx
|
||
frontend/src/components/ephemeris/ephemeris-page.tsx
|
||
frontend/tests/chart-page-view.test.tsx
|
||
frontend/tests/ephemeris-page.test.tsx
|
||
frontend/DESIGN.md
|
||
docs/tasks/PROGRESS-cend-chart-eph-20260916.md
|
||
```
|
||
|
||
CSS 注释配平:改前改后都是 **84 / 84**。含花括号的注释 1 条,是 R4 留下的 `` `*-shell { padding-inline }` ``,本轮未碰;全部删改都走整段精确字符串替换,没有按逗号切选择器。
|
||
|
||
---
|
||
|
||
## 触发的让步顺序
|
||
|
||
**没有触发任何一条。** 让步顺序第 3 条(T5.1 的参数统一表:若合并后信息密度过高则退回保留 `.chart-page-center-card`)是本轮唯一相关的一条,没有用上——八行键值表在 ≥1024 与盘面左右并排、在窄屏是一张独立卡,没有出现密度问题。其余六条属于 R4 / R6 / R7 / R8。
|
||
|
||
---
|
||
|
||
## 环境缺口(不得记作「通过」)
|
||
|
||
本会话**无登录态、无 Chrome、无真实引擎返回**,以下全部只有静态与单测证据,浏览器级行为未验:
|
||
|
||
1. **行星表在 375px 宽下横向滚动、页面本身不横滚**(任务书环境缺口原文列明的一条)。已有的是 CSS 契约断言(`overflow-x: auto` + `min-width: 0` + 表 `min-width: 26rem`)与「三张表都包了 wrap」的源码断言,**不是真机滚动验收**。
|
||
2. **Tab 行在 375px 下横滚**(本轮新写法):五个 Tab 不折行靠 `flex-wrap: nowrap` + 容器横滚,同样只有静态证据。
|
||
3. **`‹ 日期 ›` 箭头按钮的读屏可访问名**:`aria-label` 存在有断言,实际读屏播报未验。
|
||
4. **切 tab 时按需 layer 的真实拉取**:`onNeedLayer` 调用点未改、单测覆盖渲染分支,但没有真实 `/api/varga_full`、`/api/western`、`/api/qizheng` 往返。
|
||
5. **五要素 / 行运 / 未来九十天三张卡在真实数据下的疏密**:fixture 是 golden,但卡片化后的实际观感未上真机。
|
||
|
||
以上第 1、2、3、5 条建议并进 `docs/testing/` 的人工清单,与 R4 的抽屉手势、R6 的报告目录、R7 的常驻条、R8 的弹窗尺寸一起走一次真机。
|
||
|
||
---
|
||
|
||
## 事故:误 pop 了 R6 会话的 stash(已完全恢复,但请知会)
|
||
|
||
量 gzip 基线时我用了 `git stash push` 把改动暂存、还原到 `50ce02c8` 重建,再 `git stash pop`。**stash 栈是整个仓库共享的一个 ref,不是每个 worktree 一份**——在我 push 与 pop 之间,`codex/cend-report-20260916`(R6)那个会话也 push 了一个 stash,于是我 pop 到的是**他们的** `r6-wip`,落进了我的工作树(`personal-report-center.tsx`、`personal-report-page.tsx`、两个 report 测试,以及他们那份 `globals.css`)。
|
||
|
||
处置:
|
||
|
||
1. 从 `git fsck --unreachable` 找回两个 stash commit:我的 `4c112c5b`(`r5-wip`)、R6 的 `40ff9a82`(`r6-wip`)。
|
||
2. `git stash store` 把 R6 的 `40ff9a82` **原样放回 stash 栈**(内容是 commit 对象,未被改写)。
|
||
3. 把误落进我工作树的 5 个文件还原成 `HEAD` 内容,工作树回到干净基线。
|
||
4. `git stash apply 4c112c5b` 取回我自己的改动,`git diff HEAD --stat` 与 stash commit 的 stat **逐行相同**(10 文件 / +336 −203)。
|
||
|
||
**没有任何 R6 的改动进入本分支的提交**(见上面「改了哪些文件」)。但请主会话转告 R6 会话:他们的 stash 位置变过,现在在栈上(`git stash list` 里的 `On codex/cend-report-20260916: r6-wip`),内容完整;直接 `git stash pop` 之前先确认自己的工作树是干净的。
|
||
|
||
教训,建议写进 `AGENTS.md` §3:**多 worktree 共享一个 stash 栈,禁止用 `git stash` 做临时还原**。要量基线就先提交,或另开一个一次性 worktree 构建,不要动共享的 stash。
|