import { lazy, Suspense, useEffect, useState, type ReactNode } from "react"; import { useLocation, useNavigate } from "react-router"; import { ModelSetupGuide } from "@/components/layout/model-setup-guide"; import { WorkspaceSidebarNav } from "@/components/layout/workspace-sidebar-nav"; import { readWorkspaceSidebarCollapsed, writeWorkspaceSidebarCollapsed } from "@/components/layout/workspace-sidebar-state"; import { WorkspaceTopBar } from "@/components/layout/workspace-top-bar"; import { WorkspaceTopBarExtensionProvider } from "@/components/layout/workspace-top-bar-extension"; import { cn } from "@/lib/utils"; import { isSpatialWorkbenchPath } from "@/lib/workspace-routes"; const WorkspaceCommandPalette = lazy(() => import("@/components/layout/workspace-command-palette").then((module) => ({ default: module.WorkspaceCommandPalette }))); export function AppWorkspaceShell({ children }: { children: ReactNode }) { const { pathname } = useLocation(); const navigate = useNavigate(); const [mobileSidebarExpanded, setMobileSidebarExpanded] = useState(false); const [desktopSidebarCollapsed, setDesktopSidebarCollapsed] = useState(readWorkspaceSidebarCollapsed); const [paletteOpen, setPaletteOpen] = useState(false); const hideChrome = pathname.startsWith("/admin") || /^\/canvas\/[^/]+/.test(pathname); const showGlobalTopBar = !hideChrome; const spatialWorkbench = isSpatialWorkbenchPath(pathname); const creationWorkspace = pathname === "/"; const isMobileViewport = () => window.innerWidth < 1024; const toggleSidebar = () => { if (isMobileViewport()) { setMobileSidebarExpanded((current) => !current); return; } setDesktopSidebarCollapsed((current) => { const next = !current; writeWorkspaceSidebarCollapsed(next); return next; }); }; const expandDesktopSidebar = () => { setDesktopSidebarCollapsed(false); writeWorkspaceSidebarCollapsed(false); }; const handleNavClick = () => { if (isMobileViewport()) setMobileSidebarExpanded(false); }; // ⌘K / Ctrl+K 全局呼出搜索面板。 useEffect(() => { const handler = (event: KeyboardEvent) => { if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") { event.preventDefault(); setPaletteOpen((open) => !open); } }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, []); useEffect(() => { const handleWorkspaceNavigation = (rawEvent: Event) => { const event = rawEvent as CustomEvent<{ to?: string }>; if (!event.detail?.to) return; event.preventDefault(); navigate(event.detail.to); }; window.addEventListener("workspace:navigate", handleWorkspaceNavigation); return () => window.removeEventListener("workspace:navigate", handleWorkspaceNavigation); }, [navigate]); return ( <>
{!hideChrome && mobileSidebarExpanded ?