e8fa1ce4ea
Dark muted surfaces missed WCAG AA; action and tertiary tokens plus a 32-pair contract close that. Hit targets, remaining-count, and Enter-to-send follow the interaction audit without changing visual sizes. Co-authored-by: Cursor <cursoragent@cursor.com>
111 lines
6.5 KiB
Markdown
111 lines
6.5 KiB
Markdown
# PROGRESS · 客户端交互与 UI 收尾(2026-08-30)
|
||
|
||
工作树:`.worktrees/interaction-20260830`
|
||
分支:`codex/interaction-20260830`
|
||
基线:任务书写 `origin/staging` @ `ea0fbd44`;开工时远端已快进到 `95f58512`。推送前再 fetch,远端又多了 `b43808b0`(占用 BUG-444),本轮条目改为 **BUG-445–448**。按红线始终跟 `origin/staging`,不是本地 ref。
|
||
|
||
不要写成 `PROGRESS.md`。
|
||
|
||
未改 `.gitea/workflows/**`。未提升 main。未手写 `useCallback` / `useMemo`。未改既有测试断言(`composer-isolation-contract` 的 `import { ChatComposer }` 通过把计数组件拆到独立文件保住)。
|
||
|
||
## 任务 0 · 深色对比度
|
||
|
||
两个深色块(`prefers-color-scheme` 内的 `:root:not([data-theme="light"])` 与 `:root[data-theme="dark"]`):
|
||
|
||
| token | 旧 | 新 |
|
||
| --- | --- | --- |
|
||
| `--color-ink-tertiary` | `#928e84` | `#9c988e` |
|
||
| `--color-action` / `--color-focus` / `--report-accent` | `#d4785a` | `#d78064` |
|
||
|
||
`#d4785a` 在 `frontend/src` + `DESIGN.md` 已清零(含四个根边界页)。浅色 `#85432f` 未动。
|
||
|
||
32 组(8 字色 × 4 底色)全部 ≥ 4.5:1。最紧两对:tertiary on muted **4.60:1**,action on muted **4.51:1**。
|
||
|
||
反向:把 tertiary 改回 `#928e84` 后合同变红,失败信息为 `--color-ink-tertiary (#928e84) on --color-canvas-muted (#30302d) is 4.05:1`。已还原。
|
||
|
||
BUG-445。
|
||
|
||
## 任务 1 · 触达尺寸
|
||
|
||
视觉尺寸未改。浅色夹具 before/after:actions / chips / auth **0 像素差**(标题字符串不同,2689 px 只在 h1)。深色夹具除标题外,actions 313 px(tertiary 提亮)、auth 1148 px(action 提亮),chip 字形 0 差。
|
||
|
||
| 选择器 | 视觉 | 命中(elementFromPoint) | 相邻 |
|
||
| --- | --- | --- | --- |
|
||
| `.message-actions button` ×4 | 26×26,gap 1px | 27×35(CSS 伪元素 27×34;末颗 28×35 为整数探针取整) | gapX **0**,不重叠。中心距 27px,44×44 会水平重叠 17px;8px 底边距下 44 高会吃 follow-up 1px |
|
||
| `.chart-nav-chip` | 32 高,gap 8px | 约 58×39(`inset: -4px` → 40 高) | gapX **2**,不重叠。距 44 差 4px |
|
||
| `.auth-links button` | 32 高 | 86×41 / 60×41 | 登录页当前无密码通道,节点未挂;夹具 space-between gapX 142。注入探针:浅色 `rgb(133,67,47)`,深色 `rgb(215,128,100)` = `#d78064` |
|
||
| `.select-item` | min-height **44** | 列表 `max-height` 仍在,条目多 4px,时钟菜单本来就滚 | — |
|
||
| `.birth-time-skip-button` | min-height **44** | 独占一行 | — |
|
||
| `.report-center-section-heading button` | min-height **44** | 与 h2 间距 24px | — |
|
||
|
||
止损见 `BLOCKED.md`。BUG-446。
|
||
|
||
## 任务 2 · 字数上限
|
||
|
||
四处都做了,没有因高度跳动减范围。
|
||
|
||
| 位置 | 上限 | 阈值(剩余 ≤) | 计数放哪 |
|
||
| --- | ---: | ---: | --- |
|
||
| 主对话 `ChatComposer` | 500(入门称呼 80) | 50 / 8 | 既有 `.composer-footer` 右侧,`<span>` 不是 `<p>`,移动端 `> p { display: none }` 不误伤 |
|
||
| `ProfileFields` 姓名 | 80 | 8 | 标签行 `character-remaining-row` |
|
||
| `birth-time-guide-turn` | 500 | 50 | 标签行 |
|
||
| `BirthTimeUnmatchedClarification` | 240 | 24 | 标签行 |
|
||
|
||
平时不挂载。`aria-live="polite"` + `aria-atomic="true"` 只在阈值内。可见数字 `aria-hidden`,live 文案只有「接近字数上限」和「已达 N 字上限」,避免每字播报。到顶 `data-limit` → `--color-danger`。
|
||
|
||
未登录会话,产品主输入未逐字录屏;行为由 `character-remaining-contract` 锁死。footer `min-height: 44px` 已在,计数 `white-space: nowrap`,出现时不新造一行。
|
||
|
||
BUG-447。
|
||
|
||
## 任务 3 · 发送键
|
||
|
||
选择:**统一 Enter 发送、Shift+Enter 换行**,不是保留 ⌘+Enter 只补提示。
|
||
|
||
理由:主对话和生时校正对话已经是这套;用户把 Enter 习惯带到引导框只会换行。引导框仍有「整理为经历草稿」,不会卡死。漏 `isComposing` 会让中文选词误发送,比现状严重。`rows={3}` 的换行改走 Shift+Enter,并在既有 `#birth-time-guide-hint` 写明。
|
||
|
||
| 输入框 | 发送 | 换行 | `isComposing` |
|
||
| --- | --- | --- | --- |
|
||
| 主对话 `handleComposerKeyDown` | Enter | Shift+Enter | 先 return |
|
||
| 生时校正 `rectification-agentic-chat` | Enter | Shift+Enter | 同一条件 |
|
||
| 生时引导 `birth-time-guide-turn` | Enter(本轮从 ⌘/Ctrl+Enter 改来) | Shift+Enter | 先 return |
|
||
|
||
headless 无输入法,未做产品里的拼音→Enter 选词实机。合同锁三处源码都带 `event.nativeEvent.isComposing`。
|
||
|
||
BUG-448。
|
||
|
||
## 命令输出
|
||
|
||
`./node_modules/.bin/tsc --noEmit` → **0**(约 235s,无诊断)
|
||
|
||
`./node_modules/.bin/eslint` 触及文件 → **0 error**。既有 warning:`page.tsx` 两处 `react-hooks/exhaustive-deps`(restoreConsultationRecovery / profile),`globals.css` 无 eslint 配置被忽略。不是本轮引入。
|
||
|
||
`./node_modules/.bin/tsx --test tests/*.test.ts` → **2307 / 2298 pass / 9 fail / skipped 0 / todo 0**。
|
||
|
||
9 条失败全是本机无 Docker 的数据库类(与任务书 23+10 的环境缺口同类,本环境实际是 9 条 fail、0 skip)。标题:
|
||
|
||
1. admin code functions reject immutable codes, revoked redemption, and roll back on audit failure
|
||
2. Owner recovery grants only one currently loginable synced identity admin
|
||
3. local PostgreSQL applies the reviewed business schema and serves authenticated business calls
|
||
4. redeem security: case-sensitive hashing, rate limiting, idempotency and order ownership
|
||
5. Better Auth supports shared user OTP/password sessions for admins
|
||
6. database drops secret refs, generates immutable codes, and invalidates evidence after key rotation
|
||
7. ingest P0: education kinds, batch confirm, opening focus reuse, precision lock
|
||
8. PR-4 candidate decisions use server UUIDs, receipt-derived gates and separate acceptance/confirmation
|
||
9. v9 migration applies on a fresh database and re-applies idempotently
|
||
|
||
本轮新增合同(dark 32 组、touch-target、character-remaining、composer-ime)在聚焦套件 121/121 中全绿。无产品逻辑新增失败。
|
||
|
||
`./node_modules/.bin/next build` → **0**。第一次因 worktree 里 `node_modules` 外链被 Turbopack 拒;`npm ci` 后:
|
||
|
||
```
|
||
✓ Compiled successfully in 3.3s
|
||
Finished TypeScript in 6.1s
|
||
✓ Generating static pages using 7 workers (60/60) in 330ms
|
||
```
|
||
|
||
5 条既有 `skill-package-registry.ts` filesystem-tracing warning,未失败。
|
||
|
||
## 证据路径(未提交)
|
||
|
||
`.omo/evidence/interaction-20260830/`:before/after 浅色深色 PNG、`hit-rects.json`、login-light、not-found-light。
|