Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
123 lines
11 KiB
Markdown
123 lines
11 KiB
Markdown
# 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。
|