3 changed files with 67 additions and 14 deletions
@ -1,22 +1,63 @@ |
|||||||
<script lang='ts'> |
<script lang='ts'> |
||||||
import type { TableOfContents } from '$lib/components/publications/table_of_contents.svelte'; |
import type { TableOfContents, TocEntry } from '$lib/components/publications/table_of_contents.svelte'; |
||||||
import { getContext } from 'svelte'; |
import { getContext } from 'svelte'; |
||||||
import { Card } from 'flowbite-svelte'; |
import { Accordion, AccordionItem, Card } from 'flowbite-svelte'; |
||||||
|
import Self from './TableOfContents.svelte'; |
||||||
|
|
||||||
let { rootAddress } = $props<{ rootAddress: string }>(); |
let { |
||||||
|
depth, |
||||||
|
onSectionFocused, |
||||||
|
} = $props<{ |
||||||
|
depth: number; |
||||||
|
onSectionFocused?: (address: string) => void; |
||||||
|
}>(); |
||||||
|
|
||||||
let toc = getContext('toc') as TableOfContents; |
let toc = getContext('toc') as TableOfContents; |
||||||
|
|
||||||
// TODO: Check root address against ToC root address for correctness. |
let entries = $derived( |
||||||
|
Array |
||||||
|
.from(toc.addressMap.values()) |
||||||
|
.filter((entry) => entry.depth === depth) |
||||||
|
); |
||||||
|
|
||||||
// Determine the event kind. |
// Track the currently visible section for highlighting |
||||||
// If index, use the publication tree to build the table of contents. |
let currentSection = $state<string | null>(null); |
||||||
// If single event, build the table of contents from the rendered HTML. |
|
||||||
// Each rendered `<h>` should receive an entry in the ToC. |
// Handle section visibility changes from the IntersectionObserver |
||||||
|
function handleSectionVisibility(address: string, isVisible: boolean) { |
||||||
|
if (isVisible) { |
||||||
|
currentSection = address; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Toggle expansion of a ToC entry |
||||||
|
async function toggleExpansion(entry: TocEntry) { |
||||||
|
// Update the current section in the ToC |
||||||
|
const tocEntry = toc.getEntry(entry.address); |
||||||
|
if (tocEntry) { |
||||||
|
// Ensure the parent sections are expanded |
||||||
|
let parent = tocEntry.parent; |
||||||
|
while (parent) { |
||||||
|
parent.expanded = true; |
||||||
|
parent = parent.parent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
entry.expanded = !entry.expanded; |
||||||
|
if (entry.expanded && !entry.childrenResolved) { |
||||||
|
onSectionFocused?.(entry.address); |
||||||
|
await entry.resolveChildren(); |
||||||
|
} |
||||||
|
} |
||||||
</script> |
</script> |
||||||
|
|
||||||
<Card class='flex flex-col space-y-2'> |
<Accordion flush class='overflow-y-auto w-64 p-4'> |
||||||
{#each toc as entry} |
{#each entries as entry} |
||||||
<a href={entry.href}>{entry.title}</a> |
<AccordionItem open={entry.expanded}> |
||||||
|
<h3 class='text-lg font-bold'>{entry.title}</h3> |
||||||
|
{#if entry.children.length > 0} |
||||||
|
<Self depth={depth + 1} onSectionFocused={onSectionFocused} /> |
||||||
|
{/if} |
||||||
|
</AccordionItem> |
||||||
{/each} |
{/each} |
||||||
</Card> |
</Accordion> |
||||||
|
|||||||
Loading…
Reference in new issue