Files
Jyotisha/docs/tasks/TASK-site-button-contrast-20260928.md
T

123 lines
11 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 · 全站实心按钮配色与禁用态统一(2026-09-28)
## 基线
- `origin/staging` = `b3b5f0e1`(2026-09-28)。开工时 `git fetch origin --prune`,以最新 `origin/staging` 为基线,实际 SHA 写进 PROGRESS。
- 分支 `codex/site-button-contrast-20260928`,工作树 `.worktrees/site-button-contrast-20260928`。
- 进度记录 `docs/tasks/PROGRESS-site-button-contrast-20260928.md`。
- 前置:`TASK-chart-types-and-report-buttons-20260928`(BUG-1078,报告页局部修复)已部署 staging `6a4e312c`。本单**取代**它的局部覆盖,改成全站一处定义。同日其它任务书与本单无文件交集;`frontend/src/app/globals.css` 只动本单列出的规则。
## 事故实证(Claude 2026-09-28 全站扫描)
方法:TypeScript AST 列出 `frontend/src` 里全部 213 个 `<Button>` / `<button>`,再把 staging 线上实际下发的 CSS(`/_next/static/chunks/*.css`)装进无头 Chrome,深浅两种主题逐一读计算样式、按叠加后的颜色算对比度。脚本已随本单提交:`docs/testing/button-contrast-harness.cjs`。
| 样本 | 浅色 文字 / 底 / 对比 | 深色 文字 / 底 / 对比 |
| --- | --- | --- |
| `<Button>` 默认实心 | `#1d1d1f` / `#a9583e` / **3.33** | `#f2f0ea` / `#d78064` / **2.57** |
| `<Button>` 默认 · 禁用 | 45% 透明 / **1.49** | 45% 透明 / **1.83** |
| `.button-primary` | `#fbfaf7` / `#cc785c` / **3.14** | `#241f1c` / `#d78064` / 5.56 |
| `.button-primary` · 禁用 | 45% 透明 / **1.61** | 45% 透明 / **2.20** |
| `.danger-primary` | `#fbfaf7` / `#9a2f2f` / 7.13 | `#241f1c` / `#e08573` / 6.04 |
| 输入框发送键 | `#fbfaf7` / `#cc785c` / 3.14 | `#241f1c` / `#d78064` / 5.56 |
| 报告页 `<Button>`(BUG-1078 已修) | `#fbfaf7` / `#a9583e` / 4.85 | `#f2f0ea` / `#8f4a33` / 5.77 |
| 描边 / 次要按钮 | 16.12 | 13.30 |
受影响范围:
- **实心 `<Button>`,渲染为真 `<button>` 的共 63 个**(渲染为链接 `<a>` 的不受影响),其中报告页 2 个已由 BUG-1078 修好,**未修 61 个**:后台管理 52、点数 / 订阅面板 3、星历 2、生时校正对话 2、输入框发送 / 停止键 2(这两个另有 `.composer` 层外规则上色,见下)。日期选择器选中日(`calendar.tsx` 的 `bg-primary text-primary-foreground`,`birth-date-picker.tsx` 用 `!` 强行救回了一处)同病。
- **`.button-primary` 共 30 个**:登录 7、首次引导 3、人物档案 3(含 2 个 `.danger-primary`)、首页 2、生时校正各卡 11、兑换码付费墙 2、星盘资料表单 1、首页错误屏 1。
- **禁用态**:全部 213 个按钮都被 `button:disabled { opacity: .45 }` 整体淡化。
- 其它自定义按钮类(`.button-secondary`、会话列表、Tab、chip 等)逐条算过,均 ≥ 4.5。
## 根因(按符号定位,基线 `b3b5f0e1`)
1. `frontend/src/app/globals.css` 顶部元素规则 `button { color: inherit; }`、`button:disabled { cursor: default; opacity: .45; }` **不在任何 `@layer` 里**。Tailwind v4 的工具类(`text-primary-foreground`、`disabled:opacity-50`)都在 `@layer utilities`;层外规则一律压过层内规则,与选择器权重无关。所以 `<Button>` 的文字色永远是继承来的正文色:浅色是近黑,深色是近白。Tailwind 预检(preflight)在 `@layer base` 里本来就给 `button` 设了 `color: inherit`,这条层外规则是重复的。
2. `.button-primary` 与发送键用 `--color-action-strong`(`#cc785c`)作底,文字用 `--color-on-dark`。深色主题把 `--color-on-dark` 翻成 `#241f1c`,于是深色下是深字配珊瑚底,浅色下是白字配浅珊瑚(3.14)。`frontend/DESIGN.md`「Where the action color appears」写明这是产品曾接受的已知缺口("looks like Claude")。
3. 两套实心按钮各自取色:`<Button>` 走 `--color-primary`(= `--color-action`),`.button-primary` 走 `--color-action-strong`。同一个"主操作"在不同页面是两种颜色。
4. BUG-1078 只在报告页作用域内覆盖了颜色(`globals.css` 里 `:is(.report-center-message, …) [data-slot="button"]…` 那一段 + `.report-center-generate`),根因 1 没动。
## 决策记录(产品 2026-09-28 拍板)
- **D1 全站一种实心主按钮(产品选 A)**,与报告页 BUG-1078 已上线的配色相同:
- 浅色:底 `#a9583e`(`--color-action`)+ 字 `#fbfaf7`,4.85:1;悬停 `--color-action-hover`(`#8f4630`)。
- 深色:底 `#8f4a33`(`--color-action-on-dark`)+ 字 `#f2f0ea`(`--color-ink`),5.77:1;悬停与报告页同法(向 ink 混 6%)。
- 适用:`<Button>` 默认变体、`.button-primary`、输入框发送 / 停止键、日期选择器选中日。
- **D2 推翻 DESIGN.md 的"已知缺口"**:`.button-primary` 不再用 `#cc785c` 珊瑚底。代价是登录、首次引导按钮深一档,没那么像 Claude,产品接受。`#cc785c` 在**非按钮**处照旧:会话选中竖条、焦点环、打字光标、单选圆点、两处头像圆。
- **D3 实心按钮禁用态 = 中性灰**:底 `--color-canvas-strong`、字 `--color-ink-tertiary`、不透明(opacity 1)。适用于 D1 的全部实心按钮与 `.danger-primary`。**描边、幽灵、次要、图标、chip 等非实心按钮的禁用淡化不在本单范围**,保持现状。
- **D4 删掉 BUG-1078 的报告页局部覆盖**:一处定义、全站生效。报告页观感不变(数值与 D1 相同)。
- **D5 `.danger-primary` 启用态保持现在的对比度**(浅 7.13、深 6.04):`.button-primary` 改色后它不得被连带改成浅字配浅红,需要时给它单独写文字色。
- **D6 不重映射 `--color-primary`**:它还被 `text-primary` 用在报告页的加载圈和图标上,深色下改成 `#8f4a33` 会让这些图标对比度掉到约 2.3。新增一对只给按钮用的 token(建议名 `--color-action-fill` / `--color-on-action-fill`,深浅各一组),`<Button>` 默认变体、`.button-primary`、发送键、日历选中日都引用它。
## 硬红线
1. 修根因:`button { color: inherit; }` 删掉(preflight 已有),`button:disabled` 那条移进 `@layer base`,或改成不压工具类的写法;不得在各页面再写局部覆盖来绕开。
2. 不改 `--color-primary` / `--color-primary-foreground` 的映射(D6);不改 `#cc785c` 的非按钮用途(D2)。
3. 非实心按钮的外观与禁用态不变:用 harness 前后对比描边、次要、幽灵的数值,必须完全相同。
4. `.danger-primary` 两种主题 ≥ 4.5:1。
5. 每个 D1 实心按钮两种主题 ≥ 4.5:1;禁用态 opacity = 1。
6. `components/ui/button.tsx` 可以改(上一单的红线只针对报告单),但变体名和 props 不变,调用方零改动。
7. `frontend/src/app/page.tsx` 不碰;`/` 保持 `○ Static`;首屏 gzip ±2%。
8. 改既有断言写「原值 / 新值 / 原因」(`report-buttons-scope-20260928.test.ts` 必然要改);测试总数不低于基线。
9. 不升级依赖;harness 不进 `package.json`,只用本机全局 playwright-core + Chrome。
## 任务分解
### T1 根因:层外元素规则
- 处理 `globals.css` 顶部的 `button { color: inherit; }`、`button:disabled { … }`(见红线 1)。
- 源码合同测试:`globals.css` 里不存在层外的 `button { color` 与层外的 `button:disabled`。
- **验收**:harness 显示 `<Button>` 默认变体文字色 = `text-primary-foreground` 解析值;描边 / 次要 / 幽灵数值与基线逐项相同。
### T2 按钮专用 token + 两套实心按钮合一
- 新增 D6 的 token 对(`:root`、`prefers-color-scheme: dark` 且非 `data-theme=light`、`[data-theme=dark]` 三处,照现有主题写法)。
- `button.tsx` 默认变体改用新 token(含 hover),禁用态按 D3。
- `.button-primary`、`.composer .composer-row-end > button`、`.composer .composer-stop` 改用新 token,禁用态按 D3。
- `.danger-primary` 按 D5 保持对比度,禁用态按 D3。
- 日期选择器选中日走新 token,删掉 `birth-date-picker.tsx` 里的 `!` 强制补丁(根因修了就不需要)。
- **验收**:harness 全表 D1 项两种主题 ≥ 4.5,禁用态 opacity 1、灰底;数值写进 PROGRESS。
### T3 删 BUG-1078 局部覆盖
- 删掉报告页作用域的颜色与禁用规则、`.report-center-generate` 类(`generate-personal-report-button.tsx` 里的 className 一并去掉)。报告导出套餐选中态(`.report-export-presets [aria-pressed="true"]`)是另一回事,保留。
- `report-buttons-scope-20260928.test.ts` 改为全站合同,三栏说明。
- **验收**:报告页 harness 数值与改前相同(4.85 / 5.77,禁用灰)。
### T4 文档
- `frontend/DESIGN.md`:「Where the action color appears」删掉"已知缺口"段,改写两级规则(按钮底 = `--color-action-fill`;`#cc785c` 只留非按钮用途);「Button」一节写 D1–D3。
- `docs/BUG_HISTORY.md`:**BUG-1079**(全站实心按钮文字被层外 `button { color: inherit }` 压掉 + `.button-primary` 低对比 + 禁用半透明)。关联 BUG-1078,写明 1078 只修了报告作用域、根因未动,所以同病在其它 60 多处未拦住。
- `CHANGELOG.md` 一条(Skill 不 bump)。
- `docs/testing/site-button-contrast-20260928.md`:真机清单,浅 / 深各走一遍:登录、首次引导、点数与订阅面板、兑换码、人物档案(含删除确认)、星盘资料保存、星历、生时校正卡片、输入框发送 / 停止 / 排队、日期选择器、我的报告导出;每处看"文字清楚、禁用是灰不是淡红"。
## 让步顺序
1. 后台管理页(`components/admin/*`)的真机走查可以只抽 3 页,其余靠 harness 与合同测试。
2. 日期选择器选中日若牵动 `calendar.tsx` 太多,保留 `birth-date-picker.tsx` 的补丁,只在 PROGRESS 说明。
T1、T2 的 `<Button>` / `.button-primary` / 禁用灰不让。
## 开工前置命令
```bash
cd /workspace/Jyotisha && git status -sb | head -1
git fetch origin --prune
git worktree add -b codex/site-button-contrast-20260928 .worktrees/site-button-contrast-20260928 origin/staging
cd .worktrees/site-button-contrast-20260928
grep -oE "^## BUG-[0-9]+" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1 # 应为 BUG-1078
grep -n "BUG-1078\|button-primary\|opacity: .45" docs/BUG_HISTORY.md | head
cd frontend && export PATH=/exec-daemon:$PATH && npm ci && ./node_modules/.bin/tsc --noEmit && npm run lint && npm test 2>&1 | tail -6 # 记基线与失败名单
npm run build && mkdir -p /tmp/btn-base && cp .next/static/chunks/*.css /tmp/btn-base/ && node ../docs/testing/button-contrast-harness.cjs /tmp/btn-base # 基线数值
```
harness 只读**刚 build 出来**的 CSS。09-28 扫描时一份过期的 `.next` 曾让已上线的修复看起来不存在。
## BUG 编号
起点 **BUG-1079**(开工时核对 `docs/BUG_HISTORY.md` 最大号为 1078)。
## 交付
- 代码 + 文档同批一次快进推 `git push origin HEAD:staging`,核对远端 SHA;门禁绿后核对 `/api/health` 的 `deployment.gitCommit`,再用 harness 对 staging 线上 CSS 复测一遍,数值贴进 PROGRESS。
- 不提升 `main`、不改 workflow。