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[];
|
||||
};
|
||||
@@ -4,6 +4,7 @@
|
||||
import SvelteSeo from "svelte-seo";
|
||||
export let data;
|
||||
import { SITE_URL } from "$lib/metadata";
|
||||
import Toc from "$lib/Toc.svelte";
|
||||
// let GhReleasesDownload: Promise<any>;
|
||||
// if (data.ghReleaseData) {
|
||||
// GhReleasesDownload = import("$lib/GhReleasesDownload.svelte").then((m) => m.default)
|
||||
@@ -29,17 +30,25 @@
|
||||
|
||||
<article class="h-entry">
|
||||
<h1 id="title" class="p-name">{data.post.title}</h1>
|
||||
<aside>Published on <time class="dt-published" datetime={data.post.date}>{new Date(data.post.date).toLocaleDateString()}</time></aside>
|
||||
<aside>
|
||||
Published on <time class="dt-published" datetime={data.post.date}
|
||||
>{new Date(data.post.date).toLocaleDateString()}</time
|
||||
>
|
||||
</aside>
|
||||
<Toc headings={data.post.headings} />
|
||||
<!-- {#await GhReleasesDownload}
|
||||
|
||||
{:then component}
|
||||
<svelte:component this={component} releaseData={data.ghReleaseData} />
|
||||
{/await} -->
|
||||
|
||||
<!-- <div class="e-content"> -->
|
||||
<svelte:component this={data.component} />
|
||||
<div class="e-content">
|
||||
<svelte:component this={data.component} />
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
aside {font-size: .85em;}
|
||||
</style>
|
||||
aside {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user