diff --git a/app/pages/+data.ts b/app/pages/+data.ts index 80b80de..e5f8cb4 100644 --- a/app/pages/+data.ts +++ b/app/pages/+data.ts @@ -1,6 +1,8 @@ +import type { SectionCache } from "@/services/DocCache"; import type { PageContext } from "vike/types"; import { useConfig } from "vike-solid/useConfig"; +import { docCache } from "@/services/DocCache"; import buildTitle from "./buildTitle"; export type Data = Awaited>; @@ -9,7 +11,7 @@ export async function data(pageContext: PageContext) { const config = useConfig(); const { - exports: { tableOfContents, frontmatter }, + exports: { frontmatter }, urlParsed, } = pageContext; const isRoot = urlParsed.pathname === "/"; @@ -19,7 +21,16 @@ export async function data(pageContext: PageContext) { description: frontmatter?.description, }); + let doc: SectionCache | undefined; + + if (urlParsed.pathname === "/") { + doc = docCache.get("index"); + } else { + doc = docCache.get(urlParsed.pathname); + } + return { - tableOfContents, + sections: doc?.sections || [], + frontmatter, }; } diff --git a/app/partials/TableOfContents.tsx b/app/partials/TableOfContents.tsx index 6aa9d04..4dbb196 100644 --- a/app/partials/TableOfContents.tsx +++ b/app/partials/TableOfContents.tsx @@ -1,5 +1,4 @@ -import type { TableOfContents as TableOfContentsType } from "@/remarkHeadingId"; -import type { Section } from "@/libs/sections"; +import type { DocSection } from "@/services/DocCache"; import type { Data } from "@/pages/+data"; import { createSignal, createEffect, For } from "solid-js"; @@ -8,31 +7,36 @@ import { Link } from "@/components/Link"; import clsx from "clsx"; export function TableOfContents() { - const { tableOfContents } = useData(); + const { sections } = useData(); + if (!sections) return null; - if (!tableOfContents) return null; + createEffect(() => { + for (const [key, value] of Object.entries(sections)) { + console.log(`${key}: ${JSON.stringify(value)}`); + } + }); - const [currentSection, setCurrentSection] = createSignal( - tableOfContents[0]?.id, - ); + const [currentSection, setCurrentSection] = createSignal(sections[0]?.hash); const getHeadings = () => { - return tableOfContents + return sections .map((section) => { - const el = document.getElementById(section.id); + if (!section.hash) return null; + + const el = document.getElementById(section.hash); if (!el) return null; const style = window.getComputedStyle(el); const scrollMt = Number.parseFloat(style.scrollMarginTop); const top = window.scrollY + el.getBoundingClientRect().top - scrollMt; - return { id: section.id, top }; + return { id: section.hash, top }; }) .filter((x): x is { id: string; top: number } => x !== null); }; createEffect(() => { - if (tableOfContents.length === 0) return; + if (sections.length === 0) return; const headings = getHeadings(); function onScroll() { @@ -51,10 +55,10 @@ export function TableOfContents() { return () => { window.removeEventListener("scroll", onScroll); }; - }, [getHeadings, tableOfContents]); + }, [getHeadings, sections]); - function isActive(section: Section) { - if (section.id === currentSection()) return true; + function isActive(section: DocSection) { + if (section.hash === currentSection()) return true; return false; // if (!section.children) return false; @@ -72,19 +76,19 @@ export function TableOfContents() {
    - + {(section) => (
  1. - {section.title} + {section.content}

  2. diff --git a/app/services/DocCache.ts b/app/services/DocCache.ts index 540ad76..99646ed 100644 --- a/app/services/DocCache.ts +++ b/app/services/DocCache.ts @@ -1,4 +1,5 @@ import type { FlexSearchData } from "./FlexSearchService"; +import type { TableOfContents } from "@/remarkHeadingId"; import type { Node } from "@markdoc/markdoc"; import { slugifyWithCounter } from "@sindresorhus/slugify"; @@ -7,7 +8,6 @@ import { hrtime } from "node:process"; import fs from "node:fs/promises"; import path from "node:path"; import yaml from "js-yaml"; -import { copyFile } from "node:fs"; const __dirname = path.resolve(); @@ -15,12 +15,14 @@ export type SectionCache = { content: string; frontmatter?: SectionFrontmatter; markdocNode: Node; + sections: DocSection[]; }; export type DocSection = { content: string; hash?: string; subsections: string[]; + level?: number; }; type SectionFrontmatter = { @@ -99,7 +101,12 @@ class DocCache { if (node.type === "heading" && node.attributes?.level <= 2) { const hash = (node.attributes?.id as string) ?? this.slugify(content); const subsections: string[] = []; - sections.push({ content, hash, subsections }); + sections.push({ + content, + hash, + subsections, + level: node.attributes?.level, + }); } else { sections.at(-1)?.subsections.push(content); } @@ -124,9 +131,26 @@ class DocCache { return data; } + private getTableOfContents(markdocNode: Node) { + const sections: DocSection[] = []; + this.extractSections(markdocNode, sections); + + return sections; + } + private async cacheFile(file: string): Promise { const [content, frontmatter, markdocNode] = await this.getFileContent(file); - this.cache.set(file, { content, frontmatter, markdocNode }); + const filePath = file + .replace(/\+Page\.md(x)?$/, "") + .replace(/\/+/, "/") + .replace(/\/$/, ""); + + this.cache.set(filePath, { + content, + frontmatter, + markdocNode, + sections: this.getTableOfContents(markdocNode), + }); } private async populateCache(): Promise { @@ -157,6 +181,10 @@ class DocCache { return DocCache.getInstance().cache; } + public getCache(): Map { + return this.cache; + } + public get(file: string): SectionCache | undefined { return this.cache.get(file); }