import { useState, useSyncExternalStore, type ReactElement, type ReactNode } from "react"; import { ContextInfoButton } from "../ui/ContextInfoButton"; import { AppHeader } from "./AppHeader"; import { AppSidebar } from "./AppSidebar"; import { getMainViewLabel, getResponsiveShellMode, type MainView, type ResponsiveShellMode } from "./shell-model"; import "./shell.css"; function subscribeToViewport(callback: () => void): () => void { if (typeof window === "undefined") { return () => undefined; } window.addEventListener("resize", callback); return () => window.removeEventListener("resize", callback); } function getViewportShellMode(): ResponsiveShellMode { return typeof window === "undefined" ? "full" : getResponsiveShellMode(window.innerWidth); } function getServerShellMode(): ResponsiveShellMode { return "full"; } export interface AppShellProps { activeView: MainView; onViewChange: (view: MainView) => void; sidebar: ReactNode; sidebarStatus: ReactNode; headerActions: ReactNode; toolbar: ReactNode; children: ReactNode; footer: ReactNode; contextInfo: ReactNode; sidebarCollapsed: boolean; onSidebarCollapsedChange: (collapsed: boolean) => void; } export function AppShell({ activeView, onViewChange, sidebar, sidebarStatus, headerActions, toolbar, children, footer, contextInfo, sidebarCollapsed, onSidebarCollapsedChange }: AppShellProps): ReactElement { const [infoOpen, setInfoOpen] = useState(false); const [responsiveSidebarExpanded, setResponsiveSidebarExpanded] = useState(false); const responsiveMode = useSyncExternalStore( subscribeToViewport, getViewportShellMode, getServerShellMode ); const hasSidebar = Boolean(sidebar || sidebarStatus); const responsiveSidebarCollapsed = responsiveMode !== "full" && !responsiveSidebarExpanded; const effectiveSidebarCollapsed = sidebarCollapsed || responsiveSidebarCollapsed; const setSidebarCollapsed = (collapsed: boolean): void => { if (responsiveMode !== "full") { setResponsiveSidebarExpanded(!collapsed); } onSidebarCollapsedChange(collapsed); }; return (