Lane 1: the shell around every page, and the vocabulary rename (#727) #742
Loading…
Reference in a new issue
No description provided.
Delete branch "build/lane1-shell"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Lane 1's shell PR: the build plan's rollout rule made real (§2).
AppLayoutis now the lane 0 shell, and every signed-in page renders inside it: the app bar with where you are, the search box inside a campaign, the bell and the account menu; the live bar when a session is in progress; the Book with the Contents rail and the page; the footer; and on a phone the Contents sheet with the account menu in it.NavBar.jsxis gone. Route paths do not change. Main stays deployable: the old pages are unchanged inside the frame.What the frame knows and where it gets it. The campaign list once per app load; the Needs you count from
/api/me/attention; the version fromGET /api/meta; the bell from/api/me/notifications(polled for the unread count every 60 s while the tab is visible, the list fetched when the panel opens, mark-read optimistic); search fromGET /api/campaigns/{id}/search(debounced, aborted, nothing under two letters, the transcripts switch for a GM); the live bar fromGET /api/campaigns/{id}/liveevery 30 s while visible. Every one of these is optional: a 404 or a failure means that piece is not drawn, because three of the endpoints arrive with the server PR (#727's first) and a frame is on every screen. The one exception is the notifications panel, which says it did not load once somebody has opened it.The Contents lists only the pages that exist today (no door that leads nowhere): Home, Needs you and the campaigns on Home; Sessions, Highlights, Analytics, the wiki's front page, and for a GM Prep and Suggested wiki updates inside a campaign. The entries that arrive with later lanes (This week, Discussions, Storyline, Members & characters, Table rules & safety, Settings, the wiki's groups) are named in a comment against their lane.
Decisions a reviewer should know.
.qb(the base type rules) goes on each chrome piece and never around the<Outlet/>, so the pages not yet rebuilt keep their look.AppShellno longer hardcodes it;/designputs it on its own root and was render-checked in both themes.<a href>s and stay free of react-router, which is what lets/designrender them. So the frame routes their clicks itself: one listener on the shell (useChromeLinks) hands an in-app chrome link tonavigate(), and leaves alone anything inside the page's<main>, modified and middle clicks,target,download,rel="external", other origins and/auth/logout.main.jsximportsindex.cssbeforeApp.jsx, deliberately: the bundler emits CSS in module-evaluation order, and withApp.jsxfirstbase.csslanded after the component stylesheets and.qbrepainted the app bar. Verified in the built CSS.height: 100dvhon its own root) because the phone sheet is positioned inside it. An old page that saysmin-h-screencan therefore scroll by about a bar's height inside the frame; its colour, type and spacing are unchanged, and each such page is replaced by its own lane.useTheme: light, dark, auto that follows the OS live);toggleis kept for anything still calling it.Bellnow renders a row without anhref(the contract's "No longer available" rows) as text, not a dead link.The vocabulary rename (§5) lands in
vocabulary.jswith the redesign's names as constants, and on the old pages' visible text only: Session Prep → The plan, Beat Planner → Beats, Session Shelf / the board → The shelf, Campaign Journal → Session notes, journal entries → recaps, campaign story → the story / Storyline, lore → the wiki, Back to Dashboard and its variants → Home, and the two help guides. No route path, field name,tool_idor API string changed. The full table is in the commit.Coverage rows (
lane1.py): SH-1 CA-002, SH-017, IS-158, IS-198, IS-298, IS-304, IS-307 (CA-001, SH-023, SH-029, IS-303 replaced); SH-2 SH-019 (SH-018 replaced); SH-3 SH-020, SH-021, IS-157 (the entries that exist), IS-310 pending its pages; SH-4 SH-024, SH-025, SH-027, SH-037, IS-190, IS-197 (SH-026 replaced by the three-mode strip); SH-5 IS-159, IS-160, IS-162, IS-158, IS-198; SH-6 IS-304 to IS-309; SH-9 IS-298 to IS-302. SH-8 stays on the campaign pages that own it until lane 3.Tests: 1,156 (30 new for the frame, mounting the real route table with the API mocked; 7 for the theme modes). Lint clean, build green.
🤖 Generated with Claude Code
Every signed-in route renders inside the redesign's frame now. `App.jsx`'s `AppLayout` (a nav bar above an `<Outlet/>`) is replaced by `src/shell/AppFrame.jsx`, built out of lane 0's library: the app bar with where you are, the campaign search box, the bell and the identity disc; the Contents as a rail and, on a phone, as the sheet that also carries the account menu; the live-session bar; and the footer. `NavBar` is deleted. Route paths are unchanged — this is the build plan's rollout rule (§2), so from here on nobody sees an old page without the new navigation, and no page is missing while its lane is being built. The Contents lists **only the pages that exist**: Sessions, Highlights, Analytics, the wiki's front page, and Prep and Suggested wiki updates for a GM. The rest are named in comments against the lane that builds them (lane 3's This week, Storyline, Members, Settings; lane 7's Discussions; lane 8's wiki groups) rather than drawn as doors that lead nowhere. The old pages are unchanged inside it. The base type rules are scoped to `.qb` so a page keeps its own look until its lane replaces it, and every page now renders inside `AppShell` — so `AppShell` drops the class and the frame puts it on each chrome piece instead, never on the element the Outlet is in. The Outlet's wrapper is a plain div carrying the Tailwind colours the layout div it replaced used to carry. `main.jsx` imports `index.css` first so the design system's base lands before the components that are written to override it; imported after `App.jsx`, as it was, base.css won every tie and `.qb` on the app bar would have repainted it in paper. Everything the frame asks the server for is optional — the campaign list, the attention count, and four endpoints that land in their own PR (`/api/me/notifications`, `/api/campaigns/{id}/live`, `/api/campaigns/{id}/search`, `/api/meta`). A failure draws nothing rather than a banner on every screen; only the notifications panel says it did not load, because by then somebody has asked. Also here: - **Three themes.** `useTheme` is light/dark/**auto**, where auto removes the stored choice and follows `prefers-color-scheme` live. `toggle` still works. - **The vocabulary** (brief §5) in `vocabulary.js`, and applied: Dashboard → Home, Session Shelf → The shelf, Beat Planner → Beats, the `session_prep` tool → The plan, Session Prep (the place) → Prep, Campaign Journal → Session notes, journal entry → Recap, Campaign storyline → Storyline, "campaign lore" → the campaign wiki, "the board" → the shelf. - **Bell** draws a row with no `href` as text rather than a dead anchor, for the `unavailable` rows the contract allows. - `jsx-a11y` runs at error on `src/shell/` as it does on `src/ui/`. Verified in Docker: eslint clean (no warnings in the new files either), 1,156 tests green, `vite build` green, and `/design` render-checked in headless Edge in both themes after the `AppShell` change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>