From ab22fbc23d446ea4da6fae592868b9aa99d4cf7b Mon Sep 17 00:00:00 2001 From: John Jeong Date: Wed, 5 Nov 2025 15:28:34 +0900 Subject: [PATCH 1/3] toc polish --- apps/web/src/routes/_view/blog/$slug.tsx | 106 ++++++++++++++++++----- 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/apps/web/src/routes/_view/blog/$slug.tsx b/apps/web/src/routes/_view/blog/$slug.tsx index e70bb5e007..b17d3391d5 100644 --- a/apps/web/src/routes/_view/blog/$slug.tsx +++ b/apps/web/src/routes/_view/blog/$slug.tsx @@ -72,7 +72,7 @@ function Component() {
-
+
@@ -114,41 +114,103 @@ function MobileHeader() { ); } +interface TocItem { + id: string; + text: string; + level: number; + children: TocItem[]; +} + +function buildTocTree(toc: Array<{ id: string; text: string; level: number }>): TocItem[] { + const tree: TocItem[] = []; + const stack: TocItem[] = []; + + for (const item of toc) { + const node: TocItem = { ...item, children: [] }; + + while (stack.length > 0 && stack[stack.length - 1].level >= node.level) { + stack.pop(); + } + + if (stack.length === 0) { + tree.push(node); + } else { + stack[stack.length - 1].children.push(node); + } + + stack.push(node); + } + + return tree; +} + +function TocNode({ item, depth = 0 }: { item: TocItem; depth?: number }) { + const [isExpanded, setIsExpanded] = useState(true); + const hasChildren = item.children.length > 0; + + return ( +
+
+ {hasChildren && ( + + )} + 0 ? `${depth * 0.5}rem` : 0 }} + > + {item.text} + +
+ {hasChildren && isExpanded && ( +
+ {item.children.map((child) => )} +
+ )} +
+ ); +} + function TableOfContents({ toc, }: { toc: Array<{ id: string; text: string; level: number }>; }) { + const tocTree = buildTocTree(toc); + return (