From 2ab6ed968757314aa61daf29157b1c1e4cbf2bc2 Mon Sep 17 00:00:00 2001 From: hypercross Date: Thu, 26 Feb 2026 15:22:40 +0800 Subject: [PATCH] feat: reactive sidebar --- src/App.tsx | 12 ++- src/components/Sidebar.tsx | 162 ++++++++++++++++++++++++------------- src/components/index.ts | 2 +- 3 files changed, 117 insertions(+), 59 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 5bb4193..770d619 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,7 +3,7 @@ import { useLocation } from "@solidjs/router"; // 导入组件以注册自定义元素 import "./components"; -import { Article, Sidebar } from "./components"; +import { Article, MobileSidebar, DesktopSidebar } from "./components"; const App: Component = () => { const location = useLocation(); @@ -22,15 +22,19 @@ const App: Component = () => { return (
- + {/* 移动端抽屉式侧边栏 */} + setIsSidebarOpen(false)} />
+ {/* 仅在移动端显示菜单按钮 */}
-
+
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 80d8f0c..829f2c7 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -6,12 +6,80 @@ import { FileTreeNode, HeadingNode } from "./FileTree"; interface SidebarProps { isOpen: boolean; onClose: () => void; + isDesktop?: boolean; } /** - * 侧边栏组件 + * 侧边栏内容组件 */ -export const Sidebar: Component = (props) => { +const SidebarContent: Component<{ + fileTree: FileNode[]; + pathHeadings: Record; + currentPath: string; + onClose: () => void; +}> = (props) => { + const location = useLocation(); + + // 响应式获取当前文件的标题列表 + const currentFileHeadings = createMemo(() => { + const pathname = location.pathname; + return props.pathHeadings[pathname] || props.pathHeadings[`${pathname}.md`] || []; + }); + + return ( +
+
+

目录

+ + + +
+ + {/* 文件树 */} +
+

+ 文件 +

+ {props.fileTree.map((node) => ( + + ))} +
+ + {/* 当前文件标题 */} + 0}> +
+

+ 本页 +

+ {currentFileHeadings().map((node) => ( + + ))} +
+
+
+ ); +}; + +/** + * 侧边栏组件(移动端抽屉) + */ +export const MobileSidebar: Component = (props) => { const location = useLocation(); const [fileTree, setFileTree] = createSignal([]); const [pathHeadings, setPathHeadings] = createSignal< @@ -25,72 +93,58 @@ export const Sidebar: Component = (props) => { setPathHeadings(toc.pathHeadings); }); - // 响应式获取当前文件的标题列表 - const currentFileHeadings = createMemo(() => { - const pathname = location.pathname; - return pathHeadings()[pathname] || pathHeadings()[`${pathname}.md`] || []; - }); - return ( <> {/* 遮罩层 */}
{/* 侧边栏 */} ); }; + +/** + * 桌面端固定侧边栏 + */ +export const DesktopSidebar: Component = () => { + const location = useLocation(); + const [fileTree, setFileTree] = createSignal([]); + const [pathHeadings, setPathHeadings] = createSignal< + Record + >({}); + + // 加载目录数据 + onMount(async () => { + const toc = await generateToc(); + setFileTree(toc.fileTree); + setPathHeadings(toc.pathHeadings); + }); + + return ( + + ); +}; diff --git a/src/components/index.ts b/src/components/index.ts index 4280ff2..e479273 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -6,7 +6,7 @@ import './md-link'; // 导出组件 export { Article } from './Article'; export type { ArticleProps } from './Article'; -export { Sidebar } from './Sidebar'; +export { MobileSidebar, DesktopSidebar } from './Sidebar'; export type { SidebarProps } from './Sidebar'; export { FileTreeNode, HeadingNode } from './FileTree';