mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
Add ToC to blog posts
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
|
||||
type nestedListNode = {
|
||||
title: string;
|
||||
id: string;
|
||||
level: number;
|
||||
children: nestedListNode[];
|
||||
};
|
||||
Reference in New Issue
Block a user