#111 第 3 轮:建档不退回加载、右栏能拖宽、清单不迟到、月亮问句与别人的上升句(BUG-1455~1459)

- 建档重读人物名单时保留旧名单,失败也不卡在加载画面(BUG-1455)
- 对话右栏改用自己的拖宽把手,侧栏与右栏都能用方向键(BUG-1456/1457)
- 启程清单胶囊和首页一起出来,读状态时用上次的样子占位(BUG-1458)
- 起步第一问与别人的天空过场读一次已算好的星盘取星座,上升只在不会换座时用(BUG-1459,产品 10-27 同意)
- 补回删减的断言与三栏说明;登录代码改回原样,替身放进测试;删旧校正画面的无用样式
- 首屏 +7.54% 产品已接受,写进 DESIGN

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LutgzyJqNhPpZy1nFsJtN3
This commit is contained in:
Jesse_Chen
2026-10-27 10:24:57 +08:00
co-authored by Claude Opus 5.5
parent 75cf7ad0e0
commit de9d4826c1
35 changed files with 1005 additions and 183 deletions
+8 -6
View File
@@ -4,7 +4,7 @@
## 1. 组件一律用 shadcn base-nova,令牌如下
控件放在 `src/components/ui`,一律用 shadcn base-nova。缺的组件用固定版本的 shadcn CLI 加,不手抄,也不改组件的行为。图标只用 Lucide。动效只用 Motion,时长和曲线用下一节的预设。可拖宽、可收起的分栏用 react-resizable-panels。拖动排序用 dnd-kit。跨组件状态用 Zustand。
控件放在 `src/components/ui`,一律用 shadcn base-nova。缺的组件用固定版本的 shadcn CLI 加,不手抄,也不改组件的行为。图标只用 Lucide。动效只用 Motion,时长和曲线用下一节的预设。可拖宽、可收起的分栏用 react-resizable-panels;侧栏右缘和对话右栏左缘这两处单边拖宽改用 `useDragWidth`(2026-10-27,BUG-1456)。拖动排序用 dnd-kit。跨组件状态用 Zustand。
`globals.css` 在 Tailwind 的下一行引入 `shadcn/tailwind.css`。长相不换:下面的色板就是令牌,映射成 shadcn 的 `--background`、`--primary` 等。深色跟着已有的 `--color-*`,不另抄一套。星盘、星图的 SVG 绘制,以及那一刻的天空这张画布,仍按后面的章节手绘。
@@ -852,7 +852,7 @@ Agent 的 live 标记只有 `InlineSpinner` 一种。曾经并存的 canvas 小
**今日星语改为固定句库,并随次级页预取(2026-09-30,BUG-1109 / BUG-1110)。** 首页问候下面那句不再由模型写:`lib/daily-starlanguage-library.ts` 按「今日月亮落在本命第几宫(1–12,只在出生时间已确认时用)× 月相(新月前后 / 渐盈 / 满月前后 / 渐亏,按平均朔望月推算,误差约 ±1 天)× 按日期轮换的变体」拼出 trend,action / caution 按宫各两条交替;没有宫位时按月亮所在星座写一句,再没有就用原来的证据句。服务端不再在后台让模型改写并覆盖缓存,所以同一天同一个人看到的永远是同一句。次级页空闲时的预取(BUG-1104)同时取本人今天这句,写进同一个暖快照槽位与本地存储;从星盘等页点「新建对话」进首页,首帧就是真句子,不再先显示「今天的星语还没写出来。」再换掉。他人档案作为当前人物时暂不预取(其资料在人物目录里),首帧仍按原规则。
首页只揭幕一次。揭幕前的加载屏先并行取账户 / 会话、模型目录和咨询状态,再等待 lookup、会话详情等依赖数据全部到齐;不设 8 秒硬超时,超过 `HOME_BOOTSTRAP_SLOW_MS = 20_000` 才进入现有全屏错误屏。错误屏的「重试」只取消旧请求、重载 provider 并局部重跑 bootstrap,不调用 `location.reload()`。揭幕后不得再出现任何阻塞等待或组件级 spinner:今日星语未到时问候下方副行显示静态文案「今天的星语还没写出来。」(不带 `aria-busy`),内容到达后静默替换。登录后的空首页是问候语、今日星语和输入框,没有主题卡,也没有生时校正卡(2026-10-07,BUG-1247)。本人还没有出生资料时,今日星语的按钮和问候下那一行都不出现(2026-10-24)。建档是四步:称呼、看谁的盘、出生日期与时间、出生地,进度条四格。选「帮别人看」时出生资料记在那一位名下,本人可以后补。首问还没用掉、并且当前是空白首页时,问候和输入框之间有一行引导、一枚「这一次不扣点」和三个起步问题;帮别人看再加一枚「正在看:名字 · 关系」。用掉首问或离开空白首页后,这三问不再出现。已经建完档、还没点过「先不看了」、并且不是进站时就已经七项都做过时,顶栏右侧有「启程 n/N」。尺寸、抽屉和提示互斥见文首「启程清单与一次性提示」。过场结束仍不弹浮层。切换到消息尚未缓存的会话时消息区留白并只给 `sr-only` 文案,不转圈;揭幕后按侧栏顺序后台预取最近 5 条会话(`SESSION_PREFETCH_COUNT`)让常见切换零等待。轨道环消失后不得再换一套动效继续等。
首页只揭幕一次。揭幕前的加载屏先并行取账户 / 会话、模型目录和咨询状态,再等待 lookup、会话详情等依赖数据全部到齐;不设 8 秒硬超时,超过 `HOME_BOOTSTRAP_SLOW_MS = 20_000` 才进入现有全屏错误屏。错误屏的「重试」只取消旧请求、重载 provider 并局部重跑 bootstrap,不调用 `location.reload()`。揭幕后不得再出现任何阻塞等待或组件级 spinner:今日星语未到时问候下方副行显示静态文案「今天的星语还没写出来。」(不带 `aria-busy`),内容到达后静默替换。登录后的空首页是问候语、今日星语和输入框,没有主题卡,也没有生时校正卡(2026-10-07,BUG-1247)。本人还没有出生资料时,今日星语的按钮和问候下那一行都不出现(2026-10-24)。建档是四步:称呼、看谁的盘、出生日期与时间、出生地,进度条四格。选「帮别人看」时出生资料记在那一位名下,本人可以后补。首问还没用掉、并且当前是空白首页时,问候和输入框之间有一行引导、一枚「这一次不扣点」和三个起步问题;帮别人看再加一枚「正在看:名字 · 关系」。用掉首问或离开空白首页后,这三问不再出现。第一问里的上升和月亮星座先取今日星语;没有今日星语时(出生时间不到分钟,或在看别人),读一次已算好的星盘,和星盘页共用同一份结果。上升只在出生时间范围内不会换座时才写;读到之前、读不到时,问题保持「从我的盘看……」的说法,不转圈(BUG-1459)。给别人建档后的天空过场,副句「那一刻,{名字}的上升在……」同样来自这一份,上升会换或读不到就不写这一句。已经建完档、还没点过「先不看了」、并且不是进站时就已经七项都做过时,顶栏右侧有「启程 n/N」。尺寸、抽屉和提示互斥见文首「启程清单与一次性提示」。过场结束仍不弹浮层。切换到消息尚未缓存的会话时消息区留白并只给 `sr-only` 文案,不转圈;揭幕后按侧栏顺序后台预取最近 5 条会话(`SESSION_PREFETCH_COUNT`)让常见切换零等待。轨道环消失后不得再换一套动效继续等。
### 首屏死屏兜底
@@ -1267,23 +1267,25 @@ Yogini 还在取时,右栏用和 Chara 相同的轨道等待(`OrbitWaiting`
## 外壳(2026-10-24)
桌面侧栏宽 200–360px,默认 288。右侧把手是组件库按钮,仍是 6px 透明细条;拖它调整宽度。拖到比 200 更窄就收成 64px 窄轨;收起不把 64 写成宽度。宽度记在本机 `sidebar_width`。侧栏和主区始终在各自的容器里:视口就绪、跨过手机断点,都不会把整页卸掉再挂上。手机用左侧抽屉,宽 `min(86vw, 320px)`。当前页高亮用已有的 `layoutId` 滑动。翻页用已有的页面进入 280ms、离开 150ms,方向跟着侧栏顺序。顶栏点数是描边按钮:硬币图标加数字,44px;「点」只在可读名称里。数字变少时往下滚,变多时往上滚,360ms;系统要求减少动态时立刻换数字。启程清单胶囊仍是 32px,仍在点数左边。账户按钮只显示头像和名字。设置仍是三个分区。会话只在收藏组内、或最近一组内拖动排序;收藏整组仍在最前。翻页、高亮滑动和拖动排序用的库在页面出来后再载入,不进首屏。拖宽不再另载一套分栏库。
桌面侧栏宽 200–360px,默认 288。右侧把手是组件库按钮,仍是 6px 透明细条;拖它调整宽度。把手能用 Tab 选中,左右方向键每次 16px,Home / End 到最窄 / 最宽,键盘不会把侧栏收起;读屏读作竖向分隔条,带当前宽度(BUG-1457)。拖到比 200 更窄就收成 64px 窄轨;收起不把 64 写成宽度。宽度记在本机 `sidebar_width`。侧栏和主区始终在各自的容器里:视口就绪、跨过手机断点,都不会把整页卸掉再挂上。手机用左侧抽屉,宽 `min(86vw, 320px)`。当前页高亮用已有的 `layoutId` 滑动。翻页用已有的页面进入 280ms、离开 150ms,方向跟着侧栏顺序。顶栏点数是描边按钮:硬币图标加数字,44px;「点」只在可读名称里。数字变少时往下滚,变多时往上滚,360ms;系统要求减少动态时立刻换数字。启程清单胶囊仍是 32px,仍在点数左边。账户按钮只显示头像和名字。设置仍是三个分区。会话只在收藏组内、或最近一组内拖动排序;收藏整组仍在最前。翻页、高亮滑动和拖动排序用的库在页面出来后再载入,不进首屏。拖宽不再另载一套分栏库。
## 对话页(2026-10-25)
输入框仍是一个框。框底左边是模型菜单,只显示模型名;价格「N 点」只在菜单里。菜单用外壳已有的延后载入,不进首屏;库还没到时按钮上仍是模型名。右边是圆形发送,和框的底边对齐。回答下面赞、踩、复制、重新生成是 26px 的图标按钮,各有一句提示。不满意原因和兑换窗用组件库对话框,句子不改。追问是描边小按钮,仍按启程进场依次浮出(260ms,间隔 64ms),不另写一套时长。
桌面顶栏、点数右边,是打开或收起本命盘的图标按钮,提示「打开本命盘」或「收起本命盘」。面板宽 280–560px,默认 360。拖到最窄可以收起。开着和宽度记在本机 `chat_chart_panel_open`、`chat_chart_panel_width`。手机(视口还没定,或小于 768)不显示这个按钮,也不因为藏起来就把「开着」写成关掉。面板里是当前人物的本命盘,复用星盘页的绘制,不写骨架、不写「正在加载」。对话列始终留在原处。本命盘在第一次打开后载入,加在对话列旁边,不把对话列卸掉再挂上。星盘绘制不进首屏。
桌面顶栏、点数右边,是打开或收起本命盘的图标按钮,提示「打开本命盘」或「收起本命盘」。面板宽 280–560px,默认 360。面板左缘是和侧栏同样的 6px 透明把手(`.chat-chart-resize-handle`),面板左边一条 1px 分隔线。拖它调宽度,拖到比 280 更窄就收起;方向键同侧栏,不会收起。面板不再放进分栏组:对话列在面板外面,组里只剩面板一个时把手拖不动(BUG-1456)。开着和宽度记在本机 `chat_chart_panel_open`、`chat_chart_panel_width`。手机(视口还没定,或小于 768)不显示这个按钮,也不因为藏起来就把「开着」写成关掉。面板里是当前人物的本命盘,复用星盘页的绘制,不写骨架、不写「正在加载」。对话列始终留在原处。本命盘在第一次打开后载入,加在对话列旁边,不把对话列卸掉再挂上。星盘绘制不进首屏。
## 新用户启程(2026-10-25)
首页顶栏右侧、点数按钮左边,是一枚胶囊「启程 n/N」(`.onboarding-checklist-trigger`)。它沿用顶栏按钮的 32px 高度,圆角 999px,字和图标间距 6px。左边是 18×18 的进度环,描边按已完成的项画满。视口还没分出手机或桌面时,这枚胶囊不可打开。手机(侧栏视口小于 768)从底部抽屉拉出,带现有的下拉把手。平板和桌面用现有弹出层,靠右对齐,宽 `min(22rem, calc(100vw - 2rem))`,行是 `1.25rem minmax(0, 1fr) auto`,句子 `overflow-wrap: anywhere`。已完成的行用对勾,没有「去做」。底部是「先不看了」。
首页顶栏右侧、点数按钮左边,是一枚胶囊「启程 n/N」(`.onboarding-checklist-trigger`)。它沿用顶栏按钮的 32px 高度,圆角 999px,字和图标间距 6px。左边是 18×18 的进度环,描边按已完成的项画满。视口还没分出手机或桌面时,这枚胶囊不可打开。胶囊的样子和首页一起出来:弹层代码延后载入,但胶囊不等它,载入前胶囊在、不能点。账户的启程状态还在读的时候,用这台浏览器上次看到的胶囊(本机 `onboarding_checklist_face:<账户>`)占住位置;读回来说不显示就拿掉。从没见过清单的浏览器不占位(BUG-1458)。手机(侧栏视口小于 768)从底部抽屉拉出,带现有的下拉把手。平板和桌面用现有弹出层,靠右对齐,宽 `min(22rem, calc(100vw - 2rem))`,行是 `1.25rem minmax(0, 1fr) auto`,句子 `overflow-wrap: anywhere`。已完成的行用对勾,没有「去做」。底部是「先不看了」。
七项在这一次使用里刚满时,抽屉或弹出层再打开一次,进度环处同时迸一次星点(1000ms,只一次)。标题「都走过一遍了」,正文「以后有新东西,我会在用到的时候再告诉你。」关掉后胶囊消失。进站时已经满的账户,胶囊、这一屏和星点都不出现。
一次性提示用现有弹出层,宽 `min(18rem, calc(100vw - 2rem))`,不抢焦点。侧栏两项从锚点右侧伸出,其余从上方伸出,间距 8px。按钮是「知道了」。同一时刻最多一条。天空过场、兑换窗、任何弹窗或抽屉、启程清单正打开、回答还在生成时,提示不出;挡着的那一条等条件过去再出。侧栏「星盘」、手机菜单和星盘四个页签上的小圆点是 8px,贴在右上角 4px,不是字符。
启程专用动效只在启程里播放:清单还开着且有未完成项,或账户还没完成第一问。清单已经关掉的账户不播追问进场、档案卡进场、星盘和大运画出、合盘头像靠拢。动效代码还没到手、或 300ms 内没到手时,内容保持可见,不先藏起来。只在元素第一次出现时播放。重绘、来回切换不重播。除回答流式中的呼吸点外,没有无限循环。只动 `opacity`、`transform`、颜色、`clip-path`,不触发布局。Motion 用到才加载,不进首屏。启程清单、一次性提示和启程动效宿主也在页面出来后再载入,不进首屏。没载入之前不占位、不转圈;内容保持可见。系统开启「减少动态效果」时,星点和圆点闪烁去掉,其余只淡入,没有位移、缩放和擦除。
启程专用动效只在启程里播放:清单还开着且有未完成项,或账户还没完成第一问。清单已经关掉的账户不播追问进场、档案卡进场、星盘和大运画出、合盘头像靠拢。动效代码还没到手、或 300ms 内没到手时,内容保持可见,不先藏起来。只在元素第一次出现时播放。重绘、来回切换不重播。除回答流式中的呼吸点外,没有无限循环。只动 `opacity`、`transform`、颜色、`clip-path`,不触发布局。Motion 用到才加载,不进首屏。启程清单的弹层、一次性提示和启程动效宿主也在页面出来后再载入,不进首屏。提示和动效宿主没载入之前不占位、不转圈;内容保持可见。清单胶囊例外,见上文。
首屏体积:组件库迁移后首页 `/` 的首屏 gzip-9 是 694,941 字节,比迁移前基线 `0f66d92d4`(646,201)大 7.54%,超出 ±2%。多出来的是组件库外壳和整站样式,能延后的(清单弹层、提示、动效、拖动排序、分栏)都已延后。产品负责人 2026-10-27 接受这个数(issue #111)。之后的轮次以新数为基线,继续按 ±2% 管。系统开启「减少动态效果」时,星点和圆点闪烁去掉,其余只淡入,没有位移、缩放和擦除。
| 类别 | 用在哪 | 时长 | 曲线 |
| --- | --- | --- | --- |