Skip to content

Commit 0f88685

Browse files
committed
Reduce boilerplate with TableOfContents
1 parent 683bb4a commit 0f88685

File tree

7 files changed

+106
-89
lines changed

7 files changed

+106
-89
lines changed

src/lib/components/shared/Code.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
children,
77
language,
88
nohl = false,
9+
class: className,
910
...restProps
1011
}: {
1112
children: Snippet;
1213
language?: string;
1314
nohl?: boolean;
15+
class: string;
1416
} = $props();
1517
1618
let codeElement: HTMLElement;
@@ -22,7 +24,7 @@
2224
});
2325
</script>
2426

25-
<pre {...restProps}><code
27+
<pre class={className} {...restProps}><code
2628
class={language != undefined ? 'language-' + language : ''}
2729
bind:this={codeElement}>{@render children()}</code
2830
></pre>

src/lib/components/shared/TableOfContents.svelte

Lines changed: 0 additions & 69 deletions
This file was deleted.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<script lang="ts">
2+
import { cn } from '@/utils';
3+
import { onMount, type Snippet } from 'svelte';
4+
import type { TOC, TOCElem } from '@/lib/table-of-contents';
5+
6+
let {
7+
// tableOfContents,
8+
class: className,
9+
...restProps
10+
}: {
11+
// tableOfContents: TOC;
12+
class?: string;
13+
} = $props();
14+
15+
let container: HTMLDivElement;
16+
let stack: Array<HTMLUListElement> = [];
17+
let previousElement: HTMLLIElement;
18+
19+
function applyListStyles(elem: HTMLLIElement | HTMLUListElement) {
20+
elem.classList += 'list-decimal';
21+
}
22+
23+
function processTOCElements() {
24+
const elements = document.querySelectorAll('div[data-toc-level]');
25+
elements.forEach((elem) => {
26+
let levelString = elem.getAttribute('data-toc-level');
27+
if (levelString == null) return;
28+
let level = parseInt(levelString);
29+
let title = elem.getAttribute('data-toc-title');
30+
let currentLevel = stack.length - 1;
31+
32+
let listItem = document.createElement('li');
33+
let anchor = document.createElement('a');
34+
anchor.textContent = title;
35+
anchor.href = '#' + title; // TODO: Convert title to id
36+
anchor.classList += 'text-blue-500';
37+
listItem.appendChild(anchor);
38+
39+
if (level > currentLevel) {
40+
let list = document.createElement('ul');
41+
applyListStyles(list);
42+
previousElement.appendChild(list);
43+
stack.push(list);
44+
} else if (level < currentLevel) {
45+
stack.pop();
46+
}
47+
48+
stack.at(-1)?.appendChild(listItem);
49+
50+
previousElement = listItem;
51+
});
52+
}
53+
54+
onMount(() => {
55+
let tocRoot = document.createElement('ul');
56+
applyListStyles(tocRoot);
57+
stack.push(tocRoot);
58+
processTOCElements();
59+
container.appendChild(tocRoot);
60+
});
61+
</script>
62+
63+
<div class={cn('', className)} {...restProps}>
64+
<p class="text-foreground text-xl font-bold">Table of Contents</p>
65+
<div bind:this={container}></div>
66+
</div>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script lang="ts">
2+
import Linkable from '@/components/shared/Linkable.svelte';
3+
4+
let {
5+
title,
6+
level = 0,
7+
...restProps
8+
}: {
9+
title: string;
10+
level?: number;
11+
} = $props();
12+
</script>
13+
14+
<div data-toc-level={level} data-toc-title={title} {...restProps}>
15+
<Linkable id={encodeURIComponent(title)}
16+
><p class="text-foreground text-xl font-bold">{title}</p></Linkable
17+
>
18+
</div>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Root from './TableOfContents.svelte';
2+
import Element from './TableOfContentsElement.svelte';
3+
4+
export {
5+
Root,
6+
Element,
7+
//
8+
Root as TableOfContents,
9+
Element as TableOfContentsElement
10+
};
File renamed without changes.

src/routes/blog/articles/numworks-programming/+page.svelte

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import Code from '@/components/shared/Code.svelte';
55
import Collapsible from '@/components/shared/Collapsible.svelte';
66
import Linkable from '@/components/shared/Linkable.svelte';
7-
import TableOfContents from '@/components/shared/TableOfContents.svelte';
8-
import type { TOC } from '@/lib/tableOfContents';
7+
import * as TableOfContents from '$lib/components/shared/table-of-contents/index.js';
8+
import type { TOC } from '@/lib/table-of-contents';
99
1010
let tableOfContents: TOC = [
1111
{ title: 'Introduction', id: 'intro' },
@@ -22,8 +22,8 @@
2222
</script>
2323

2424
<Article article={NUMWORKS_PROGRAMMING}>
25-
<TableOfContents {tableOfContents} />
26-
<Linkable id="intro"><p class="text-foreground text-xl font-bold">Introduction</p></Linkable>
25+
<TableOfContents.Root />
26+
<TableOfContents.Element title="Introduction" />
2727
<p>
2828
Towards the end of 2023, I got a <a
2929
target="_blank"
@@ -43,9 +43,7 @@
4343
customizable graphs). I mostly programmed on my calculator when I had nothing to do during
4444
class.
4545
</p>
46-
<Linkable id="py-modules">
47-
<p class="text-foreground text-xl font-bold">Python Modules</p>
48-
</Linkable>
46+
<TableOfContents.Element title="Python Modules" />
4947
<p>
5048
The Python implementation comes with a select few custom modules: <code>math</code>,
5149
<code>cmath</code>, <code>matplotlib.pyplot</code>, <code>numpy</code>, <code>turtle</code>,
@@ -74,12 +72,8 @@
7472
suspend execution for t seconds</Code
7573
>
7674
</Collapsible>
77-
<Linkable id="limits">
78-
<p class="text-foreground text-xl font-bold">Limitations</p>
79-
</Linkable>
80-
<Linkable id="py-performance">
81-
<p class="text-foreground text-xl font-bold">Performance</p>
82-
</Linkable>
75+
<TableOfContents.Element title="Limitations" />
76+
<TableOfContents.Element title="Performance" level={1} />
8377
<p>
8478
With these methods mentioned above, you can theoretically make just about anything, only limited
8579
by hardware. These limitations catch up to you quite quickly. For one, clearing the screen every
@@ -105,9 +99,7 @@
10599
creating full-fledged modules. After all, the calculator wasn't made to create games with
106100
Python, which is why the drawing module is as simple as it is.
107101
</p>
108-
<Linkable id="py-mem">
109-
<p class="text-foreground text-xl font-bold">Memory and Storage</p>
110-
</Linkable>
102+
<TableOfContents.Element title="Memory and Storage" level={1} />
111103
<p>
112104
It should be obvious that the team behind this calculator chose Python as the programming
113105
language available for users because of its simplicity for making scripts, and even more for
@@ -140,9 +132,7 @@ struct _mp_obj_base_t {
140132
seem like a lot, and it actually is, but when you have multiple large scripts installed, the
141133
limit is definitely reachable.
142134
</p>
143-
<Linkable id="native-apps">
144-
<p class="text-foreground text-xl font-bold">Writing native apps</p>
145-
</Linkable>
135+
<TableOfContents.Element title="Writing Native Apps" />
146136
<p>
147137
Recently, I discovered that it is possible to write external apps in C (and C++ or any other
148138
language that is compatible with C) that can be uploaded onto the calculator. This discovery

0 commit comments

Comments
 (0)