moved and rewrote table-of-contents.svelte to use stateful design

This commit is contained in:
2026-02-15 13:36:29 +01:00
parent 151e1206ab
commit 6042157caf
6 changed files with 37 additions and 47 deletions

View File

@@ -1,32 +1,27 @@
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte'; import {onMount} from 'svelte';
let { interface TocEntry {
stickyScrolling, text: string;
}: { link: string;
stickyScrolling?: boolean;
} = $props();
let idCounter: number = 0; /**
* possible values: 0, 1, 2, 3
*/
indentLevel: number;
}
let root: HTMLElement; let tocEntries: TocEntry[] = $state([]);
let container: HTMLElement;
onMount(() => { onMount(() => {
let headers = getHeaders(); let headers = getHeaders();
headers.forEach(header => { headers.forEach(header => {
let headerId = getHeaderId(header); tocEntries.push({
var element = document.createElement("a"); text: `${(header as HTMLElement).innerHTML}`,
element.classList += "toc-level-" + getHeaderLevel(header); link: `#${getHeaderId(header)}`,
element.href = `#${headerId}`; indentLevel: getHeaderLevel(header),
element.innerHTML = `${(header as HTMLElement).innerHTML}`; });
container.appendChild(element);
}); });
// Hide table of contents if no valid entries have been found
if (headers.length == 0) {
root.style.display = "none";
}
}); });
let getHeaders = function(): NodeList { let getHeaders = function(): NodeList {
@@ -43,41 +38,40 @@
text = text.replaceAll(/[^a-zA-Z0-9]/gi, "-"); text = text.replaceAll(/[^a-zA-Z0-9]/gi, "-");
id = text; id = text;
(header as HTMLElement).id = id; (header as HTMLElement).id = id;
idCounter += 1;
} }
return id; return id;
} }
let getHeaderLevel = function(header: Node): string { function getHeaderLevel(header: Node): number {
switch ((header as HTMLElement).tagName) { switch ((header as HTMLElement).tagName) {
case "H2": case "H2":
return "0"; return 0;
case "H3": case "H3":
return "1"; return 1;
case "H4": case "H4":
return "2"; return 2;
case "H5": case "H5":
return "3"; return 3;
default: default:
return "0"; return 0;
} }
} }
</script> </script>
{#if stickyScrolling} {#snippet tocEntryLine({ entry }: { entry: TocEntry })}
<div class="toc-container sticky-toc" bind:this={root}> <a class="toc-level-{entry.indentLevel}" href="{entry.link}">{@html entry.text}</a>
{@render tocList()} {/snippet}
</div>
{:else} {#if tocEntries.length > 0}
<div class="toc-container" bind:this={root}> <div class="toc-container">
{@render tocList()} <ul class="toc-list">
{#each tocEntries as entry}
{@render tocEntryLine({ entry })}
{/each}
</ul>
</div> </div>
{/if} {/if}
{#snippet tocList()}
<ul class="toc-list" bind:this={container}></ul>
{/snippet}
<style> <style>
:global { :global {
body { body {
@@ -95,14 +89,10 @@
backdrop-filter: blur(var(--blur-radius-background)); backdrop-filter: blur(var(--blur-radius-background));
} }
.sticky-toc {
position: sticky;
top: 20px;
}
.toc-list { .toc-list {
padding: 0; padding: 0;
margin: 0; margin: 0;
width: 100%;
} }
.toc-list a { .toc-list a {

View File

@@ -1,7 +1,7 @@
<script> <script>
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
export let data; export let data;
</script> </script>

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
import LinkList, { type LinkEntry } from "$lib/lists/link-list.svelte"; import LinkList, { type LinkEntry } from "$lib/lists/link-list.svelte";
let favouriteAlbums: LinkEntry[] = [ let favouriteAlbums: LinkEntry[] = [

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
import { type Project, games, hardware, apps, music } from './projects'; import { type Project, games, hardware, apps, music } from './projects';
import LinkList from "$lib/lists/link-list.svelte"; import LinkList from "$lib/lists/link-list.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
</script> </script>
<svelte:head> <svelte:head>

View File

@@ -1,7 +1,7 @@
<script> <script>
import Banner2 from "$lib/banner2.svelte"; import Banner2 from "$lib/banner2.svelte";
import Content from "$lib/viewport/content.svelte"; import Content from "$lib/viewport/content.svelte";
import TableOfContents from "$lib/table-of-contents.svelte"; import TableOfContents from "$lib/components/table-of-contents.svelte";
export let data; export let data;
</script> </script>