Files
Jyotisha/docs/tasks/TASK-settings-dialog-size-and-nav-20260915.md
T
Jesse_ChenandClaude Fable 5 4c002a084e docs(tasks): brief the settings dialog size recurrence and the nav emphasis bar
BUG-698 复发自 BUG-554。四个分区确实都映射到 .settings-modal,CSS 里
width 与 height 也都写了——但 .settings-modal 的 height/max-height 只用
dvh,没有 vh 回退。不支持 dvh 时整条声明作废,height 退回 auto,高度改由
内容决定,正是「切分区就立马缩小」。全文件 18 处 dvh 只有 sidebar-provider
那一处配了回退,本仓自己知道这个写法。

BUG-554 的防复发「设置弹窗必须同时声明 width 与 height」拦不住这次:它
检查声明存在性,不检查声明是否生效;守它的断言也只是一句 CSS 文本匹配。
本单把防线换成「height 用 dvh 必须先写 vh 回退」的全文件契约测试。

首要嫌疑不等于已证实——本会话没有浏览器。任务 1.1 要求执行方先量四个分区
的 getBoundingClientRect 并确认 height 是否被划掉,量不出来就转 investigating
交回产品,不得盲改。

另去掉设置分区菜单的左侧强调条(移动端下边框同理)。删之前必须先拆开选中态
与悬停态——它们共用同一条声明,色条是当前唯一的区分。左侧会话列表的 2px 色条
本轮保留,口径暂时不一致已授权。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 04:56:45 +00:00

