From 8556eed36c808ea1fc4e6d58f05f64404e224606 Mon Sep 17 00:00:00 2001 From: AstroHan Date: Sun, 6 Sep 2026 13:44:45 +0800 Subject: [PATCH] fix(desktop): hug the right edge and ease the workbar column open and shut The right workbar's collapse toggle sat 24px in from the plate's edge on macOS, where the platform draws nothing on the right: the titlebar strip and the workbar's own bar each spelled out `--space-6 + overlay-right-width`. Fold that into one `--maka-titlebar-gutter-right` token with the bar's own `--space-2` inset, so the toggle keeps the same x in both bands and only Windows caption buttons push it inward. The column also snapped between `display: none` and its width, unlike the sidebar. On a wide window the frame and the overlay panel that share its grid area now animate width and margin, with `visibility` gated by the same duration. Their children hold the open width and hang off the right edge (`justify-content: end` on the lone grid track; an auto margin would resolve to 0 against negative free space), so the face and the toggle keep their resting x and the box's left edge sweeps over them, the way the sidebar reveals its own. Below 991px the column stacks under the conversation at full width, so there collapsing still removes the row, as it does for the bottom placement at every width. A modal obscuring the shell sets `hidden` on the frame instead of collapsing it, so a dialog does not play the ease. The panels stay mounted while hidden; a CDP trace of the 280ms ease costs ~95ms of main thread over 33 frames with no drops at 120Hz. `min-width`/`max-width` on the column go: `workbar-layout.ts` already clamps the value, and a floor would stop the collapse short of 0. Dead rules go with them: the narrow block's `max-width: none`, the panel's `[hidden]` override that `base.css` already covers with `!important`, and the side-chat panel's flex column, which the panel's own grid track now stretches. The shell story that holds the toggle to one x carries the motion contract too, since it is the one story that mounts both bands: it asserts the 8px gutter, then samples frames around collapse and restore for a running width transition, the panel tracking the frame, and the face and toggle never moving. It writes the simulated caption width on the document root, where the gutter token reads it, and passes `motionEnabled` so the shell frame does not pin the fixture attribute that turns transitions off. A narrow-viewport story pins the stacked layout. Generated-by: Claude Code --- .../features/workbar/ui/workbar-surface.tsx | 19 +-- apps/desktop/src/renderer/maka-tokens.css | 7 + .../src/renderer/styles/shell-layout.css | 10 +- .../src/renderer/styles/workbar/artifacts.css | 1 - .../src/renderer/styles/workbar/shell.css | 83 ++++++++--- .../src/renderer/styles/workbar/side-chat.css | 9 +- apps/desktop/stories/app-shell.stories.tsx | 132 +++++++++++++----- .../stories/session-workbar.stories.tsx | 55 +++++++- 8 files changed, 231 insertions(+), 85 deletions(-) diff --git a/apps/desktop/src/renderer/features/workbar/ui/workbar-surface.tsx b/apps/desktop/src/renderer/features/workbar/ui/workbar-surface.tsx index e0077ba8ba..4b35d3c2f6 100644 --- a/apps/desktop/src/renderer/features/workbar/ui/workbar-surface.tsx +++ b/apps/desktop/src/renderer/features/workbar/ui/workbar-surface.tsx @@ -102,6 +102,7 @@ function WorkbarPanelLoading(props: { label: string }) { function WorkbarPanel(props: { id?: string; active: boolean; + collapsed?: boolean; placement: SessionWorkbarPlacement; overlay?: boolean; className?: string; @@ -115,6 +116,7 @@ function WorkbarPanel(props: { hidden={!props.active} data-placement={props.placement} data-overlay={props.overlay || undefined} + data-collapsed={props.collapsed || undefined} className={ props.className ? `maka-session-workbar-panel ${props.className}` @@ -422,9 +424,8 @@ export function WorkbarSurface(props: { const panel = props.panelsState[placement]; const activeTab = panel.tabs.find((tab) => tab.id === panel.activeTabId); const showingLauncher = panel.launcherOpen || !activeTab; - const visible = - !props.hidden && - (placement === 'right' ? !props.rightCollapsed : props.bottomOpen); + const collapsed = + placement === 'right' ? props.rightCollapsed : !props.bottomOpen; return (