mirror of
https://github.com/remorses/playwriter.git
synced 2026-09-14 16:37:40 +08:00
21cfadce7d
Replace flat TocItem/PreparedTocItem/TocGroup types with a recursive
TocTreeNode -> FlatTocItem pipeline that supports arbitrary page nesting.
**Types:**
- TocNodeType = 'page' | 'h1'-'h6' — heading level encoded in type field,
no separate headingDepth. Smaller objects, self-descriptive.
- TocTreeNode = { label, href, type, children } — recursive tree, the wire format.
- FlatTocItem = { label, href, type, visualLevel, prefix, parentHref, pageHref }
— flat rendering item with depth clamped to 0-3.
**Depth clamping:**
flattenTocTree() walks the recursive tree and clamps visual depth to max 4
levels (0-3). When pages nest deeply, headings flatten to siblings at level 3.
Formula: visualLevel = min(pageDepth + headingDepth, 3). Preserves correct
visual gap for skipped markdown levels (## -> ####) via the h-type encoding.
**Component changes:**
- TableOfContents accepts FlatTocItem[], renders with visibility filtering
instead of two-tier TocGroup. Expand/collapse works at any depth by
tracking expanded hrefs and computing visibility from parentHref chain.
- Search expand override merged into visibility computation so matched items
inside collapsed branches become visible during search.
- search.ts operates directly on FlatTocItem[] — removed SearchEntry and
buildSearchEntries(). Walks parentHref chain for ancestor expansion.
**Extraction:**
slugify, extractText, generateTocTree moved to toc-tree.ts (side-effect-free)
so they can be tested without importing the page module.
**Tests:**
21 vitest tests covering slugify, extractText, tree building (nested, skipped
levels, pop-back), flattening (prefixes, depth clamping, page wrapping,
parentHref/pageHref tracking), and full mdast -> tree -> flat pipeline.
**Remaining for multi-page:**
- Multi-page data source (multiple MDX files / manifest)
- Route-aware active tracking (pathname for page, IntersectionObserver for
headings on current page only)
- Cross-page navigation (SPA or full page load)