// Path: Frontend/src/components/shell/AppShell/AppShell.tsx import { createSignal, onCleanup, onMount, Show, type JSX } from "solid-js"; import { getDocumentTheme, setTheme, type Theme } from "../../../theme/runtime"; import { WorkspaceHome } from "../../workspace-home/WorkspaceHome/WorkspaceHome"; import { AppShellDataProvider, useAppShellData } from "../data/app-shell.context"; import { LeftRail } from "../LeftRail/LeftRail"; import { MobileBottomNav } from "../MobileBottomNav/MobileBottomNav"; import { MobileWorkspaceBrowser } from "../MobileWorkspaceBrowser/MobileWorkspaceBrowser"; import { ServerDock } from "../ServerDock/ServerDock"; import { NotificationsMenu } from "../TopBar/NotificationsMenu"; import { ProfileMenu } from "../TopBar/ProfileMenu"; import { TopBar } from "../TopBar/TopBar"; import { WorkspaceSidebar } from "../WorkspaceSidebar/WorkspaceSidebar"; import styles from "./AppShell.module.scss"; type MobileWorkspaceView = "notifications" | "profile" | null; const MOBILE_VIEWPORT_QUERY = "(max-width: 48rem)"; const AppShellContent = (): JSX.Element => { const [themeState, setThemeState] = createSignal("light"); const [isRailCollapsed, setIsRailCollapsed] = createSignal(false); const [isSidebarCollapsed, setIsSidebarCollapsed] = createSignal(false); const [isMobileViewport, setIsMobileViewport] = createSignal(false); const [isMobileWorkspaceBrowserOpen, setIsMobileWorkspaceBrowserOpen] = createSignal(false); const [activeMobileWorkspaceView, setActiveMobileWorkspaceView] = createSignal(null); const appShellData = useAppShellData(); onMount((): void => { setThemeState(getDocumentTheme()); if (typeof window === "undefined" || typeof window.matchMedia !== "function") { return; } const mediaQuery = window.matchMedia(MOBILE_VIEWPORT_QUERY); const syncMobileViewport = (): void => { setIsMobileViewport(mediaQuery.matches); if (!mediaQuery.matches) { setIsMobileWorkspaceBrowserOpen(false); setActiveMobileWorkspaceView(null); } }; syncMobileViewport(); mediaQuery.addEventListener("change", syncMobileViewport); onCleanup(() => { mediaQuery.removeEventListener("change", syncMobileViewport); }); }); const toggleTheme = (): void => { const next: Theme = themeState() === "dark" ? "light" : "dark"; setTheme(next); setThemeState(next); }; const openMobileWorkspaceView = (view: Exclude): void => { setIsMobileWorkspaceBrowserOpen(false); setActiveMobileWorkspaceView((current) => (current === view ? null : view)); }; const toggleMobileWorkspaceBrowser = (): void => { setActiveMobileWorkspaceView(null); setIsMobileWorkspaceBrowserOpen((open) => !open); }; const toggleMobileNotifications = (): void => { openMobileWorkspaceView("notifications"); }; const toggleMobileProfile = (): void => { openMobileWorkspaceView("profile"); }; const closeMobileWorkspaceView = (): void => { setActiveMobileWorkspaceView(null); }; return (
{/* Left server rail */}
{/* Sidebar + main workspace frame */}
{ setIsRailCollapsed((collapsed) => !collapsed); }} />
{/* On mobile, top-bar menus become full workspace views instead of popovers. */} { setIsSidebarCollapsed((collapsed) => !collapsed); }} /> } >
{/* Floating server dock overlay */}
{ toggleMobileWorkspaceBrowser(); }} /> { setIsMobileWorkspaceBrowserOpen(false); }} />
); }; export const AppShell = (): JSX.Element => { return ( ); };