@@ -363,38 +427,31 @@ export const PanelSlot = ({ panel, registry, components, interactive, locked, no
>
);
- if (isMaximized) {
- return (
- <>
- {/* Placeholder to preserve layout space */}
-
- {/* Maximized overlay — portalled to escape stacking contexts */}
- {createPortal(
-
,
- document.body,
- )}
- >
- );
- }
-
- const panelStyle = noHeader
- ? { backgroundColor: 'rgba(255, 255, 255, 0.12)', borderColor: 'rgba(0, 0, 0, 0.25)', ...(transitioningPanelId === panel.id ? { viewTransitionName: `panel-${panel.id}` } : {}) }
- : { backgroundColor: 'rgba(255, 255, 255, 0.12)', borderColor: 'rgba(255, 255, 255, 0.2)', ...(transitioningPanelId === panel.id ? { viewTransitionName: `panel-${panel.id}` } : {}) };
+ // Maximize is a CSS state toggle on THE SAME element — no portal, no remount — so the panel's content
+ // (scroll position, media playback, in-flight state) is preserved exactly across maximize/restore.
+ // It fills the content REGION (starting below the global Header), not the whole viewport: the panel is
+ // confined to the layout's `absolute z-2` content stacking context, which sits under the fixed nav
+ // Header (z-10) — so a full-viewport overlay would hide the panel's own header/Restore behind the nav.
+ // Clearing the header keeps it visible + the nav accessible. (Maximize only happens in the dashboard
+ // shell; previews/mobile no-op it, so the header offset is always the right reference.)
+ const maximizedStyle = { backgroundColor: 'rgba(30, 30, 30, 0.95)', borderColor: 'rgba(255, 255, 255, 0.2)' };
+ const normalStyle = noHeader
+ ? { backgroundColor: 'rgba(255, 255, 255, 0.12)', borderColor: 'rgba(0, 0, 0, 0.25)' }
+ : { backgroundColor: 'rgba(255, 255, 255, 0.12)', borderColor: 'rgba(255, 255, 255, 0.2)' };
+ const panelStyle = {
+ ...(isMaximized ? maximizedStyle : normalStyle),
+ ...(transitioningPanelId === panel.id ? { viewTransitionName: `panel-${panel.id}` } : {}),
+ } as React.CSSProperties;
return (