moved and rewrote table-of-contents.svelte to use stateful design
This commit is contained in:
@@ -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 {
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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[] = [
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user