diff --git a/src/components/Shell.tsx b/src/components/Shell.tsx new file mode 100644 index 0000000..5951931 --- /dev/null +++ b/src/components/Shell.tsx @@ -0,0 +1,84 @@ +import { useState, useEffect, type ComponentType } from 'react'; + +export interface ModuleConfig { + id: string; + label: string; + icon: ComponentType<{ size?: number; className?: string }>; + component: ComponentType; +} + +function getHashModule(modules: ModuleConfig[]): string { + const hash = window.location.hash.slice(1); + return modules.some((m) => m.id === hash) ? hash : modules[0]?.id ?? ''; +} + +export function Shell({ modules }: { modules: ModuleConfig[] }) { + const [activeModule, setActiveModule] = useState(() => getHashModule(modules)); + + useEffect(() => { + const onHashChange = () => setActiveModule(getHashModule(modules)); + window.addEventListener('hashchange', onHashChange); + return () => window.removeEventListener('hashchange', onHashChange); + }, [modules]); + + useEffect(() => { + if (!window.location.hash) { + window.location.hash = modules[0]?.id ?? ''; + } + }, [modules]); + + const switchModule = (id: string) => { + window.location.hash = id; + }; + + const ActiveComponent = modules.find((m) => m.id === activeModule)?.component ?? modules[0]?.component; + + return ( +
+ {/* Web 侧边栏 (md 及以上) */} + + + {/* 内容区 */} +
+ {ActiveComponent && } +
+ + {/* 移动端底部导航 (md 以下) */} + +
+ ); +}