From b2a46333334e59a4a46d7de9d4ca39505848c9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 1 Oct 2026 11:52:29 -0400 Subject: [PATCH] =?UTF-8?q?T48a=20Docs=20=C2=B7=20Frame:=20titles=20and=20?= =?UTF-8?q?the=20list=20read=20plain=20words,=20links=20with=20a=20section?= =?UTF-8?q?=20route,=20long=20code=20wraps,=20the=20rail=20stays=20in=20fl?= =?UTF-8?q?ow=20on=20narrow=20screens,=20check.sh=20holds=20every=20docs?= =?UTF-8?q?=20example=20to=20Cargo.toml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/docs/guides.ts | 16 ++++++++++------ frontend/src/pages/Docs.tsx | 5 +++-- frontend/src/styles.css | 8 +++++--- scripts/check.sh | 4 ++++ 4 files changed, 22 insertions(+), 11 deletions(-) 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 && ( -