fix(viewer): make in-document links in rendered markdown scroll to their heading

marked emits no heading ids and, with <base href="/">, a bare #section href points at the dashboard root, so [Install](#installation) in the File Viewer did nothing. The shared click delegate now resolves fragment links against the rendered document: GitHub-style slugs in data-md-anchor (never ids, so a heading cannot capture an app element), case-insensitive and percent-decoded, repeats numbered -1/-2, # = top, explicit ids supported, an unmatched fragment ignored instead of navigating.

Tests: slug/assign/find unit tests (CI gate) and a real-browser test clicking links in a File Viewer document, which fails without the change.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrzFKEdBLwVfu6ev2ZscJS
This commit is contained in:
Devvyn
2026-10-09 17:01:44 +08:00
co-authored by Claude Sonnet 5.5
parent 3a0cee6b90
commit 8da4a07a60
7 changed files with 363 additions and 1 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"aicodeman": patch
---
A link to another heading of the same file in the markdown File Viewer (`[Install](#installation)`) now scrolls to that heading. It did nothing: marked emits no heading ids, so there was nothing to jump to, and with `<base href="/">` a bare `#installation` href points at the dashboard's root, not at the page, so letting the browser follow it was never an in-page jump either. The shared link handler (File Viewer and Response Viewer) now resolves fragment links itself against the rendered document: headings get GitHub-style slugs (lower-case, punctuation dropped, a repeated title numbered `-1`, `-2`), matched case-insensitively and percent-decoded, `#` goes to the top, an explicit `<a id>` in the document works, and a fragment that matches nothing is ignored instead of navigating the app. The anchors are `data-md-anchor` attributes looked up inside the document, never `id`s, so a heading called "Settings" cannot collide with an element of the app itself.