Atlas dock: pin-by-default, drag-resize to 50vw, cookie persist
The Atlas Agent Dock used to open as a fixed overlay floating on top of the workspace at a hardcoded 440px. This change makes it pinned by default (part of the layout, content reflows), adds a left-edge drag-to-resize handle, a pin/unpin toggle, and persists the choice per user in a cookie.
What changed
Pinned + open: the aside drops its shadow/overlay and
app-chrome.tsx reserves paddingRight = width
on its root flex container, so the rail + page reflow beside the
panel and never overlap. Unpinned restores today's
fixed z-40 drawer-shadow overlay, content full-width
beneath.
The left-edge handle (ported from
add-matter/step5-review/atlas-drawer.tsx) uses pointer
capture and clampDockWidth. Floor 340px (matches the
ACP min-w-[340px]); ceiling 50% of the viewport — width
can never exceed half the screen, and a window resize re-clamps a
previously-saved width down.
A lucide Pin/PinOff button sits in the ACP
header beside the Session menu and close. Labels
Agents.pinPanel / Agents.unpinPanel /
Agents.resizePanel ship in both
en.json and hi.json.
pinned + width persist in the
atlas-dock-prefs cookie (sameSite=lax,
path=/, ~180d, NOT httpOnly). The
(workspace) layout reads it server-side and hydrates
the store. Open/close stays ephemeral.
Where it lives
src/lib/agents/dock-prefs.ts— cookie name, defaults,clampDockWidth(50vw ceiling), parse/read/write helpers.src/stores/agent-dock-store.ts— addspinned/width(+ setters,persistPrefs,hydratePrefs); seeds from the cookie on client init; open/close stays ephemeral.src/components/agents/agent-dock.tsx— pinned (in-flow, no shadow) vs unpinned (fixed z-40shadow); mounts the left-edge resize handle.src/components/agents/agent-chat-panel.tsx— the pin/unpin header toggle.src/components/agents/agent-dock-mount.tsx— wires store prefs into the dock; the window-resize 50vw re-clamp; hydrates from the server-read cookie.src/components/app-chrome.tsx— reserves right-side space only whenpinned && open.src/app/[locale]/(workspace)/layout.tsx— server-reads the cookie and threads initial prefs down.
Verify
pnpm lint pnpm typecheck pnpm test pnpm build
- Default fresh session (no cookie) opens pinned — content reflows beside the panel.
- Toggle unpin → floating overlay; content full-width underneath.
- Resize drag the left edge — clamps at 340px and 50vw; narrowing the window re-clamps.
- Persist reload preserves pin + width; open/close does not survive (ephemeral).
Stories: Agents/AgentDock (Pinned / Unpinned / Closed,
live resize) and Agents/AgentChatPanel
(WithPinToggle). Unit coverage in
dock-prefs.test.ts (clamp/parse/cookie round-trip) and
agent-dock-store.test.ts (pin default, persist, hydrate).
Files changed
13 file(s), +539 / -42 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +3 | -0 |
| messages/hi.json | Config | +3 | -0 |
| src/app/[locale]/(workspace)/layout.tsx | App route | +24 | -9 |
| src/components/agents/agent-chat-panel.stories.tsx | Component | +29 | -0 |
| src/components/agents/agent-chat-panel.tsx | Component | +30 | -1 |
| src/components/agents/agent-dock-mount.tsx | Component | +53 | -0 |
| src/components/agents/agent-dock.stories.tsx | Component | +36 | -4 |
| src/components/agents/agent-dock.tsx | Component | +84 | -10 |
| src/components/app-chrome.tsx | Component | +12 | -0 |
| src/lib/agents/dock-prefs.test.ts | Library | +83 | -0 |
| src/lib/agents/dock-prefs.ts | Library | +93 | -0 |
| src/stores/agent-dock-store.test.ts | Test | +34 | -1 |
| src/stores/agent-dock-store.ts | Source | +55 | -17 |