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