Repository navigation
feat(console): on a narrow window the sidebar is the icon rail, and a click expands it over the content - #27893
Conversation
…d expand it over the content Below the width the record split needs beside an expanded sidebar (1160 + 256 = 1416 px), the console sidebar mounts as the icon rail. A click on the rail's background, the app bar trigger or Cmd/Ctrl+B expands it over the content; a navigation choice, a press outside it or Esc folds it again. "Keep sidebar open" turns the fold off per browser. The fold stashes the wide-window open state the primitive's cookie would otherwise lose, and hands it back when the window widens. @object-ui/components gains useIsViewportBelow(breakpoint). Claude-Session: https://claude.ai/code/session_01Utp6CaPpqK4cmqg5XJnjsj Co-authored-by: Claude <noreply@anthropic.com>
…old width Claude-Session: https://claude.ai/code/session_01Utp6CaPpqK4cmqg5XJnjsj Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CaPpqK4cmqg5XJnjsj Co-authored-by: Claude <noreply@anthropic.com>
… reads the sidebar's leading class Claude-Session: https://claude.ai/code/session_01Utp6CaPpqK4cmqg5XJnjsj Co-authored-by: Claude <noreply@anthropic.com>
…-oakpit Claude-Session: https://claude.ai/code/session_01Utp6CaPpqK4cmqg5XJnjsj Co-authored-by: Claude <noreply@anthropic.com>
The overlay test's route probe assigned the module-level navigate during render, which react-hooks/globals reports as an error and fails the app-shell lint. The probe now hands it over from an effect. Claude-Session: https://claude.ai/code/session_01Utp6CaPpqK4cmqg5XJnjsj Co-authored-by: Claude <noreply@anthropic.com>
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh |
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh Contract reviewServed-tier: Face: declaration only. The PR body, the changeset and claim 6512986675 each say ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh 史诗席位预览核对请求 · epic:#26676#1To the epic seat ( State on head What to look at
Deviations to confirm or reject
Evidence (never-merged branch
|
|
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh 席位核对ACCEPT · head
Generated by Claude Code |
|
domain:ui#4 · os-bill · session_01Utp6CaPpqK4cmqg5XJnjsj Preview review (proxy for epic:#26676#1) · 1831836 · REWORK Post-merge proxy preview review under ruling B (6520722066 on #26676), answering the "What to look at" list of 6514234395. Surface: Overall: REWORK on points 1, 2 and 5; points 3 and 4 PASS. Under the ruling's remedy these go to new cards under #26676, not a revert. 1. 1280 px window: icon rail, content = window − 48 · REWORK
2. Expand over content, fold, rail icons, hover · REWORK
3. Keep sidebar open · PASSThe expanded overlay's foot shows "Keep sidebar open" (239×36). Pressed, the sidebar docks at 256 px with 4. 1440 px unchanged; phone drawer unchanged · PASS1440: docked 256 px, 5. The wide-window state is kept · REWORK
The boardsNo v4 board shows the narrow-window sidebar (no 48 px rail, overlay or keep-open item). The seven desktop boards (RecordPageV4*, RecordDrawerV4*) draw a fixed expanded sidebar 200 px wide with ☰ in the top bar; SidebarReports shows four 220 px sidebar mock-ups about "All reports"; RecordMobile shows phones with ☰ and no sidebar. The live expanded sidebar is 256 px against the boards' 200 / 220; not graded. Example board shot Other observations (not verdicts)
Evidence (never-merged branch Generated by Claude Code |
Requested by Bill · project thread
维护者速读
components/src/ui/**没碰。≥1416 px 与手机抽屉行为不变。回滚即还原本 PR。ui/packages/app-shell/src/layout/consoleSidebarRail.ts(阈值推导、浮出、收回);ui/packages/app-shell/src/hooks/useResponsiveSidebar.ts(折叠与宽窗状态暂存);UnifiedSidebar.tsx的外框与底部开关。pnpm --dir ui exec vitest run packages/app-shell/src/layout/__tests__/UnifiedSidebar.railOverlay-27593.test.tsx packages/app-shell/src/hooks/__tests__/useResponsiveSidebar.test.tsx,预期全绿;或在 1280 px 窗口打开任一应用,侧栏是图标轨,点轨道空白处浮出。Fixes #27593
Clause-②: yes (widening)
Metadata-protocol: none
What changes
app-shelluseResponsiveSidebar, extended in place). While the window is narrower thanCONSOLE_SIDEBAR_RAIL_BELOW_WIDTHand wider than the phone breakpoint, the console sidebar is folded to its icon rail; when the window widens past it, the sidebar unfolds. It replaces the old one-time 768–1023 px collapse. A layout effect, so a window that opens narrow paints the rail first.app-shell/src/layout/consoleSidebarRail.ts):RECORD_SPLIT_MIN_CONTENT_WIDTH(the split's list 440 + pane 720 = 1160) +CONSOLE_EXPANDED_SIDEBAR_WIDTH(256, the primitive's--sidebar-width; a test reads the primitive's value and holds the two equal) = 1416. A 1280 px window folds (1232 px left for the split); a 1440 px window keeps the expanded sidebar (1184 px left).UnifiedSidebar,railOverlayprop set byConsoleLayout). A click on the rail's background, the app bar's trigger, or ⌘B / Ctrl+B expands the folded sidebar as an overlay: the fixed panel takes its expanded width above the page (z-40, a shadow), while adisplay: contentsframe around the sidebar holds the primitive's in-flow gap at the rail width, so the content does not move. A navigation (an entry chosen in it, the command palette, Back), a press outside it, or an Esc no other layer handled folds it again. A press inside the sidebar's React tree, its entries' portaled menus included, does not; a press on the app bar's trigger is left to the trigger. Hover does nothing; a click on a rail icon opens the entry as before.aria-pressed, stored per browser as the workspace preferenceconsole.sidebar.keepOpen(os:pref:store). On, a narrow window keeps the wide-window sidebar (expanded beside the content, ⌘B collapses it as on a wide window) and the toggle stays in the footer to turn it off.sidebar_statecookie on every open and close, the fold's included, so the fold now stashes the wide-window state (os:console-sidebar:wide-open) when it takes over and hands it back when the window widens, or on the next load that opens wide.@object-ui/components: new exportuseIsViewportBelow(breakpoint)besideuseIsMobile, read synchronously on the first render and live throughmatchMedia.@object-ui/i18n:sidebar.keepOpenin all ten packs.components/src/ui/**,packages/spec/**, or any metadata key.Tests
layout/__tests__/UnifiedSidebar.railOverlay-27593.test.tsx(11): 1280 mounts the rail; a background click expands the overlay, the panel carries the overlay classes and the frame's variant reaches the primitive's gap (not the panel); hover does not expand and a rail icon navigates; a nav choice, a route change from elsewhere, an outside press, Esc fold it; an Esc another layer handled does not; a press in an entry's portaled menu does not; the trigger toggles once; keep-open ends the fold, survives a remount, and turning it off folds again; 1440 unchanged; 700 mounts the phone drawer.hooks/__tests__/useResponsiveSidebar.test.tsxrewritten (7): 1280 folds / 1440 open; a manual expand on a narrow window holds; widening hands back an open and a collapsed wide state; a wide load after a narrow one gets the wide state; keep-open; the phone breakpoint is left alone.layout/__tests__/consoleSidebarRail.width-27593.test.tsx(3): the expanded width equals the primitive's--sidebar-width; the derivation; 1280 / 1440 on either side.components/src/hooks/__tests__/use-viewport-below.test.tsx(3): first-render answer with no wrong frame, the breakpoint edge, live across resizes.KeyboardShortcutsDialog.wiredOnly-11674mounts a 1440 px window (its ⌘B probe starts from the expanded sidebar);consoleTopBar.height-12639readsCONSOLE_BELOW_TOP_BARas the sidebar's leading class (the overlay adds its own after it).Acceptance notes
mainddab8b99). The "resizable rail (200–480 px, remembered in localStorage)" the card's Source describes does not exist: the only remembered sidebar state is the primitive'ssidebar_stateopen/closed cookie. The sidebar was alreadycollapsible="icon"with rail tooltips (the entries' own labels), anduseResponsiveSidebaralready collapsed it once between 768 and 1023 px, writing that into the cookie. There was no pin toggle in the expanded sidebar (the shell's one trigger is in the app bar), so "Keep sidebar open" is new, with one new i18n key.components/src/ui/**(uiAGENTS.mdRemove explicit pnpm version from workflows to fix version conflict #7): the overlay is built from the outside, through the primitive'sclassName/ props on the panel and adisplay: contentsframe whose arbitrary variant narrows the gap (the first child of the primitive'sdata-collapsibleelement). The overlay test pins that the variant reaches the gap, so a primitive sync that moves it turns the test red.Sidebarelement, which the clickable non-control census (clickableNonControlCensus-13461) does not judge.recordPageColumns.ts(plugin-detail) derives its 1120 / 760 container floors from example windows with the sidebar expanded. The tiers are container-measured, so they follow the fold on their own: at 1280 the content area is 1232 px instead of 1024, so a full record page there can now reach the wider tier. The docblock's window examples still describe an expanded sidebar; not edited here (outside this card's surface).examples/app-crm, Contacts); the shell is app-independent.content/docs/describes the console shell's sidebar, and the components README lists no hooks; nothing to update.Verification
All readings on head
bc7935f4(the branch merged withorigin/mainatc4cb5ec0; of the files this diff edits, the merge touched only the ten locale packs, and merged them cleanly), unless a line says otherwise.Browser measurement (Chromium, the CRM example's Contacts list)
Branch code at
fdb717ea(pre-merge; the merge brought nothing under the edited surface), backendobjectstack dev --seed-admin --freshonexamples/app-crm, console on its Vite dev server. Screenshots, readings and the script are on the never-merged evidence branchclaude/issue-27593-evidence@b86187c2, folderevidence/27593/.data-console-rail=railoverlayoverlaydata-mobile), no desktop sidebarThe overlay leaves the content box exactly where it was (48 / 1232 in every 1280 state); the "Keep sidebar open" footer is present only while expanded.
Tests and type-check
use-viewport-below,useResponsiveSidebar,consoleSidebarRail.width-27593,UnifiedSidebar.railOverlay-27593): Test Files 4 passed (4), Tests 24 passed (24); os-verify-lock VERDICT command-exit 0.UnifiedSidebar,ConsoleLayout,useResponsiveSidebar,LocalizedSidebarTriggeror thesidebar_statecookie (135 files) pluspackages/i18n/, on48346663: Test Files 2 failed | 223 passed (225), Tests 2 failed | 2443 passed | 13 skipped. The two were the pins this PR updates (KeyboardShortcutsDialog.wiredOnly-11674: its ⌘B probe mounted at happy-dom's default 1024 px and expected an expanded sidebar;consoleTopBar.height-12639: its source regex readclassName={CONSOLE_BELOW_TOP_BAR}verbatim); after the update both files pass (17/17).bc7935f4, after rebuilding@object-ui/i18nand@object-ui/components:type-checkof@object-ui/componentsand@object-ui/app-shell(tsc --noEmit and tsconfig.test.json) exit 0, and the four new files, the two updated pins,LocalizedSidebarTrigger.appBar-12429andpackages/i18n/: Test Files 98 passed (98), Tests 1428 passed | 13 skipped; VERDICT command-exit 0.scripts/ablation-replace.mjs(anchor 1 -> 0, blob changed, restored,git diff HEADempty after); app-shell tests importsrc, so no dist rebuild:pnpm --dir ui run check:i18n-drift(1 key added, 0 en values changed),check:i18n-keys,check:i18n-dead-keys: exit 0.pnpm --dir ui run check:new-line-citations: 0 new, exit 0.components,app-shellandi18n-consuming suites.Gates
dispatch-gates --commandsonbc7935f4derived 35 families; all 35 ran, eachexit 0(check-sdui-manifestand its--self-test, andpnpm --dir ui exec vitest run scripts/, among them).--ranreconciliation: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN.🤖 Generated with Claude Code
https://claude.ai/code/session_01Utp6CaPpqK4cmqg5XJnjsj
Generated by Claude Code