import { Bot, Heart, LayoutDashboard, PackageSearch, PanelLeft, PanelRight, ServerCog, ShieldCheck, UserRoundPen, WandSparkles, Wrench } from "lucide-react"; import { type ComponentType, type ReactNode, useEffect, useState } from "react"; import type { PageId, PageParams, PageRoute } from "../contracts/page"; import type { CurrentUserView } from "../contracts/workspace"; import { MagicalParticleLayer } from "./MagicalParticleLayer"; import { applyBackgroundImage, applyThemeBackgroundPreset, applyThemePalette, loadThemeState, themePaletteChangeEvent, themePalettes, themeTokens, type ThemePaletteChangeDetail, type WorkspaceThemeState } from "../theme/tokens"; import { cx } from "../utils/classes"; interface AppShellProps { routes: PageRoute[]; currentPage: PageId; session: CurrentUserView; onNavigate: (pageId: PageId, params?: PageParams) => void; children: ReactNode; } interface MenuGroup { id: string; label: string; routeIds: PageId[]; icon: ComponentType<{ size?: number; className?: string }>; } const menuGroups: MenuGroup[] = [ { id: "overview", label: "平台概览", routeIds: ["home"], icon: LayoutDashboard }, { id: "servers", label: "服务器管理", routeIds: ["servers"], icon: ServerCog }, { id: "plugins", label: "插件市场", routeIds: ["plugins"], icon: PackageSearch }, { id: "users", label: "用户管理", routeIds: ["users"], icon: ShieldCheck }, { id: "ai", label: "AI 提供商管理", routeIds: ["aiProviders"], icon: Bot }, { id: "tools", label: "系统工具", routeIds: ["maintenance"], icon: Wrench } ]; const roleLabels: Record = { platformAdmin: "平台管理员", serverOwner: "服主", serverAdmin: "服务器管理员" }; export function AppShell({ routes, currentPage, session, onNavigate, children }: AppShellProps) { const [themeState, setThemeState] = useState(() => loadThemeState()); const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); useEffect(() => { function handleThemePaletteChange(event: Event) { const paletteId = (event as CustomEvent).detail?.paletteId; if (!paletteId) { return; } setThemeState((current) => (current.paletteId === paletteId ? current : { ...current, paletteId })); } window.addEventListener(themePaletteChangeEvent, handleThemePaletteChange); const stored = loadThemeState(); applyThemePalette(stored.paletteId); applyThemeBackgroundPreset(stored.backgroundPresetId); applyBackgroundImage(stored.backgroundImage); setThemeState(stored); return () => window.removeEventListener(themePaletteChangeEvent, handleThemePaletteChange); }, []); const activePalette = themePalettes.find((palette) => palette.id === themeState.paletteId) ?? themePalettes[0]; const routesById = new Map(routes.map((route) => [route.id, route])); const visibleGroups = menuGroups .map((group) => ({ ...group, routes: group.routeIds.map((routeId) => routesById.get(routeId)).filter((route): route is PageRoute => Boolean(route)) })) .filter((group) => group.routes.length > 0); function activateGroup(group: (typeof visibleGroups)[number]) { if (group.routes[0].id !== currentPage) { onNavigate(group.routes[0].id); } } return (
{children}
); }