261 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASK · 设置弹窗尺寸随分区变化(BUG-698,复发自 BUG-554)+ 分区菜单去掉强调条
- 日期:2026-09-15
- 基线 commit:`origin/staging` @ `6c748d86`
- 执行分支:`codex/settings-dialog-size-and-nav-20260915`
- 工作树:`.worktrees/settings-dialog-size-and-nav-20260915`
- 线上状态:staging 当前部署 `8d56d0ab`(早于本基线两轮实现提交,但**晚于** BUG-554 的修复 `dc6598d7`)。用户现象是在已含 BUG-554 修复的版本上复现的。
---
## 1. 产品诉求(原话)
> 设置面板的弹窗大小不一样,选别的就立马缩小了。而且菜单项不要加粗左边框的强调条。
两件事:任务 1 是缺陷(BUG-698),任务 2 是产品决策。
---
## 2. 事故实证
行号会漂移,定位以符号名为准。核对于 `origin/staging@6c748d86`。
### 2.1 这是 BUG-554 的复发
`docs/BUG_HISTORY.md` → **BUG-554 | 设置弹窗随分区跳变,星盘资料铺开整张表单,账户与点数离开首页**(resolved,修复版本 `dc6598d7`):
- 当时的用户现象第一句就是「三个设置分区弹窗尺寸不同」。
- 当时的根因:`accountDialogClasses` 给每个分区不同宽度,高度随内容撑开。
- 当时的修复:四个分区共用 `.settings-modal` 固定尺寸。
- 当时的防复发:**「设置弹窗必须同时声明 width 与 height」**。
现在 `frontend/src/lib/home-types.ts` → `accountDialogClasses` 的四个分区确实都是 `"settings-modal"`,`globals.css` 里也确实同时声明了 width 与 height:
```css
.settings-modal { width: min(100vw - 32px, 880px); height: min(84dvh, 640px); max-height: min(84dvh, 640px); overflow: hidden; display: grid; grid-template-rows: auto 1fr; }
```
**防复发措施仍在,现象仍复现。** 说明那条防复发写错了层次——它防的是「有没有写 height」,防不住「写了但没生效」。
守着它的测试也只是一句文本匹配,`frontend/tests/account-dialog-overlay.test.ts`:
```js
assert.match(styles, /\.settings-modal \{[^}]*width:[^}]*height:/);
```
它读的是 CSS 源文本,既不渲染也不量盒子,所以声明只要存在就绿。
### 2.2 首要嫌疑:`dvh` 没有 `vh` 回退,不支持时整条 `height` 被丢弃
`.settings-modal` 的 `height` 与 `max-height` 都只写了 `dvh`,**没有 `vh` 回退**。浏览器遇到不认识的单位会**整条声明作废**,于是:
- `height: min(84dvh, 640px)` 作废 → `height` 回到 `auto` → **高度由内容决定**
- `max-height: min(84dvh, 640px)` 作废 → 落回 `.account-modal` 的 `max-height: min(84dvh, 760px)` → **同样作废** → 没有任何高度约束
结果正好是用户描述的:内容多的分区高,内容少的分区矮,**切分区就立刻变大小**。而 width 用的是 `100vw`,不受影响——所以看上去是「高度在跳,宽度没动」。
**这个仓库自己知道要写回退**,`globals.css` 里就有一处标准写法:
```css
.group\/sidebar-provider[data-viewport] { height: 100vh; height: 100dvh; min-height: 0; overflow: hidden; }
```
全文件 18 处 `dvh` 声明,**只有这一处配了 `vh` 回退**。`.settings-modal` 是其中后果最严重的一处,因为它是唯一一个「固定高度就是功能本身」的面板。
⚠️ **这是首要嫌疑,不是已证实的根因。** 会话环境没有浏览器,无法实测。执行方**必须先复现并确认**,见任务 1.1。若实测发现 `dvh` 正常生效、尺寸仍在变,按 1.2 继续排查,**不得直接把回退当作修复交付**。
### 2.3 分区菜单的强调条
`frontend/src/app/globals.css`:
```css
.settings-dialog-nav-item:hover,
.settings-dialog-nav-item[aria-current="page"] { background: var(--color-canvas-muted); color: var(--color-ink); }
.settings-dialog-nav-item[aria-current="page"] { box-shadow: inset 2px 0 0 var(--color-action); }
```
移动端(`@media (max-width: 767px)`,导航变成顶部四栏)是同一条的下边框版本:
```css
.settings-dialog-nav-item[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--color-action); }
```
产品要去掉的就是这两条 `box-shadow`。
**去掉之后有一个必须同时解决的问题**:选中态与悬停态**共用同一条规则**(上面第一条),强调条是当前唯一区分它们的东西。直接删 `box-shadow` 会让「鼠标划过某项」和「当前就在某项」长得一模一样。任务 2 必须把这两态拆开。
---
## 3. 决策记录(产品已授权)
1. **去掉设置分区菜单的左侧强调条**(移动端的下边框同理)。选中态改用面(背景)与墨色等级表达,不用色条。
2. 这条**只针对设置弹窗的分区菜单**。左侧会话列表当前会话的 2px 色条(`--sidebar-ring`,见 `frontend/DESIGN.md`「Where the action color appears」第 2 条)**本轮不动**。改完两处观感会不一致,产品知情并接受;若之后也要去掉,另开一轮。
3. **不要用加粗(`font-weight`)来区分选中态。** 产品原话就是不要"加粗"的强调;`frontend/DESIGN.md` 也写明导航层级来自墨色等级而不是色相。
4. 尺寸问题按缺陷处理,占 **BUG-698**,并在记录里写明复发自 BUG-554、旧防复发为何没拦住。
---
## 4. 硬红线
1. `./node_modules/.bin/tsc --noEmit` 0 错;`npm run lint` **0 error**。
2. 测试总数不得低于开工时 `origin/staging` 的实测;改既有断言写「原值 / 新值 / 原因」三栏。
3. **BUG-554 的其余防复发条款继续有效,不得顺手破坏**:星盘资料默认视图不得无条件渲染 `<form`;`/` 保持 `○ Static`,不得 `useSearchParams`;收银台仍 `window.open`;硬跳转清单不得变长。
4. 不得改 `accountDialogClasses` 让四个分区重新用不同的类——那正是 BUG-554 的原始根因。
5. 不得动 admin(antd + Refine)。
6. 不得顺手升级依赖。
7. 改 UI 的同一提交内更新 `frontend/DESIGN.md`。
---
## 5. 任务分解
### 任务 1 · BUG-698:设置弹窗尺寸随分区变化
**1.1 先复现并确认机制(不得跳过)**
1. 起本地 dev,登录,打开设置弹窗,在四个分区之间来回切:个人资料 → 星盘资料 → 账户与点数 → 通用设置。
2. 用 DevTools 量 `section.account-modal.settings-modal` 的 `getBoundingClientRect()`,四个分区各记一次。
3. 在 Computed 面板看 `height` 与 `max-height` 的**计算值**,以及 Styles 面板里 `.settings-modal` 的 `height` 声明**有没有被划掉**。
4. 把四组数字和结论写进 PROGRESS。
- **若 `height` 被划掉 / 计算值为 `auto`** → §2.2 成立,做 1.2。
- **若 `height` 正常生效、盒子四个分区一致** → 说明用户看到的是别的东西(例如内容在固定盒子里塌成一小块、或某个分区的内容把 `overflow: hidden` 顶破)。**此时不要硬改 CSS**,把量到的数字和截图写进 PROGRESS,本任务转 `investigating`,由产品补充现象(哪两个分区、什么浏览器、窗口多大)后再开一轮。
**1.2 修复:给固定高度补 `vh` 回退**
按仓库既有写法(`.group\/sidebar-provider[data-viewport]` 那一行)补成两条声明,新值写在旧值之后:
```css
.settings-modal {
width: min(100vw - 32px, 880px);
height: min(84vh, 640px);
height: min(84dvh, 640px);
max-height: min(84vh, 640px);
max-height: min(84dvh, 640px);
…
}
```
同样处理同一批里**高度即功能**的几处,其余只写 `max-height` 的可以不动(作废后退化成无上限,不会让盒子随分区跳变):
- `.account-modal` 的 `max-height: min(84dvh, 760px)`
- 移动端 `.settings-modal { height: 100dvh }` 与 `.account-modal { max-height/min-height: 100dvh }`
**1.3 把防复发从「有没有写」升级成「量不量得到」**
现有断言只是文本匹配,挡不住本次复发。新增**两条**契约测试:
- **回退契约**:`globals.css` 中凡是在 `height`(非 `max-height`)里用了 `dvh` 的规则,同一规则内必须存在一条 `vh` 版本的同名属性声明,且 `vh` 在前。这条可以纯文本实现,覆盖全文件而不只是设置弹窗——它才是真正能防住下一次的那条。
- **同尺寸契约**:断言 `accountDialogClasses` 的四个设置分区映射到**同一个类名**(现有测试只验了 `dialogClass: "settings-modal"` 这一个分区的渲染)。
原有的 `assert.match(styles, /\.settings-modal \{[^}]*width:[^}]*height:/)` **保留**,但在它上面加注释说明它只是存在性检查、真正的防线是上面两条。
**验收标准(任务 1)**
- 1.1 的四组 `getBoundingClientRect()` 数字写进 PROGRESS,四个分区高度与宽度完全一致。
- 1.3 的两条新测试通过;故意把某处 `height: …dvh` 的回退删掉,回退契约测试必须变红(执行方本地验一次,结论写进 PROGRESS,不用把破坏提交上去)。
- 桌面与 375px 两种宽度下四个分区逐一切换,弹窗外框不跳变——**浏览器项**,写进 `docs/testing/`。
---
### 任务 2 · 分区菜单去掉强调条,并拆开选中态与悬停态
**2.1** 删除这两条:
```css
.settings-dialog-nav-item[aria-current="page"] { box-shadow: inset 2px 0 0 var(--color-action); } /* 桌面 */
.settings-dialog-nav-item[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--color-action); } /* 移动端 */
```
**2.2** 把现在共用的那条规则拆成两态。目标:选中比悬停"重"一档,且两者都不用强调色条、不用 `font-weight`。建议值(执行方可在同族 token 内微调,但必须给出选择理由):
```css
.settings-dialog-nav-item:hover {
background: color-mix(in srgb, var(--color-canvas-muted) 55%, transparent);
color: var(--color-ink-secondary);
}
.settings-dialog-nav-item[aria-current="page"] {
background: var(--color-canvas-muted);
color: var(--color-ink);
}
```
即:**悬停是一层淡的面 + 次级墨;选中是实的面 + 主墨。** 与 `frontend/DESIGN.md`「Hierarchy inside the nav comes from ink rank, not hue」一致。
**2.3** 深色主题必须同样成立。`--color-canvas-muted` 与两级墨色在深色下都有定义,但 55% 混透明后与深色底的对比要复查;`frontend/tests/dark-theme-contract.test.ts` 若涉及新增 token 需同步。**不得引入新的字面色值。**
**2.4** 键盘可达性不受影响:`:focus-visible` 的描边规则不动。选中态不能只靠颜色——`aria-current="page"` 已经在 DOM 上,屏幕阅读器不受本改动影响,这一点在 PROGRESS 里写明即可。
**2.5** `frontend/DESIGN.md` 同提交更新:在导航/强调色一节写明「设置弹窗分区菜单不使用强调色条,选中与悬停靠面与墨色等级区分」,并写明**左侧会话列表的 2px 色条本轮保留**,两处口径暂时不同是已知且授权的。
**验收标准(任务 2)**
- `grep -n "inset 2px 0 0 var(--color-action)\|inset 0 -2px 0 var(--color-action)" frontend/src/app/globals.css` 在 `.settings-dialog-nav-item` 上下文无结果。
- 新增契约测试:`.settings-dialog-nav-item[aria-current="page"]` 规则内不含 `box-shadow`,且 `:hover` 与 `[aria-current="page"]` **不再共用同一条声明**(两者必须是各自独立的规则块)。
- 浅色与深色各看一遍,悬停与选中肉眼可区分——**浏览器项**,写进 `docs/testing/`。
---
### 任务 3 · 测试与文档
**3.1** 开工先量基线:
```
cd .worktrees/settings-dialog-size-and-nav-20260915/frontend
npm ci
npm test 2>&1 | tail -20 # pass / fail / tests 三个数字
```
**3.2** 文档:
- `docs/BUG_HISTORY.md` 新增 **BUG-698**,字段齐全。**「复发自」一栏必须写 `BUG-554`**,并在「根因」里写清旧防复发(「必须同时声明 width 与 height」)为何没拦住——它检查的是声明存在性,不是声明是否生效。同时回到 BUG-554 那条记录,在「防复发」末尾补一句指向 BUG-698 的修正。
- `frontend/DESIGN.md`:任务 2.5 的内容;另加一条 CSS 规则——**凡是 `height` 用 `dvh` 的地方必须先写 `vh` 回退**,并说明为什么(不支持时整条声明作废,固定高度会退化成内容高度)。
- `docs/testing/settings-dialog-20260915.md`:把任务 1 与 2 里标了「浏览器项」的条目写成可照做的清单。
- `CHANGELOG.md`:一条日期 + 一句话标题 + 要点。
- `docs/tasks/PROGRESS-settings-dialog-size-and-nav-20260915.md`。
---
## 6. 让步顺序
1. 任务 1.1 若复现不出尺寸变化,**转 `investigating` 并停在那里**,把量到的数字交回产品。不得为了"有交付"而盲改 CSS。
2. 任务 1.3 的回退契约测试若在全文件范围内误伤了合理写法(例如某处确实只能用 `dvh`),**缩小到 `height` 属性且排除已注释说明的例外**,例外清单写进测试文件头部注释。不得因为难写就退回原来的存在性断言。
3. 任务 2.2 的具体数值可调,但**必须让选中比悬停重一档**;调完在浅色与深色下都要能分辨。
4. **绝不让步**:不得让四个分区重新使用不同的类;不得用 `font-weight` 做选中态;不得引入字面色值;BUG-554 的其余防复发条款不得破坏。
---
## 7. 开工前置命令
```bash
cd /workspace/Jyotisha
git status -sb | head -1
git fetch origin --prune
git worktree add -b codex/settings-dialog-size-and-nav-20260915 \
.worktrees/settings-dialog-size-and-nav-20260915 origin/staging
cd .worktrees/settings-dialog-size-and-nav-20260915/frontend
npm ci
npm test 2>&1 | tail -20
./node_modules/.bin/tsc --noEmit
npm run lint
```
纯前端改动,不要求 `scripts/pre_work_check.py`。
交付:`git push origin HEAD:staging`,推完核对远端 SHA。
---
## 8. 串行与依赖
- 本单改 `frontend/src/app/globals.css`。`TASK-chat-reading-load-20260915` 与 `TASK-mobile-touch-and-breakpoints-20260915` 的实现已合入 `staging`(`8144fca2`、`6c748d86`),以 `6c748d86` 为基线即可,无需再等。
- 与那两轮改的是同一文件的不同区段,但**它们已经合入**,所以本单不与任何在途轮次并行。开工前仍按 `AGENTS.md` §3 确认状态板上没有新的「执行中」项在动这个文件。
---
## 9. BUG 编号
- 本单占用 **BUG-698**(任务 2 是产品决策,不占编号)。
- `origin/staging@6c748d86` 的当前最大号是 **BUG-697**(BUG-695~697 由触控与断点那轮占用)。
- 开工时仍需核对 `docs/BUG_HISTORY.md` 的当前最大号。