fix(web): 次级页稳定外壳与缓存预取,跨部署导航自愈(BUG-966/967)
This commit is contained in:
+21
-13
@@ -395,14 +395,21 @@ shell. Each used to own a full-screen layout — a `*-shell` root, a `*-topbar`
|
||||
with one 「返回对话」 link, and a `*-hero` with a page-sized h1 — three copies of
|
||||
one skeleton, none of them carrying the sidebar.
|
||||
|
||||
- **Composition:** `app/(secondary)/layout.tsx` = `SidebarProvider` →
|
||||
`AppSidebar` (read-only) → `SidebarInset.chat-panel.secondary-panel`. The
|
||||
route group changes no URL; what it changes is that the four routes share
|
||||
**one** shell instance, so moving between them neither remounts the sidebar
|
||||
nor re-reads the session list. Each page contributes only `SecondaryHeader`:
|
||||
the same 46px row the chat page uses — sidebar trigger, page name, an optional
|
||||
quiet note chip, and up to two right-aligned actions. The body is the only
|
||||
thing that scrolls, and it owns the page floor (`--color-canvas-soft`).
|
||||
- **Composition:** `app/(app)/layout.tsx` = `SessionListProvider` →
|
||||
`SidebarProvider` → `AppSidebar` → `SidebarInset.chat-panel.secondary-panel`
|
||||
(home registers its own inset class). `/chart`, `/ephemeris` and `/reports`
|
||||
share `SecondaryPageShell`: the same 46px `SecondaryHeader` (sidebar trigger,
|
||||
page name, a reserved note slot so a late birth line cannot collapse the row,
|
||||
up to two actions) and a `.secondary-page` body that always fills the
|
||||
remaining viewport. Waiting copy is centered in that cell; swapping in the
|
||||
tall content does not change the shell height. No spinner, skeleton, or
|
||||
「正在加载」. First-screen data for the three pages lives in a module-level
|
||||
cache; a second visit paints the last result immediately and refreshes in
|
||||
the background. Sidebar `pointerenter` / `pointerdown` prefetches that data
|
||||
(`<Link>` only prefetches JS). A tab that outlived a deploy compares
|
||||
`NEXT_PUBLIC_GIT_COMMIT` with `/api/health` `.deployment.gitCommit` on
|
||||
visibility and before navigation; a mismatch uses `window.location.assign`,
|
||||
a match keeps the client router.
|
||||
- **One sidebar component, two modes.** `AppSidebar` is the only sidebar in the
|
||||
product. `/` passes `controls`; the secondary layout does not, and without it
|
||||
the same markup renders read-only. There used to be a second component for
|
||||
@@ -419,10 +426,11 @@ one skeleton, none of them carrying the sidebar.
|
||||
deleting stay on `/`, backed by `Home()`'s optimistic-update and rollback
|
||||
layer, which is far more than these four routes need.
|
||||
- **Leaving the chat is a navigation, not a reload.** 星盘 / 星历 / 我的报告 are
|
||||
`<Link>` on every page, including `/`, where they used to be a full document
|
||||
`AppLink` on every page, including `/`, where they used to be a full document
|
||||
load that threw away the React tree, the session list and the account. Only
|
||||
`/login` stays a hard exit, and `persistLoginSessionReturn()` still stashes the
|
||||
`?c=` before any of them.
|
||||
`?c=` before any of them. After a deploy, a stale tab's next `AppLink` is the
|
||||
hard exit: `window.location.assign`, not a silent client-router no-op.
|
||||
- **Loading:** the sidebar renders its nav immediately and fills the list when
|
||||
`/api/sessions` returns. While that is in flight the list area carries static
|
||||
copy — never a skeleton, per the unified-loading ruling. A list read in the
|
||||
@@ -446,7 +454,7 @@ one skeleton, none of them carrying the sidebar.
|
||||
- **Surface:** `--color-canvas-soft` floor; rows use `--color-canvas`, a warm hairline, and `--radius-lg` on the list as a whole. No drop shadow.
|
||||
- **Width:** 900px centered, matching long-form chat reading. Rows stack at the global 767px cut.
|
||||
- **Actions:** “生成完整报告” is the one filled action. A ready row keeps “查看报告” as the primary document action with “导出报告(.md)” quiet beside it. The export downloads the same longform Markdown the detail page renders. Generating copy is one-step (“正在生成报告,大约 10–30 秒”); there is no chapter-count progress. A failed row states the reason in place and offers no second generate entry — the header already has one. Card summary is a deterministic excerpt of the Markdown 「摘要」 section, stored on the cover document at generation time.
|
||||
- **States:** loading, empty, populated, generating, ready, failed, unauthorized, list error. Export work uses the shared inline spinner inside the initiating button, reports a short row-local error, and never starts a second writing flow. A missing Markdown appendix is an old report: the detail page asks the reader to regenerate.
|
||||
- **States:** loading, empty, populated, generating, ready, failed, unauthorized, list error. First-screen loading uses `SecondaryPageShell` waiting copy 「报告列表还没拿到。」 — never a spinner, skeleton, or 「正在加载」. Export work uses the shared inline spinner inside the initiating button, reports a short row-local error, and never starts a second writing flow. A missing Markdown appendix is an old report: the detail page asks the reader to regenerate.
|
||||
- **Accessibility:** generate, refresh, and row actions are 44px. The generating row's chip is a live region; a failed export is an alert.
|
||||
|
||||
### Personal report reader
|
||||
@@ -828,7 +836,7 @@ Three product rules for assistant markdown in `.message-markdown` (BUG-962 / 963
|
||||
|
||||
### 等待态
|
||||
|
||||
星盘页是独立文档。外壳揭幕(标题、返回)可以在主盘到达之前发生;揭幕之后填数据不得再出现 spinner / 骨架 / 「正在加载」,沿用 §9 星历页那一类静态句,不新造第五套加载动画。
|
||||
星盘页是独立文档。`SecondaryPageShell` 揭幕(标题、保留的 note 槽、撑满剩余视口的内容区)可以在主盘到达之前发生;揭幕之后填数据不得再出现 spinner / 骨架 / 「正在加载」,沿用 §9 星历页那一类静态句,不新造第五套加载动画。同一会话再次进入直接用模块缓存,不重放等待句。
|
||||
|
||||
| 时刻 | 文案 |
|
||||
| --- | --- |
|
||||
@@ -850,6 +858,6 @@ Three product rules for assistant markdown in `.message-markdown` (BUG-962 / 963
|
||||
- **当日行运:** 九曜的星座、度数、相对本命宫位、顺逆。桌面表格,767px 以下每行改成带标签的堆叠。没有本命上升时,相对本命列为空,并写「还没有本命上升,相对本命这一列空着。」
|
||||
- **未来九十天:** 按日期升序只写事实(「某星 进入 某座」「某星 停滞转顺 · 度数」)。`/api/ephemeris_events` 未上线时整段静态说明:「换座和停滞还没接上。这一页其余部分不受影响。」不得让整页失败。
|
||||
- **出口:** 主按钮「带这天去提问」在顶栏,把当前日期预填进对话草稿并回到 `/`。不写「这一页是天象本身,不是对你的判断。」
|
||||
- **等待:** 揭幕后不得再出现 spinner / 骨架 / 「正在加载」。未登录是静态「请先登录」加去登录,不是转圈。
|
||||
- **等待:** 揭幕后不得再出现 spinner / 骨架 / 「正在加载」。首屏未到时 `SecondaryPageShell` 写「这一天的星历还没拿到。」,居中在已撑满的内容区里。未登录是静态「请先登录」加去登录,不是转圈。同一会话再次进入直接用模块缓存。
|
||||
- **文案:** 不得写运势结论,不得把三套坐标系换算或叠加。不另印「这是天象本身」这类边界说明。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user