sidebar: squeeze the conversation layout instead of floating over it
The open panel now occupies layout space: #root (the AppFrame grid) gives up the panel width on the right via margin-right driven by a --dsh-sidebar-width CSS variable, and only the center column is flexible, so the squeeze lands exactly on the agent output and the input bar (VSCode sidebar behavior). The fixed panel covers the vacated strip; expand/ collapse animates the margin and the slide on the same theme duration, width drags disable the transition, and prefers-reduced-motion is honored.
This commit is contained in:
@@ -101,6 +101,19 @@ export function Sidebar(props: { ctx: Context }) {
|
||||
const widthDrag = useRef({ startX: 0, startWidth: 0 })
|
||||
const [draggingWidth, setDraggingWidth] = useState(false)
|
||||
|
||||
// Layout push: the app shell gives up the panel's width while it is open
|
||||
// (0 while collapsed), so the conversation and input bar are squeezed
|
||||
// instead of covered. Dragging disables the layout transition.
|
||||
useEffect(() => {
|
||||
const width = snapshot.state?.panelOpen === true ? snapshot.state.width : 0
|
||||
document.documentElement.style.setProperty('--dsh-sidebar-width', `${width}px`)
|
||||
}, [snapshot.state?.panelOpen, snapshot.state?.width])
|
||||
useEffect(() => {
|
||||
if (draggingWidth) document.body.setAttribute('data-dsh-sidebar-dragging', '')
|
||||
else document.body.removeAttribute('data-dsh-sidebar-dragging')
|
||||
}, [draggingWidth])
|
||||
|
||||
|
||||
// Whether the panel currently fills the viewport (fullscreen expansion).
|
||||
const fullscreen = state !== undefined && window.innerWidth - state.width < 8
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Sidebar } from './Sidebar.tsx'
|
||||
import { registerTurnTailInterception } from './intercept.tsx'
|
||||
import { t } from './locales.ts'
|
||||
import css from './sidebar.module.css'
|
||||
import './layout.css'
|
||||
|
||||
/** Services required before mounting (provided by the client runtime). */
|
||||
export const inject = ['slots', 'sessions']
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Layout push: when the sidebar is open it OCCUPIES the layout instead of
|
||||
* floating over it — the app shell (#root, the AppFrame three-column grid)
|
||||
* gives up the panel's width on the right. Only the center column is
|
||||
* flexible (1fr), so the squeeze lands exactly on the conversation output
|
||||
* and the input bar, like a VSCode sidebar. The fixed panel covers the
|
||||
* vacated strip, which looks seamless because #root's background is the
|
||||
* theme base.
|
||||
*
|
||||
* The width rides a CSS variable updated by the Sidebar shell (0 while
|
||||
* collapsed); expand/collapse animates both the margin and the panel slide
|
||||
* on the same theme duration. Width drags disable the transition so the
|
||||
* layout tracks the pointer.
|
||||
*/
|
||||
#root {
|
||||
margin-right: var(--dsh-sidebar-width, 0px);
|
||||
transition: margin-right var(--ds-transition-duration-slow) var(--ds-ease-in-out);
|
||||
}
|
||||
|
||||
body[data-dsh-sidebar-dragging] #root {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#root {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user