Add ToC to blog posts

This commit is contained in:
Jade Ellis
2024-07-16 16:59:04 +01:00
parent 008bfa4d94
commit 58d3d01cbe
7 changed files with 243 additions and 8 deletions
+78
View File
@@ -0,0 +1,78 @@
<script lang="ts">
import TocItem from "./TocItem.svelte";
let className = "toc";
type FlatHeading = { level: number; title: string };
export let headings: nestedListNode[];
// creates a `class` property, even
// though it is a reserved word
export { className as class };
export let listType = "ul";
let open = false;
/** @type {import('./$types').Snapshot<string>} */
export const snapshot = {
capture: () => open,
restore: (value: boolean) => (open = value),
};
// console.log(headings);
</script>
<aside class={className}>
<details bind:open>
<summary accesskey="c" title="(Alt + C)">Table of Contents</summary>
<div class="inner">
{#if headings?.length > 0}
<svelte:element
this={listType}
class="toc-level {'toc-level-' + headings[0].level}"
>
{#each headings as node}
<TocItem {node} {listType} />
{/each}
</svelte:element>
{/if}
</div>
</details>
</aside>
<style>
aside {
margin-block: calc(var(--spacing) / 4);
}
details {
/* margin: var(--spacing) 2px; */
margin: 0 2px;
border: 1px solid var(--surface-secondary-color);
background: var(--surface-color);
border-radius: var(--border-radius);
padding: 0.4em;
}
details summary {
cursor: zoom-in;
margin-inline-start: 10px;
user-select: none;
}
details[open] summary {
cursor: zoom-out;
}
summary {
font-weight: 500;
}
.inner {
padding: 0 10px;
opacity: 0.9;
margin-block-start: calc(var(--spacing) / 4);
margin-block-end: calc(var(--spacing) / 2);
margin-inline: calc(var(--spacing) / 2);
}
.inner :global(ul) {
margin: 0;
margin-inline-start: calc(var(--spacing));
padding: 0;
}
summary:focus {
outline: 0;
}
</style>
+16
View File
@@ -0,0 +1,16 @@
<script lang="ts">
export let node: nestedListNode;
export let listType = "ul"
</script>
<li class="toc-item {"toc-item-" + node.level}">
<a href={"#" + node.id} class="toc-link {"toc-link-" + node.level}">{node.title}</a>
{#if node.children.length > 0}
<svelte:element this={listType} class="toc-level {"toc-level-" + node.children[0].level}">
{#each node.children as nodes}
<svelte:self node={nodes} {listType} />
{/each}
</svelte:element>
{/if}
</li>
+7
View File
@@ -0,0 +1,7 @@
type nestedListNode = {
title: string;
id: string;
level: number;
children: nestedListNode[];
};