Browse Source

Allow two ToC component variants

- A sidebar variant is meant for integration within a sidebar.  This is used in the current Publication component.
- An accordion variant is intended for standalone use.
master
buttercat1791 9 months ago
parent
commit
b07914f963
  1. 30
      src/lib/components/publications/Publication.svelte
  2. 65
      src/lib/components/publications/TableOfContents.svelte

30
src/lib/components/publications/Publication.svelte

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
SidebarGroup,
SidebarWrapper,
Heading,
CloseButton,
} from "flowbite-svelte";
import { getContext, onDestroy, onMount } from "svelte";
import {
@ -90,6 +91,10 @@ @@ -90,6 +91,10 @@
return currentBlog !== null && $publicationColumnVisibility.inner;
}
function closeToc() {
publicationColumnVisibility.update((v) => ({ ...v, toc: false }));
}
function closeDiscussion() {
publicationColumnVisibility.update((v) => ({ ...v, discussion: false }));
}
@ -155,13 +160,20 @@ @@ -155,13 +160,20 @@
</script>
<!-- Table of contents -->
{#if publicationType !== "blog" || !isLeaf}
<TableOfContents
depth={0}
onSectionFocused={(address: string) => {
publicationTree.setBookmark(address);
}}
/>
{#if publicationType !== 'blog' || !isLeaf}
{#if $publicationColumnVisibility.toc}
<Sidebar class='sidebar-leather left-0 md:!pr-8'>
<CloseButton onclick={closeToc} class='btn-leather absolute top-0 right-0' />
<TableOfContents
displayMode='sidebar'
rootAddress={rootAddress}
depth={2}
onSectionFocused={(address: string) => {
publicationTree.setBookmark(address);
}}
/>
</Sidebar>
{/if}
{/if}
<!-- Default publications -->
@ -205,9 +217,7 @@ @@ -205,9 +217,7 @@
<!-- Blog list -->
{#if $publicationColumnVisibility.blog}
<div
class="flex flex-col p-4 space-y-4 overflow-auto max-w-xl flex-grow-1
{isInnerActive() ? 'discreet' : ''}
"
class={`flex flex-col p-4 space-y-4 overflow-auto max-w-xl flex-grow-1 ${isInnerActive() ? 'discreet' : ''}`}
>
<div
class="card-leather bg-highlight dark:bg-primary-800 p-4 mb-4 rounded-lg border"

65
src/lib/components/publications/TableOfContents.svelte

@ -1,24 +1,36 @@ @@ -1,24 +1,36 @@
<script lang='ts'>
import type { TableOfContents, TocEntry } from '$lib/components/publications/table_of_contents.svelte';
import { TableOfContents, type TocEntry } from '$lib/components/publications/table_of_contents.svelte';
import { getContext } from 'svelte';
import { Accordion, AccordionItem, Card } from 'flowbite-svelte';
import { Accordion, AccordionItem, Card, SidebarDropdownWrapper, SidebarGroup, SidebarItem } from 'flowbite-svelte';
import Self from './TableOfContents.svelte';
import type { SveltePublicationTree } from './svelte_publication_tree.svelte';
import { page } from '$app/state';
let {
export type TocDisplayMode = 'accordion' | 'sidebar';
let {
displayMode = 'accordion',
rootAddress,
depth,
onSectionFocused,
} = $props<{
displayMode?: TocDisplayMode;
rootAddress: string;
depth: number;
onSectionFocused?: (address: string) => void;
}>();
let toc = getContext('toc') as TableOfContents;
let publicationTree = getContext('publicationTree') as SveltePublicationTree;
let toc = new TableOfContents(rootAddress, publicationTree, page.url.pathname ?? "");
let entries = $derived(
Array
let entries = $derived.by(() => {
console.debug("[ToC] Filtering entries for depth", depth);
const entries = Array
.from(toc.addressMap.values())
.filter((entry) => entry.depth === depth)
);
.filter((entry) => entry.depth === depth);
console.debug("[ToC] Filtered entries", entries.map((e) => e.title));
return entries;
});
// Track the currently visible section for highlighting
let currentSection = $state<string | null>(null);
@ -51,13 +63,34 @@ @@ -51,13 +63,34 @@
}
</script>
<Accordion flush class='overflow-y-auto w-64 p-4'>
{#each entries as entry}
<AccordionItem open={entry.expanded}>
<h3 class='text-lg font-bold'>{entry.title}</h3>
{#if displayMode === 'accordion'}
<Accordion flush multiple>
{#each entries as entry}
<AccordionItem open={entry.expanded}>
{#snippet header()}
<span class="text-gray-800 dark:text-gray-300">{entry.title}</span>
{/snippet}
{#if entry.children.length > 0}
<Self rootAddress={entry.address} depth={depth + 1} onSectionFocused={onSectionFocused} />
{/if}
</AccordionItem>
{/each}
</Accordion>
{:else}
<SidebarGroup>
{#each entries as entry}
{#if entry.children.length > 0}
<Self depth={depth + 1} onSectionFocused={onSectionFocused} />
<SidebarDropdownWrapper label={entry.title}>
<Self
displayMode={displayMode}
rootAddress={entry.address}
depth={depth + 1}
onSectionFocused={onSectionFocused}
/>
</SidebarDropdownWrapper>
{:else}
<SidebarItem label={entry.title} href={entry.href} />
{/if}
</AccordionItem>
{/each}
</Accordion>
{/each}
</SidebarGroup>
{/if}
Loading…
Cancel
Save