From ee85059dee344992ff7f5c1def098b443c12df05 Mon Sep 17 00:00:00 2001 From: buttercat1791 Date: Sat, 17 May 2025 08:58:14 -0500 Subject: [PATCH] Add more supporting functions for ToC component --- src/lib/components/TableOfContents.svelte | 72 +++++++++++++++++++++-- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/src/lib/components/TableOfContents.svelte b/src/lib/components/TableOfContents.svelte index 71bcdd0..78aa83a 100644 --- a/src/lib/components/TableOfContents.svelte +++ b/src/lib/components/TableOfContents.svelte @@ -6,11 +6,75 @@ let { rootAddress } = $props<{ rootAddress: string }>(); + let publicationTree = getContext('publicationTree') as PublicationTree; + + let tocAddresses = $state>(new Map()); + let tocRoot = $state(null); + // Determine the event kind. // If index, use the publication tree to build the table of contents. // If single event, build the table of contents from the rendered HTML. // Each rendered `` should receive an entry in the ToC. + function normalizeHashPath(title: string): string { + // TODO: Confirm this uses good normalization logic to produce unique hrefs within the page. + return title.toLowerCase().replace(/ /g, '-'); + } + + async function insertIntoTocFromPublicationTree(address: string): Promise { + const targetEvent = await publicationTree.getEvent(address); + if (!targetEvent) { + console.warn(`[ToC] Event ${address} not found.`); + // TODO: Determine how to handle this case in the UI. + return; + } + + const hierarchyEvents = await publicationTree.getHierarchy(address); + if (hierarchyEvents.length === 0) { + // This means we are at root. + return; + } + + // Michael J 05 May 2025 - In this loop, we assume that the parent of the current event has + // already been populated into the ToC. As long as the root is set when the component is + // initialized, this code will work fine. + let currentParentTocNode: TocEntry | null = tocRoot; + for (let i = 0; i < hierarchyEvents.length; i++) { + const currentEvent = hierarchyEvents[i]; + const currentAddress = currentEvent.tagAddress(); + + if (tocAddresses.has(currentAddress)) { + continue; + } + + const currentEventChildAddresses = await publicationTree.getChildAddresses(currentAddress); + for (let address of currentEventChildAddresses) { + if (address === null) { + continue; + } + + const childEvent = await publicationTree.getEvent(address); + if (!childEvent) { + console.warn(`[ToC] Event ${address} not found.`); + continue; + } + + currentParentTocNode!.children ??= []; + + const childTocEntry: TocEntry = { + title: childEvent.getMatchingTags('title')[0][1], + href: `${page.url.pathname}#${normalizeHashPath(childEvent.getMatchingTags('title')[0][1])}`, + expanded: false, + children: null, + }; + currentParentTocNode!.children.push(childTocEntry); + tocAddresses.set(address, childTocEntry); + } + + currentParentTocNode = tocAddresses.get(currentAddress)!; + } + } + function buildTocFromDocument(parentElement: HTMLElement): void { const entries: TocEntry[] = []; const currentPathname = page.url.pathname; @@ -30,8 +94,8 @@ const tocEntry: TocEntry = { title, href, - expanded: false, // Default to not expanded; can be changed as needed. - children: null, // These are leaf entries from a flat scan of headers. + expanded: false, + children: null, }; entries.push(tocEntry); } @@ -39,10 +103,6 @@ // TODO: Update ToC state within the component. } - - let toc = $state([]); - - const publicationTree = getContext('publicationTree') as PublicationTree;