[eric] desktop: sidebar toggle pins the sidebar open in fullscreen; card anchors to the viewport so docked chrome squeezes it

This commit is contained in:
ciregenz
2026-07-21 00:03:37 -07:00
parent 9509cd4384
commit cd07b2143f
2 changed files with 24 additions and 14 deletions
@@ -444,7 +444,10 @@ const AppShell: React.FC = () => {
// Zen compact mode: the sidebar is the only chrome now, so whenever it's "away" (user collapsed it,
// OR a fullscreen card hides everything) a left-edge hover floats it back in as an overlay.
const fsActive = !!fullscreenCardId && isDashboardViewActive;
const sidebarAway = (sidebarCollapsed || fsActive) && isDashboardViewActive;
// Arc: the sidebar toggle PINS the sidebar open inside fullscreen (docked, card shrinks beside it);
// unpinned fullscreen keeps the hover-peek overlay.
const [fsSidebarPinned, setFsSidebarPinned] = useState(false);
const sidebarAway = (sidebarCollapsed || (fsActive && !fsSidebarPinned)) && isDashboardViewActive;
const [sidePeek, setSidePeek] = useState(false);
useEffect(() => { if (!sidebarAway) setSidePeek(false); }, [sidebarAway]);
// When the sidebar docks away, the canvas runs flush to the window's left edge, so the floating
@@ -849,7 +852,7 @@ const AppShell: React.FC = () => {
)}
<Box sx={{ display: 'flex', flex: 1, minHeight: 0 }}>
{((!sidebarCollapsed && !fsHideChrome) || sideOverlay) && (
{((!sidebarCollapsed && (!fsHideChrome || fsSidebarPinned)) || sideOverlay) && (
<>
<Box
onMouseEnter={() => { if (sideOverlay) cancelPeekClose(); }}
@@ -900,7 +903,16 @@ const AppShell: React.FC = () => {
<Tooltip title={sideOverlay ? 'Dock sidebar' : 'Hide sidebar'}>
{/* Arc-style pin: from the floating peek this DOCKS the sidebar permanently (pushes the
canvas), from docked it collapses back to peek. Toggle, not one-way collapse. */}
<IconButton size="small" onClick={() => setSidebarCollapsed((v) => !v)}
<IconButton size="small" onClick={() => {
if (fsActive) {
setFsSidebarPinned((v) => {
if (!v) setSidebarCollapsed(false);
return !v;
});
return;
}
setSidebarCollapsed((v) => !v);
}}
data-onboarding="sidebar-toggle" aria-expanded={!sidebarCollapsed}
sx={{ color: c.text.tertiary, p: 0.5, borderRadius: 1, '&:hover': { color: c.text.secondary, bgcolor: `${c.text.tertiary}14` } }}>
<AnimatedPanelLeft size={17} />
@@ -48,19 +48,17 @@ function workspaceSize(): { w: number; h: number } {
}
export function computeTiledStyle(zone: string, panX: number, panY: number, zoom: number): TiledStyle | null {
// 'fullscreen' = the Arc layout: the app chrome hides except the dock rail, which stays put on
// the left, and the card expands into the ENTIRE dashboard beside it, floating on the same gap
// the tile zones use. Target is WINDOW space here, so the viewport origin does NOT cancel.
// 'fullscreen' = the Arc layout: the dock rail stays put on the left and the card expands into
// the ENTIRE dashboard beside it, floating on the same gap the tile zones use. Anchored to the
// VIEWPORT (not the window) so docked chrome, like the pinned sidebar, squeezes the card instead
// of being covered by it.
if (zone === 'fullscreen') {
const el = document.querySelector('[data-canvas-viewport]');
const r = el ? el.getBoundingClientRect() : null;
const ox = r ? r.left : 0;
const oy = r ? r.top : 0;
const { w: vpW, h: vpH } = workspaceSize();
return {
left: (FULLSCREEN_DOCK_RAIL + GAP - ox - panX) / zoom,
top: (GAP - oy - panY) / zoom,
width: window.innerWidth - FULLSCREEN_DOCK_RAIL - GAP * 2,
height: window.innerHeight - GAP * 2,
left: (FULLSCREEN_DOCK_RAIL + GAP - panX) / zoom,
top: (GAP - panY) / zoom,
width: vpW - FULLSCREEN_DOCK_RAIL - GAP * 2,
height: vpH - GAP * 2,
transform: `scale(${1 / zoom})`,
transformOrigin: 'top left',
};