docs(tasks): fold two mobile blockers into the reading-load round, brief touch targets and breakpoints
2026-09-15 的 UI 走查(web + 移动端)结果落盘。 并入 TASK-chat-reading-load:折叠层里的四列表在窄屏没有重排规则 (767 的卡片化只认三列,width:100% 又让 overflow-x 永不触发),它是 折叠能不能落地的前置;全局 input/select 是 14px,iOS 聚焦会把整页放大, 命中整条注册与资料录入漏斗。 新单 TASK-mobile-touch-and-breakpoints(BUG-695~697):消息操作按钮 命中区 27×34 且相邻只隔 1px;CSS 平板上限 900px 与 sidebar-state.ts 的 1024 不一致,901–1023 是混合态;报告域 720/760/860 三刀互不对齐, 761–860 目录已塌、正文还是桌面。含断点白名单契约测试作为防复发。 另加 docs/testing/ios-keyboard-composer-20260915.md:html/body overflow hidden + 100dvh 外壳 + sticky 输入框 + interactiveWidget 只有 Android 认, 是键盘遮挡的风险形状,但代码断不了真假,交真机确认后再决定是否立单。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
This commit is contained in:
co-authored by
Claude Fable 5
parent
4147326115
commit
899f955d4b
@@ -118,6 +118,7 @@
|
||||
| `TASK-unified-loading-20260902.md` | `PROGRESS-unified-loading-20260902.md` | 首页一次等待一次揭幕 | 已验收 | `482796fc`(BUG-479) |
|
||||
| — | — | 初始化后点首页「家庭」报运行合同未完成:本命第一步未强制计算工具、主题卡无入口钉死 | 待验收 | `codex/consultation-family-contract-incomplete-20260909`(BUG-630);走查 `docs/testing/consultation-family-contract-incomplete-20260909.md` |
|
||||
| `TASK-chat-reading-load-20260915.md` | — | 首页「从一个主题开始」整段下线(连同 `/api/onboarding` 的 LLM 取数与揭幕闸门);聊天回答改两层可见性:口语层默认展开、第一个 H2 起的骨架进默认收起的「完整分析」折叠块;口语层定形为「结论+2–3 要点+下一步」≤400 字。内容一字不删,只改默认可见性。⚠️ 会让 BUG-630 的走查路径失效(`guided_topic` 入口下线,枚举保留) | 待领取 | `codex/chat-reading-load-20260915` |
|
||||
| `TASK-mobile-touch-and-breakpoints-20260915.md` | — | 消息操作按钮触屏命中区 27×34、相邻仅隔 1px(BUG-695);CSS 平板上限 900px 与 `sidebarViewportForWidth` 的 1024 不一致,901–1023 是混合态(BUG-696);报告域 720/760/860 三个断点互不对齐,761–860 目录已塌、正文还是桌面(BUG-697)。含断点白名单契约测试。**串行在 chat-reading-load 之后** | 待领取 | `codex/mobile-touch-and-breakpoints-20260915` |
|
||||
|
||||
### 个人报告
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# TASK · 首页主题卡下线 + 聊天回答两层化(降低阅读负担)
|
||||
# TASK · 首页主题卡下线 + 聊天回答两层化 + 两处移动端阻塞(降低阅读负担)
|
||||
|
||||
- 日期:2026-09-15
|
||||
- 基线 commit:`origin/staging` @ `ebd5ba68`(`docs: clear the timezone gap and record what actually keeps the gate red`)
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
> 首页底下的那些问题都可以去掉;聊天过程中怎么让用户不会觉得「我现在看到字很多,我有点阅读障碍」。
|
||||
|
||||
两件事分别对应任务 1 和任务 2–3。**两件事可以在同一分支同一轮做完**,互不依赖,但共用一次测试基线测量(任务 4)。
|
||||
两件事分别对应任务 1 和任务 2–3。
|
||||
|
||||
2026-09-15 的 UI 走查又带出两处**移动端**问题,同批并入(任务 2.6、任务 5):折叠层里的四列表在手机上读不了(它是折叠能不能落地的前置),以及全局输入框 14px 导致 iPhone 聚焦时整页放大。
|
||||
|
||||
全部任务可以在同一分支同一轮做完,互不依赖,共用一次测试基线测量(任务 4)。
|
||||
|
||||
---
|
||||
|
||||
@@ -48,10 +52,47 @@
|
||||
|
||||
而渲染层对这一切是**完全平铺**的:`frontend/src/components/chat-message-content.tsx` → `ChatMessageContent` 把整篇 markdown 一次渲染到底,唯一的折叠是 `TechniqueAuditDisclosure`,而且 `showFoldedAudit = rows.length > 0 && split.rows.length === 0` —— 正文里已经有那张表时反而**不折**。
|
||||
|
||||
### 2.3 根因一句话
|
||||
### 2.3 折叠层里的宽表在手机上读不了
|
||||
|
||||
移动端的表格卡片化重排**只认三列表**(`frontend/src/app/globals.css`,`@media (max-width: 767px)` 内):
|
||||
|
||||
```css
|
||||
.markdown-table table:has(thead th:nth-child(3):last-child) thead { /* 视觉隐藏表头 */ }
|
||||
.markdown-table table:has(thead th:nth-child(3):last-child) tbody tr { display: grid; … }
|
||||
```
|
||||
|
||||
技法审计表(技法 / 状态 / 说明)正好三列,重排正常。但 `natalSpokenReportContract` 还要求一张 **四列的 Yoga 表**(`name / formation / strength or hit-miss / domain effect`),统一参数那节也会出宽表。它们落到基础规则:
|
||||
|
||||
```css
|
||||
.markdown-table { overflow-x: auto; }
|
||||
.markdown-table table { width: 100%; } /* ← 与上一行互相抵消 */
|
||||
.markdown-table th, .markdown-table td { word-break: keep-all; } /* ← 中文不断词 */
|
||||
```
|
||||
|
||||
`width: 100%` 让表格永远不超出容器,`overflow-x: auto` 于是永不触发;四列被压成约 85px 一柱,`keep-all` 又不许中文断词。375px 屏上要么挤成竖排单字,要么撑破容器。
|
||||
|
||||
**这正是任务 2 折叠层里的内容**——手机用户点开「完整分析」第一眼就撞上,所以它是折叠能不能落地的前置条件,并进本轮。
|
||||
|
||||
### 2.4 所有输入框 14px,iPhone 一聚焦就整页放大
|
||||
|
||||
`frontend/src/app/globals.css` 的全局 input 规则:
|
||||
|
||||
```css
|
||||
input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"])…,
|
||||
select:not([class^="ant-"])… { min-height: 44px; …; font-size: var(--type-body-sm); }
|
||||
```
|
||||
|
||||
`--type-body-sm = 14px`,且移动端媒体查询里**没有任何一处把它提上去**(`grep` 过 `@media (max-width: 767px)` 之后的全部规则)。
|
||||
|
||||
iOS Safari 对字号小于 16px 的输入框会在聚焦时自动放大页面,并且不会自己缩回去。命中的是整条注册与资料录入漏斗:登录邮箱、姓名、出生日期、出生时间、出生地搜索。
|
||||
|
||||
已经躲过的只有两处,改动不得破坏它们:`.otp-input` 是 20px,`.composer textarea` 是 `var(--type-body-md)`(16px)。
|
||||
|
||||
### 2.5 根因一句话
|
||||
|
||||
- 首页:一个低价值入口押着一次 LLM 调用和整个揭幕闸门。
|
||||
- 聊天:内容合同要求「全量输出」,渲染层没有「默认可见性」这一层,于是全量输出 = 全量可见。
|
||||
- 移动端:宽表的响应式规则只覆盖了三列这一种形状;输入框字号沿用了正文小号,没有为触屏留出 16px 的下限。
|
||||
|
||||
---
|
||||
|
||||
@@ -186,9 +227,30 @@ export function splitSpokenAndReport(text: string): SpokenAndReportSplit;
|
||||
- 个人报告页走 `personal-report-document-view.tsx`,**不经过**本组件,不得受影响。
|
||||
- 会话落库、复制按钮、重新生成拿到的仍是**完整原文**,不是口语层。
|
||||
|
||||
**2.6 折叠层里的宽表必须在手机上可读(本轮前置,不得延后)**
|
||||
|
||||
处置分两档,按列数分流,**不要动现有的三列规则**(它有测试、工作正常):
|
||||
|
||||
- **三列表**:保持现状的卡片化重排,一行也不改。第三列是说明性长文本,塌成第二行读起来像图注,这是它成立的原因。
|
||||
- **四列及以上**:改为**真正可横向滚动**,而不是继续卡片化。四字段 × N 行的表格塌成卡片会变成一条极长的竖列(Yoga 表 8 行 × 4 字段 = 32 行),比横滑更难读;而且用户是主动点开「完整分析」才看到它的,横滑是可接受的代价。
|
||||
|
||||
在 `@media (max-width: 767px)` 内加:
|
||||
|
||||
```css
|
||||
.markdown-table table:not(:has(thead th:nth-child(3):last-child)) {
|
||||
width: auto;
|
||||
min-width: max-content; /* 让 .markdown-table 的 overflow-x: auto 真正生效 */
|
||||
}
|
||||
```
|
||||
|
||||
并给 `.markdown-table` 加一个**可横滑的视觉提示**(右缘渐隐或 `scroll-shadow`,用既有 token,不引新库、不加 JS),否则用户不知道右边还有内容。`word-break: keep-all` 保留——横滑模式下它反而是对的。
|
||||
|
||||
同一处理必须同时覆盖:聊天里的宽表、`.technique-audit-panel`(它已有三列规则,不受影响,确认即可)。**个人报告页的表格不在本轮范围**(走 `.personal-report-*` 自己的规则)。
|
||||
|
||||
**验收标准(任务 2)**
|
||||
|
||||
- 一条本命类回答:口语层直接可读,下面一个收起的「完整分析」块;展开后章节顺序与原文完全一致,一个字不少。
|
||||
- 375px 宽视口下展开「完整分析」:三列技法审计表仍是卡片式;四列 Yoga 表可横向滑动、不挤压、不撑破容器;页面本身**不出现横向滚动条**(`.conversation` 的 `overflow-x: hidden` 必须仍然成立)。
|
||||
- 闲聊类回答(无 H2)渲染与改动前逐字一致。
|
||||
- onboarding 打字机消息渲染与改动前逐字一致。
|
||||
- 复制该条消息,得到的是完整原文(含骨架)。
|
||||
@@ -263,7 +325,8 @@ npm test 2>&1 | tail -20 # 记下 pass / fail / tests 三个数字
|
||||
|
||||
**4.4 文档**
|
||||
|
||||
- `frontend/DESIGN.md`:新增「回答的两层可见性」一节(口语层 / 折叠层的判定规则、`<summary>` 文案规则、流式期间的表现),并把首页去掉主题卡后的版式写进首页那一节。同一提交内完成。
|
||||
- `frontend/DESIGN.md`:新增「回答的两层可见性」一节(口语层 / 折叠层的判定规则、`<summary>` 文案规则、流式期间的表现),并把首页去掉主题卡后的版式写进首页那一节。**另加一条表格规则**:三列表在窄屏卡片化、四列及以上横向滚动并带滑动提示,以及表单输入 16px 下限的理由(iOS 聚焦放大)。同一提交内完成。
|
||||
- `docs/testing/chat-reading-load-20260915.md`:新建真机清单,至少含——iPhone Safari 上逐个聚焦表单输入框确认不放大;375px 下展开「完整分析」确认宽表可横滑且页面不横向滚动;折叠块在流式期间不展开、不出现转圈。
|
||||
- `CHANGELOG.md`:一条日期 + 一句话标题 + 变更要点(首页主题卡下线;回答默认只展开口语层)。注明 Skill 版本**不**bump(本轮不改 Skill)。
|
||||
- `docs/tasks/PROGRESS-chat-reading-load-20260915.md`:做了什么、测试三个数字(基线 / 改后)、删了哪些断言、新增哪些、偏离与原因。
|
||||
- `docs/tasks/README.md`:把本任务书那行状态从「待领取」改成「执行中 / 待验收」;同时处理 §3.1 说的 BUG-630 那一行。
|
||||
@@ -277,6 +340,31 @@ npm test 2>&1 | tail -20 # 记下 pass / fail / tests 三个数字
|
||||
|
||||
---
|
||||
|
||||
### 任务 5 · 输入框字号 14 → 16(iOS 聚焦放大)
|
||||
|
||||
**5.1** `frontend/src/app/globals.css` 的全局 input / select 规则,`font-size` 从 `var(--type-body-sm)`(14px) 改为 `var(--type-body-md)`(16px)。
|
||||
|
||||
- 优先做**无条件提升**(所有视口一致 16px)。`min-height: 44px` 已经在了,行高和内边距不用动,桌面端视觉变化很小。
|
||||
- 若产品在桌面端观感上不接受 16px,退而求其次只在触屏下提升:
|
||||
```css
|
||||
@media (pointer: coarse) { input:not(…), select:not(…) { font-size: var(--type-body-md); } }
|
||||
```
|
||||
两种都可以,选哪种写进 PROGRESS。**不接受的是维持 14px。**
|
||||
|
||||
**5.2** 不得破坏既有的两处安全值:`.otp-input`(20px)、`.composer textarea`(`--type-body-md`)。
|
||||
|
||||
**5.3** 排除项不变:`[type="radio"]`、`[type="checkbox"]`、antd(`[class^="ant-"]` / `.ant-picker input`)——admin 是 antd + Refine,不在本轮范围。
|
||||
|
||||
**5.4** 改完复查这几个表单的换行有没有被挤坏(字号变大会改变换行点):登录邮箱 + 验证码、姓名、出生日期、出生时间、出生地搜索下拉、设置弹窗里的各字段。桌面和 375px 各看一遍。
|
||||
|
||||
**验收标准(任务 5)**
|
||||
|
||||
- `grep -nE "font-size: var\(--type-body-sm\)" frontend/src/app/globals.css` 的结果里不再包含全局 input/select 规则。
|
||||
- 375px 视口下逐个聚焦上述输入框,页面不发生缩放(**真机项**:模拟器不一定复现 iOS 的放大行为,做不到就写进 `docs/testing/` 清单,不得写成「通过」)。
|
||||
- 表单在 375px 与桌面两种宽度下无换行崩坏、无溢出。
|
||||
|
||||
---
|
||||
|
||||
## 6. 让步顺序
|
||||
|
||||
被挡住时按这个顺序退,退到哪一步写进 PROGRESS:
|
||||
@@ -285,7 +373,9 @@ npm test 2>&1 | tail -20 # 记下 pass / fail / tests 三个数字
|
||||
2. 任务 3 若导致 voice 合同套件大面积红且一轮内收不住,**把任务 3 整体拆到下一轮**,本轮只交任务 1 + 2 + 4。渲染层折叠独立生效,不依赖文案改动。
|
||||
3. 任务 1.3 删接口若牵出 Mastra agent 注册或模型目录的连带失败,**保留 `route.ts` 与 agent 文件但断开前端调用**(前端不再请求即可拿到全部收益),把未删干净的部分写进根目录 `BLOCKED.md`。
|
||||
4. `generalGuidedJyotishTopics` 若被别处引用,保留该模块,只删首页引用。
|
||||
5. **绝不让步**:骨架内容不得删减;完整原文必须仍然入库、可复制、可导出;`guided_topic` 枚举值不得从 schema 移除;不得动数据库结构。
|
||||
5. 任务 2.6 的横滑提示(渐隐 / scroll-shadow)若在深色主题下做不干净,**先只交「能横滑」**,提示留到下一轮,写进 PROGRESS。能横滑本身不让。
|
||||
6. 任务 5 若无条件 16px 在桌面端观感上被否,退到 `(pointer: coarse)` 版本。**维持 14px 不是选项。**
|
||||
7. **绝不让步**:骨架内容不得删减;完整原文必须仍然入库、可复制、可导出;`guided_topic` 枚举值不得从 schema 移除;不得动数据库结构。
|
||||
|
||||
---
|
||||
|
||||
@@ -320,11 +410,12 @@ git push origin HEAD:staging # 快进推送,触发 backend-qualit
|
||||
|
||||
- 本轮改 `frontend/src/app/page.tsx` 与 `frontend/src/components/chat-message-content.tsx`。开工前确认没有别的轮次同时在改这两个文件(`docs/tasks/README.md` 状态板上「执行中」的行)。若有,**本轮排在其后**。
|
||||
- 与 `TASK-report-provenance-binding-20260915.md` 无文件重叠,可并行。
|
||||
- **`TASK-mobile-touch-and-breakpoints-20260915.md` 必须排在本轮之后**:两轮都改 `frontend/src/app/globals.css`,且那一轮的任务 2.2 依赖本轮是否已删掉主题卡。
|
||||
|
||||
---
|
||||
|
||||
## 9. BUG 编号起点
|
||||
|
||||
- `origin/staging@ebd5ba68` 的 `docs/BUG_HISTORY.md` 当前最大号 = **BUG-694**。
|
||||
- 本任务书是产品改造,**不预分配 BUG 编号**。执行中若发现或引入回归,从 **BUG-695** 起连续编号,并按 `AGENTS.md` §5 在同一变更里补 `docs/BUG_HISTORY.md`。
|
||||
- 本任务书是产品改造,**不预分配 BUG 编号**。执行中若发现或引入回归,从 **BUG-698** 起连续编号(BUG-695~697 已由 `TASK-mobile-touch-and-breakpoints-20260915.md` 占用),并按 `AGENTS.md` §5 在同一变更里补 `docs/BUG_HISTORY.md`。
|
||||
- 开工时请再核一次最大号——可能已有别的轮次占用。
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
# TASK · 消息操作触控目标 + 断点错位(BUG-695~697)
|
||||
|
||||
- 日期:2026-09-15
|
||||
- 基线 commit:`origin/staging` @ `41473261`
|
||||
- 执行分支:`codex/mobile-touch-and-breakpoints-20260915`
|
||||
- 工作树:`.worktrees/mobile-touch-and-breakpoints-20260915`
|
||||
- **串行依赖:必须排在 `TASK-chat-reading-load-20260915.md` 之后。** 两轮都改 `frontend/src/app/globals.css`,不得并行。开工前确认前一轮已合入 `staging`,并以合入后的 staging 为基线,而不是 `41473261`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 来源
|
||||
|
||||
2026-09-15 的 UI 走查(web + 移动端)在首页与聊天两件事之外,另外查实三处。其中两处已并入 `TASK-chat-reading-load-20260915.md`(折叠层宽表、输入框 14px),本单处理剩下的两类。
|
||||
|
||||
走查同时确认了一批**做得好、本轮不要动**的东西,列在 §6,避免执行方顺手"优化"掉。
|
||||
|
||||
---
|
||||
|
||||
## 2. 事故实证
|
||||
|
||||
行号会漂移,定位以符号名为准。核对于 `origin/staging@41473261`。
|
||||
|
||||
### 2.1 BUG-695|消息操作按钮触控目标 27×34,相邻只隔 1px
|
||||
|
||||
`frontend/src/app/globals.css`:
|
||||
|
||||
```css
|
||||
.message-actions { gap: 1px; margin: -4px 0 8px 42px; }
|
||||
.message-actions button { width: 26px; height: 26px; flex: 0 0 26px; }
|
||||
/* Visual icon stays 26px. Neighbours sit 27px centre-to-centre (26px + 1px gap)
|
||||
and follow-ups start after an 8px bottom margin, so a 44×44 overlay would
|
||||
steal clicks. This is the largest non-overlapping hit: 27×34. */
|
||||
.message-actions button::after { width: 27px; height: 34px; }
|
||||
```
|
||||
|
||||
复制 / 点赞 / 点踩 / 重新生成四个按钮并排,中心间距 27px。WCAG 2.5.8 的 24×24 下限过了,但离触屏推荐的 44×44 差很远;在手机上点赞很容易点成点踩。
|
||||
|
||||
**注释本身写清楚了这是被布局逼出来的**:往下 8px 就是 follow-up 药丸,44×44 的覆盖层会抢走它们的点击。所以这不是「把 27 改成 44」一行能解决的,得先给这一行让出空间。
|
||||
|
||||
同类但优先级低得多的还有一处:`.markdown-code-copy { min-height: 28px }`。本产品的回答里代码块极少,顺手一起处理,做不了不阻塞。
|
||||
|
||||
### 2.2 BUG-696|CSS 的平板上限 900px 与 JS 的 1023 不一致,901–1023 是混合态
|
||||
|
||||
JS(`frontend/src/lib/sidebar-state.ts` → `sidebarViewportForWidth`):
|
||||
|
||||
```
|
||||
width < 768 → mobile
|
||||
width < 1024 → tablet
|
||||
否则 → desktop
|
||||
```
|
||||
|
||||
侧栏宽度跟着它走(`globals.css` 的 `[data-viewport="tablet"]…` 用 `--sidebar-width-tablet: 240px`,desktop 用 288px)。
|
||||
|
||||
但 CSS 里另有两处用 `max-width: 900px` 当平板上限:
|
||||
|
||||
- `.code-form { grid-template-columns: 1fr 1fr; }`
|
||||
- `.model-selector-trigger { max-width: 100%; grid-column: 1; grid-row: 1; }`
|
||||
|
||||
以及两处 `(min-width: 768px) and (max-width: 900px)` 的首页栅格规则。
|
||||
|
||||
**结果:901–1023px 之间,`data-viewport` 还是 `tablet`(侧栏 240px 窄版),但所有 `max-width: 900px` 的规则已经失效**,模型选择器和首页栅格回到桌面排法。这个区间正好是 iPad 横屏(1024 刚好落在 desktop 侧)、桌面窗口拖到一半、以及不少 Android 平板。
|
||||
|
||||
### 2.3 BUG-697|报告域三个断点互不对齐,761–860 是混合态
|
||||
|
||||
| 断点 | 规则 | 文件位置 |
|
||||
| --- | --- | --- |
|
||||
| `max-width: 720px` | `.report-center-shell` 内边距、`.report-center-hero` 单栏、按钮满宽 | 报告中心 |
|
||||
| `max-width: 760px` | `.personal-report-reader-body` 内边距、`.personal-report-document` 内边距、封面单栏 | 报告阅读区 |
|
||||
| `max-width: 860px` | `.personal-report-md-layout` 单栏、`.personal-report-toc` 静态化、目录切抽屉 | 报告目录 |
|
||||
|
||||
在 761–860px:**目录已经塌成抽屉了,正文还是桌面内边距**。在 721–760:阅读区已窄、报告中心还是桌面。
|
||||
|
||||
另外整份样式表的宽度切点共有:`430 / 480 / 620 / 639·640 / 640·641 / 720 / 760 / 767·768 / 860 / 900 / 1024`。其中 `639·640`(会员)与 `640·641`(校正)是两组各自自洽的邻接对,相差 1px,不造成错位但属于噪音;`430` 与 `480` 是两个小屏断点;`620` 是出生资料录入卡独有的。
|
||||
|
||||
---
|
||||
|
||||
## 3. 决策记录(产品已授权)
|
||||
|
||||
产品负责人 2026-09-15 确认按下述范围执行:
|
||||
|
||||
1. **BUG-695 修**:把消息操作的触控目标做到触屏下 44×44,代价是让出垂直空间。
|
||||
2. **BUG-696 / 697 修的是「错位」,不是「统一」。** 本轮**只**消除 §2.2 和 §2.3 两个混合区间,以及把噪音断点收敛。**不做全表断点重构**——本会话没有浏览器,全表重排的视觉回归验证不了,收益也远小于风险。
|
||||
3. **收敛的方式是约定 + 契约测试,不引 PostCSS 插件。** CSS 自定义属性不能用在媒体查询条件里,而本仓 Next.js 配置没有 `postcss-custom-media`。本轮不为此加构建依赖(`frontend/AGENTS.md` §7.7:不得顺手升级依赖)。
|
||||
4. **视觉验收是环境缺口。** 本轮没有浏览器与真机,断点改动的目视确认写成 `docs/testing/` 清单交给产品,**不得在 PROGRESS 里写成「通过」**。
|
||||
|
||||
---
|
||||
|
||||
## 4. 硬红线
|
||||
|
||||
1. `./node_modules/.bin/tsc --noEmit` 0 错;`npm run lint` **0 error**。
|
||||
2. 测试总数不得低于开工时 `origin/staging` 的实测;改既有断言写「原值 / 新值 / 原因」三栏。
|
||||
3. `next build` 后 `/` 仍是 `○ Static`;首屏 gzip ±2% 内。
|
||||
4. **不得改任何组件的 JSX 结构来迁就断点**——本轮是样式与命中区的调整。唯一允许的结构改动是 BUG-695 需要的那点垂直空间,且必须在 `frontend/DESIGN.md` 里写明。
|
||||
5. **不得动 `sidebarViewportForWidth` 的 768 / 1024**。它是 JS 侧真相,CSS 向它对齐,不是反过来。
|
||||
6. 不得动 admin(antd + Refine,`[class^="ant-"]` 排除项照旧)。
|
||||
7. 不得顺手升级依赖、不得引入 PostCSS 插件、不得顺手修不在本单里的 warning。
|
||||
8. 改 UI 的同一提交内更新 `frontend/DESIGN.md`。
|
||||
|
||||
---
|
||||
|
||||
## 5. 任务分解
|
||||
|
||||
### 任务 1 · BUG-695:消息操作触控目标
|
||||
|
||||
**1.1** 在触屏下(`@media (pointer: coarse)`)把 `.message-actions button` 的命中区做到 **44×44**,并让出它需要的空间:
|
||||
|
||||
- 加大 `.message-actions` 的下外边距(现为 `8px`),或加大 `.conversation-follow-ups` 的上外边距,使 44px 的覆盖层不与 follow-up 药丸重叠。
|
||||
- 按钮之间的 `gap` 从 `1px` 放大到至少 `var(--space-1)`,使相邻命中区不互相吞。
|
||||
- **视觉图标保持 26×26**,只放大命中区与间距。桌面端(`pointer: fine`)保持现状不变。
|
||||
|
||||
**1.2** 保留 `::after` 覆盖层那条注释的意图,但**更新注释内容**——它现在描述的是旧结论(「44×44 会抢走点击」),改完之后必须说明新的几何关系为什么不会抢。留着过期注释比没有注释更坏。
|
||||
|
||||
**1.3** `.markdown-code-copy` 的 `min-height` 在 `(pointer: coarse)` 下提到 44px。做不了不阻塞,写进 PROGRESS。
|
||||
|
||||
**验收标准**
|
||||
|
||||
- `(pointer: coarse)` 下 `.message-actions button` 的有效命中区 ≥ 44×44,且相邻按钮命中区不重叠、不与 follow-up 药丸重叠。
|
||||
- `(pointer: fine)` 下的几何与改动前逐值一致。
|
||||
- 新增 CSS 契约测试断言上述两条(本仓已有大量 `globals.css` 文本断言的先例,照同样方式写)。
|
||||
- 桌面端四个按钮的视觉排布肉眼无变化——这一条是**真机/浏览器项**,写进 `docs/testing/`。
|
||||
|
||||
---
|
||||
|
||||
### 任务 2 · BUG-696:CSS 平板上限对齐 JS 的 1024
|
||||
|
||||
**2.1** 把下列 `max-width: 900px` 改为 `max-width: 1023px`,使 CSS 的平板区间与 `sidebarViewportForWidth` 的 `[768, 1024)` 完全重合:
|
||||
|
||||
- `.code-form { grid-template-columns: 1fr 1fr; }`
|
||||
- `.model-selector-trigger { max-width: 100%; grid-column: 1; grid-row: 1; }`
|
||||
|
||||
**2.2** 两处 `(min-width: 768px) and (max-width: 900px)` 的首页栅格规则同样改为 `and (max-width: 1023px)`。
|
||||
|
||||
⚠️ 其中一处是 `.starter-list`/`.starter-hero` 相关。**如果前一轮(`TASK-chat-reading-load-20260915`)已经删掉了主题卡**,先确认这些选择器是否还有作用域;已成孤儿的规则直接删除,不要改了断点再留着。
|
||||
|
||||
**2.3** 改完检查 901–1023 区间内这几处的排版是否合理:模型选择器(是否还挤)、首页两张产品卡(单栏还是双栏)、兑换码表单。**这是浏览器项**,写进清单。
|
||||
|
||||
**验收标准**
|
||||
|
||||
- `grep -n "max-width: 900px" frontend/src/app/globals.css` 无结果。
|
||||
- 新增契约测试:断言 `globals.css` 中不出现 `900px` 作为宽度断点,且 `sidebar-state.ts` 的阈值仍是 `768` / `1024`。
|
||||
- 901 / 1023 / 1024 三个宽度下的目视确认写进 `docs/testing/`。
|
||||
|
||||
---
|
||||
|
||||
### 任务 3 · BUG-697:报告域三断点收敛为一个
|
||||
|
||||
**3.1** 把 `max-width: 720px`(报告中心)与 `max-width: 760px`(报告阅读区)**合并到 `max-width: 767px`**,与全局移动断点对齐。两组规则内容不变,只改条件并合并到同一个块里(或保持两块但条件一致,择一,写进 PROGRESS)。
|
||||
|
||||
**3.2** `max-width: 860px`(报告目录塌成抽屉)**保留为有理由的例外**,但必须在 `globals.css` 里就地加注释说明理由——目录是三栏布局的第三栏,它需要比正文更早塌陷,860 是内容宽度决定的,不是设备宽度。没有理由就一并并入 1023。执行方按实际布局判断并在 PROGRESS 里给结论。
|
||||
|
||||
**3.3** 噪音收敛(纯整理,行为不得变):
|
||||
|
||||
- `max-width: 639px` + `min-width: 640px`(会员)与 `max-width: 640px` + `min-width: 641px`(校正)统一为 **640/641 这一组**,即会员那对改成 `max-width: 640px` / `min-width: 641px`。差 1px,没有真实用户影响,只为让白名单更短。
|
||||
- `max-width: 430px`(toaster + 校正面)并入 `max-width: 480px`,**除非**并入后校正面在 431–480 之间明显变坏;若是,保留 430 并就地注释理由。
|
||||
- `max-width: 620px`(出生资料录入卡)并入 `640px`。
|
||||
|
||||
**3.4** 在 `globals.css` 顶部新增一段注释,声明**允许出现的宽度断点白名单**及各自含义:
|
||||
|
||||
```
|
||||
480 小屏手机
|
||||
640/641 内容级栅格塌陷(会员方案卡、校正候选卡、录入卡)
|
||||
767/768 移动 / 平板,与 sidebar-state.ts 对齐
|
||||
860 报告目录(第三栏,内容宽度决定)——若 3.2 判定无理由则删除本行
|
||||
1023/1024 平板 / 桌面,与 sidebar-state.ts 对齐
|
||||
```
|
||||
|
||||
**验收标准**
|
||||
|
||||
- `globals.css` 里出现的宽度断点值,全部在 3.4 的白名单内。
|
||||
- 新增契约测试:从 `globals.css` 抽出所有 `(max-width: Npx)` / `(min-width: Npx)` 的 N,断言集合等于白名单。**这条测试是本单最重要的防复发措施**——它让下一个人加断点时必须先改白名单。
|
||||
- 761 / 800 / 860 三个宽度下报告页的目视确认写进 `docs/testing/`。
|
||||
|
||||
---
|
||||
|
||||
### 任务 4 · 测试与文档
|
||||
|
||||
**4.1** 开工先量基线,写进 PROGRESS:
|
||||
|
||||
```
|
||||
cd .worktrees/mobile-touch-and-breakpoints-20260915/frontend
|
||||
npm ci
|
||||
npm test 2>&1 | tail -20 # pass / fail / tests 三个数字
|
||||
```
|
||||
|
||||
**4.2** 新增测试至少覆盖:任务 1 的命中区几何、任务 2 的 900px 消失 + JS 阈值不变、任务 3 的断点白名单。
|
||||
|
||||
**4.3** 文档:
|
||||
|
||||
- `frontend/DESIGN.md`:新增「断点」一节,写白名单与各自含义,并写明 CSS 必须向 `sidebar-state.ts` 对齐而不是反过来;触控目标一节写明「触屏 44×44、桌面视觉 26×26」的双轨规则。
|
||||
- `docs/BUG_HISTORY.md`:新增 BUG-695 / 696 / 697 三条,字段齐全(状态、现象、触发条件、根因、修复、验证、防复发、关联记录、修复版本)。视觉部分只有清单没有真机证据时,状态写 `resolved` 但在「验证」里如实写明「代码级契约测试通过,浏览器级验收见 `docs/testing/`」。
|
||||
- `docs/testing/mobile-touch-and-breakpoints-20260915.md`:把任务 1.3 / 2.3 / 3.x 里标了「浏览器项 / 真机项」的条目写成可照做的清单(给出具体宽度、具体页面、看什么)。
|
||||
- `CHANGELOG.md`:一条日期 + 一句话标题 + 要点。
|
||||
- `docs/tasks/PROGRESS-mobile-touch-and-breakpoints-20260915.md`。
|
||||
|
||||
---
|
||||
|
||||
## 6. 走查确认「已经做得好」的部分——本轮不得改动
|
||||
|
||||
执行方容易顺手"优化"掉这些,逐条列明:
|
||||
|
||||
| 项 | 现状 | 不要动的理由 |
|
||||
| --- | --- | --- |
|
||||
| `env(safe-area-inset-*)` | 侧栏、chat-header、composer、auth 面板全覆盖 | 刘海与 home bar 已适配正确 |
|
||||
| `min-width: 0` 纪律 | 全表贯彻,无固定大宽度 | 这是页面不横向溢出的原因 |
|
||||
| `dvh` | 15 处,`vh` 仅 3 处做降级兜底 | 已是正确形态 |
|
||||
| `@media (hover: hover)` 6 块 | 全部只承担颜色 / 位移装饰 | 没有 hover-only 的功能,触屏无损 |
|
||||
| 44px 触控纪律 | 侧栏汉堡、会话菜单、关闭、额度、模型选择器、follow-up 药丸、composer 发送全是 44 | 只有 `.message-actions` 与 `.markdown-code-copy` 破例,即本单任务 1 |
|
||||
| 深色主题 | 32 对对比度矩阵 + 契约测试 | 加任何颜色都要过那张矩阵 |
|
||||
| `prefers-reduced-motion` / `prefers-contrast` / `forced-colors` / `print` | 均有 | 完整 |
|
||||
| `.rectification-timeline` 的 `padding-inline` | 移动端已有覆盖(`--space-4 + --assistant-content-inset`),高度 64→56 | 内边距是为对齐头像栏,不是失误 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 让步顺序
|
||||
|
||||
1. 任务 3.2(860 例外)判不清就**保留 860 并注释**,不要强行并入——错并会让报告目录在 768–860 之间挤在正文旁。
|
||||
2. 任务 3.3 的三条噪音收敛,任何一条并入后观感变坏就**保留原值并就地注释理由**,白名单相应加一行。收敛是为了可维护,不值得拿观感换。
|
||||
3. 任务 1 若让出垂直空间后消息之间的节奏明显变松,**先只放大 `gap` 与相邻间距、命中区做到 44 宽 × 现有高**,把高度留到下一轮,写进 PROGRESS。
|
||||
4. 任务 2 的 901–1023 目视若发现模型选择器在新区间反而更差,**回退该条并在 PROGRESS 说明**,但 `.code-form` 的对齐照做。
|
||||
5. **绝不让步**:不得改 `sidebarViewportForWidth`;不得引 PostCSS 插件;不得为断点重构去改组件 JSX;断点白名单契约测试必须落地。
|
||||
|
||||
---
|
||||
|
||||
## 8. 开工前置命令
|
||||
|
||||
```bash
|
||||
cd /workspace/Jyotisha
|
||||
git status -sb | head -1
|
||||
git fetch origin --prune
|
||||
|
||||
# 确认前置轮次已合入
|
||||
git log --oneline origin/staging -5 # 应能看到 chat-reading-load 的实现提交
|
||||
|
||||
git worktree add -b codex/mobile-touch-and-breakpoints-20260915 \
|
||||
.worktrees/mobile-touch-and-breakpoints-20260915 origin/staging
|
||||
cd .worktrees/mobile-touch-and-breakpoints-20260915/frontend
|
||||
npm ci
|
||||
npm test 2>&1 | tail -20
|
||||
./node_modules/.bin/tsc --noEmit
|
||||
npm run lint
|
||||
```
|
||||
|
||||
纯前端改动,不要求 `scripts/pre_work_check.py`。
|
||||
|
||||
交付:
|
||||
|
||||
```bash
|
||||
git push origin HEAD:staging
|
||||
```
|
||||
|
||||
推完核对远端 SHA。
|
||||
|
||||
---
|
||||
|
||||
## 9. BUG 编号
|
||||
|
||||
- 本单占用 **BUG-695、BUG-696、BUG-697**。
|
||||
- `TASK-chat-reading-load-20260915.md` 若在执行中需要新编号,从 **BUG-698** 起。
|
||||
- 开工时仍需核对 `docs/BUG_HISTORY.md` 的当前最大号,可能已被别的轮次占用。
|
||||
@@ -0,0 +1,55 @@
|
||||
# 真机清单 · iOS 键盘是否遮挡输入框(2026-09-15)
|
||||
|
||||
**为什么需要人来测**:这一项无法从代码断定,也没有自动化替代。会话环境没有 iPhone、没有 Chrome、没有登录态。走查只能确认「风险形状成立」,不能确认「真的坏」。结论出来之前**不立修复单**。
|
||||
|
||||
## 代码侧已确认的事实
|
||||
|
||||
| 事实 | 位置 |
|
||||
| --- | --- |
|
||||
| 页面自身不可滚动 | `frontend/src/app/globals.css` → `html, body { width: 100%; height: 100%; overflow: hidden; }` |
|
||||
| 应用外壳锁死视口高度 | `.group\/sidebar-provider[data-viewport] { height: 100dvh; overflow: hidden; }` |
|
||||
| 输入框是滚动区外的粘性行 | `.composer-wrap { position: sticky; bottom: 0; }`;`.chat-panel` 用 `grid-template-rows` 把它排成独立一行 |
|
||||
| 只声明了 Android 认的键盘策略 | `frontend/src/app/layout.tsx` → `viewport.interactiveWidget = "resizes-content"`。**iOS Safari 不支持这个属性,会忽略** |
|
||||
| 没有任何 `visualViewport` 监听 | `grep -rn "visualViewport" frontend/src` = 0 命中 |
|
||||
|
||||
这是「app shell + 锁定高度 + 粘性输入框」的典型形状。iOS 在键盘弹出时不缩小布局视口,只缩小可视视口;系统自带的 scroll-into-view 兜底在 `overflow: hidden` 的外壳里没有可滚的东西。**但 iOS 也可能自行平移可视视口把输入框顶上来**,所以必须实测。
|
||||
|
||||
## 怎么测
|
||||
|
||||
设备:iPhone。两个浏览器各测一遍——**Safari** 和**微信内置浏览器**(后者用的是 WKWebView,行为可能不同,而且很可能是真实用户的主要入口)。
|
||||
|
||||
地址:`https://staging.jyotisha.chat`
|
||||
|
||||
### A. 聊天输入框
|
||||
|
||||
1. 登录,进入任意一个已有会话(不要用空首页,空首页的布局不同)。
|
||||
2. 点一下底部输入框,等键盘完全弹出。
|
||||
3. **看**:输入框整条是否还完整可见?发送按钮是否露在键盘上方?
|
||||
4. 连打三行以上文字,让输入框自己长高(它 `max-height: 128px`)。**看**:长高之后是否被键盘吃掉?
|
||||
5. 输入过程中,上方最后一条消息是否还看得见?还是被顶没了?
|
||||
6. 收起键盘。**看**:页面有没有留下一块空白,或者整体位置偏了没还原。
|
||||
|
||||
### B. 长会话里的输入框
|
||||
|
||||
1. 找一个消息很多、需要滚动的会话,滚到中间位置(不在底部)。
|
||||
2. 点输入框。**看**:弹键盘时页面有没有突然跳到别处。
|
||||
|
||||
### C. 登录页与资料录入
|
||||
|
||||
1. 退出登录,在 `/login` 点邮箱输入框。**看**:键盘弹出后输入框和「获取验证码」按钮是否都还可见。
|
||||
2. 新账号走一遍姓名 → 出生日期 → 出生时间 → 出生地搜索。出生地搜索会弹下拉列表,**重点看**:下拉列表是否被键盘压住、能不能点到。
|
||||
|
||||
### D. 横屏
|
||||
|
||||
把手机横过来重复 A.2。横屏时键盘占比更大,最容易暴露。
|
||||
|
||||
## 怎么回报
|
||||
|
||||
每一条写「正常 / 有问题 + 一句现象 + 截图」。截图请**不要**带真实姓名、出生资料或会话内容——用一个测试账号,或者截图后把这些涂掉。
|
||||
|
||||
- 如果 A–D 全部正常:这一项关闭,记进本文件末尾,不开修复单。
|
||||
- 如果任何一条有问题:把现象贴回来,我据此出修复单。预判的修法是引入 `visualViewport` 监听把键盘高度写进一个 CSS 变量,由 `.composer-wrap` 消费;但具体怎么改要看实际是哪一种坏法。
|
||||
|
||||
## 结论
|
||||
|
||||
> 待填。测完把结论写在这里(日期 + 设备 + 浏览器 + 逐条结果),不要另开文件。
|
||||
Reference in New Issue
Block a user