# PROGRESS · C 端界面对齐 R3(侧栏拍平、入口收敛、去头像) 任务书:`docs/tasks/TASK-cend-ui-claude-alignment-20260916.md` 的 R3 执行方式:**直接执行模式** 分支:`codex/cend-ui-r3-20260916` 基线:`origin/staging` = `62903b7a`(R2 合入后) BUG 段:不占用(产品改造,非缺陷) --- ## 又一处与任务书不符的现状 任务书 E6 描述侧栏是「品牌 / 新建对话 + 我的报告 / 星盘列表 / 收藏对话 details / 历史对话 details / 账户」。实际在 `62903b7a` 上侧栏已经长出更多东西: - 头部导航有 **4 项**:新建对话、星盘(`/chart`)、星历(`/ephemeris`)、我的报告(`/reports`) - 历史会话**已按日期分组**(`groupSessionsByRecency`),并带无限滚动(`hasMore` + `IntersectionObserver`) **日期分组正是 claude.ai 的做法,予以保留**,本轮只拆折叠层与冗余入口。 --- ## T3.1 · 侧栏拍平 三段结构(星盘列表组 + 两个 `
`)合并为**一条平铺列表**: | 改前 | 改后 | |---|---| | `SidebarGroup.chart-nav`「星盘列表」+ 加号 + 名字 chip 网格 | **整组删除**(见 T3.2) | | `
`「收藏对话」+ chevron | 列表顶部的一个 `sidebar-group-label`「收藏」,带 13px 星标 | | `
`「历史对话」+ chevron | 同一条列表,沿用原有的日期分组标签 | | 两处空态文案 | 一处:`暂无对话,点上方「新建对话」开始` | 列表缩进从 `calc(var(--space-3) + 18px + var(--space-2))`(为对齐折叠标题的图标)改为 `0 var(--space-3) var(--space-1)`——不再嵌在可折叠标题之下,没有需要对齐的图标了。 **键盘可达性**:`handleExpandHistory` 的焦点转移链路保留。原来焦点落在 `` 上,现在落在 `

