diff --git a/frontend/src/docs/guides.ts b/frontend/src/docs/guides.ts
index f5bccfd..df5fab1 100644
--- a/frontend/src/docs/guides.ts
+++ b/frontend/src/docs/guides.ts
@@ -20,10 +20,12 @@ const escape = (text: string) => text.replace(/&/g, "&").replace(/
text
.toLowerCase()
- .replace(/<[^>]+>/g, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "");
+/** A heading's words: no backticks, links as their text. */
+const plain = (markdown: string) => markdown.replace(/`/g, "").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1");
+
function read(file: string): Guide {
const source = sources[`./${file}.md`];
if (source === undefined) throw new Error(`docs: no ${file}.md`);
@@ -31,16 +33,18 @@ function read(file: string): Guide {
const toc: Guide["toc"] = [];
const marked = new Marked({
renderer: {
- heading({ tokens, depth }: Tokens.Heading) {
- const html = this.parser.parseInline(tokens);
+ heading({ tokens, depth, text }: Tokens.Heading) {
+ const words = plain(text);
if (depth === 1) {
- title = html.replace(/<[^>]+>/g, "");
+ if (title) throw new Error(`docs: ${file}.md has a second # title`);
+ title = words;
return "";
}
- const id = slugify(html);
+ const html = this.parser.parseInline(tokens);
+ const id = slugify(words);
if (depth === 2) {
if (toc.some((h) => h.id === id)) throw new Error(`docs: ${file}.md repeats heading ${id}`);
- toc.push({ id, text: html.replace(/<[^>]+>/g, "") });
+ toc.push({ id, text: words });
}
return `${html}`;
},
diff --git a/frontend/src/pages/Docs.tsx b/frontend/src/pages/Docs.tsx
index 8ecb8fa..d998c79 100644
--- a/frontend/src/pages/Docs.tsx
+++ b/frontend/src/pages/Docs.tsx
@@ -37,7 +37,8 @@ export function Docs() {
const link = target.closest("a[href^='/']");
if (!link || e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return;
e.preventDefault();
- navigate({ to: link.getAttribute("href")! });
+ const url = new URL(link.href);
+ navigate({ to: url.pathname, hash: url.hash.slice(1) || undefined });
};
return (
@@ -66,7 +67,7 @@ export function Docs() {
{guide.toc.length > 0 && (
-