`,`historyHeadingRef` 的类型从 `HTMLElement` 收窄为 `HTMLParagraphElement`。`firstSessionRef ?? historyHeadingRef` 的优先级不变。 | 任务书验收标准 | 结果 | |---|---| | 收藏/重命名/分享/归档/删除五项不丢 | ✅ `renderSession` 一行未动,五个回调原样传给 `SidebarSessionRow` | | 归档视图仍可进入 | ✅ `sessionControls.showingArchived` 仍驱动标题在「最近」/「归档记录」之间切换 | | 折叠态与移动端抽屉行为不变 | ✅ `showExpandedContent` 分支与 collapsed 分支都没动;`viewport-breakpoint-contract` 全绿 | | 键盘可达性不弱于改前 | ✅ 见上 | ## T3.2 · 星盘入口收敛 **这里我偏离了任务书 D6 的字面写法,方向相反。** D6 写的是「收敛到侧栏一处,账户菜单里的『星盘资料』项删除」。我做的是**反过来**:删掉侧栏的星盘列表组,保留账户菜单里的「星盘资料」。 理由两条: 1. **D6 写于侧栏只有 2 个头部导航项的时候**,现在是 4 个(新建对话/星盘/星历/我的报告)。再塞第 5 项会把头部压得很重。 2. **「星盘资料」是管理动作,不是导航目的地**——它打开的是设置弹窗的一个分区,和「个人资料」「通用设置」同级。而侧栏那组 chip 点下去也只是开同一个弹窗(`page.tsx` 里 `onSelectChart` / `onAddChart` / `onOpenChartLibrary` 三个回调全是 `openAccountDialog("chart-library")`),**一组点了只会开弹窗的名字不提供任何导航价值**。 D6 的真实目标是「收敛到一处」,两种做法都满足;选哪个留下是我的判断,在此披露。若产品认为必须在侧栏可见,改回来是加一个 `SidebarMenuItem` 的事。 连带删除:`charts` / `onSelectChart` / `onAddChart` 三个 props、`SidebarChart` 类型、`page.tsx` 里的 `sidebarCharts` 派生,以及 `.chart-nav-list` / `.chart-nav-chip` / `.session-nav-header` / `.session-nav-toggle` / `.sidebar-label` / `.sidebar-section*` 一批 CSS。 ## T3.3 · 删掉助手消息头像 `AgentAvatar` 组件、两处渲染点(`chat-message-row.tsx`、`onboarding-chat-message.tsx`)、三条 CSS 规则全部删除。 `--assistant-content-inset` 从 `calc(32px + var(--space-3))` 改为 `0px`。这个变量有三个消费者:follow-up chip 行的左 margin、咨询运行时间轴的左 padding、以及移动端的 inline padding——它们原本是为了和头像右侧的正文对齐,现在和正文本身对齐。 | 任务书验收标准 | 结果 | |---|---| | `/jyotish-logo.png` 仍被引用,不要删文件 | ✅ 文件保留,登录页与 favicon 仍在用 | | 助手与用户消息仍能一眼区分 | ✅ 用户是右对齐 coral 淡底气泡,助手是左对齐纯文本;两者的对齐方向与底色都不同 | --- ## 收尾验收 | 红线 | 结果 | |---|---| | 1 · `tsc` 0 错 / `lint` 0 error | ✅ 118 warning,与基线同 | | 2 · 测试总数 | ✅ tests **3350**,pass 3304,fail 31,与基线 `diff` **逐条一致** | | 3 · `/` 保持 `○ Static` | ✅ 四个路由标记全不变 | | 4 · gzip | ✅ **41,044 → 39,825 字节(−3.0%)**;累计相对基线 41,095 降 **3.1%** | | 5 · `page.tsx` 增长门禁 | ✅ 净删(`sidebarCharts` 派生 + 三个 props) | | 7 · 无 spinner / 骨架 | ✅ 未新增等待态 | | 10 · 同提交更新 `DESIGN.md` | ✅ 「Sidebar shell」的展开内容与空态两条重写、新增拍平理由;「Message」的 Identity 一条重写 | | 11 · 不升依赖、不留新 warning | ✅ | Python 快速门(BUG-736 防复发):本轮改了 `page.tsx`,`pytest tests/test_supabase_user_data_contract.py` 8 条全绿。 ### 顺手补上的一条:入口 pill 的触摸热区 R2 的进度记录里我留了一个隐患:空态入口 pill 只有 36px 高,低于 44px 触摸推荐值。本轮 `touch-target-contract` 因为 `.chart-nav-chip` 被删而打红,正好是管这类控件的合同——于是给 `.starter-entry` 补了 `::after { inset: -4px }` 的热区扩展(与 `.message-actions button`、`.auth-links button` 同一套做法:保持视觉尺寸,扩大命中区),并把它写进该合同接替 `.chart-nav-chip` 的位置。R2 那条隐患就此关闭。 ### 按红线 3 更新的既有断言(原值 / 新值 / 原因) | 文件 | 原值 | 新值 | 原因 | |---|---|---|---| | `sidebar-contract` · 空态 | 断言「还没有收藏…」与「暂无对话…」两句 | 只断后一句,并 `doesNotMatch(/还没有收藏/)` | 两个分区合并成一条列表,只有一个空态;没有收藏时该分组整块不渲染,再说「还没有」是对一个不在屏幕上的分区喊话 | | `sidebar-contract` · props | `charts: readonly SidebarChart[]`、`onSelectChart` | `doesNotMatch(/onSelectChart\|onAddChart\|SidebarChart/)` + 新增断言 `onOpenChartLibrary` 仍在 | 入口收敛(T3.2)。这条**收紧**了:从「必须有」变成「必须没有」,并锁住幸存的那一个 | | `sidebar-contract` · 标题色阶 | 选择器 `.sidebar-label, .sidebar-section-summary` | `.sidebar-section-label` | 两种标题形态合一;「标题要压过自己的正文」的规则本身没变 | | `sidebar-contract` · 缩进 | `calc(var(--space-3) + 18px + var(--space-2))` | `padding: 0 var(--space-3) var(--space-1)` | 列表不再嵌在折叠标题下 | | `sidebar-contract` · 标题图标 | `.sidebar-label > svg` 与 `.sidebar-section-summary > svg` 各 18px | `.sidebar-group-label > svg` 用强调色 | 唯一剩下的标题是「最近」两字不带图标;收藏的星标是 13px 行内标记 | | `rectification-agentic-entry`、`rectification-timeline-20260909` | `--assistant-content-inset: calc(32px + var(--space-3))` | `0px` | 头像删除 | | `class-name-definition-contract` | `knownUnstyled` 含 `chart-nav` | 移除 | 类名已不存在 | | `touch-target-contract` | `.chart-nav-chip` 32px + 热区 | `.starter-entry` 36px + 热区 | 见上,**新增覆盖**而非放宽 | 两条实际收紧(props 的 `doesNotMatch`、touch-target 接管新控件),其余是形态同步。 --- ## 环境缺口(不得记为通过) 1. **侧栏抽屉在移动端的手势与焦点行为**(折叠态、抽屉开合、Escape 关闭)。 2. **拍平后长会话列表的滚动与无限加载**:日期分组标签在连续滚动中的粘滞表现。 3. **去掉头像后助手/用户消息的可区分度**——自动化只能证明两者的对齐与底色不同,实际观感要真机看。 4. 承接 R2 的两项:空态首屏可见性、入口 pill 触摸(本轮已补热区,仍需真机确认)。 --- ## 三轮完结 R1 / R2 / R3 全部实现并合入。`TASK-cend-surfaces-claude-alignment-20260916.md`(R4–R8,五个次级面)尚未开工。