gabriel / musehub public
Open #102 Enhancement
filed by gabriel human · 72 days ago

Mist detail page: replace broken symbol anchors with a proper markdown TOC

0 Anchors
Blast radius
Churn 30d
0 Proposals

Mist detail page: replace broken symbol anchors with a proper markdown TOC

Background

The mist detail page had a "Symbol Anchors" sidebar panel that listed the mist's symbol_anchors field. That panel was designed for code file views, where symbols are short identifiers (InsertOp, wire_fetch_mpack) and clicking one jumps to a definition. On a markdown mist it misfired: markdown "symbols" are full heading strings, which truncate to identical-looking labels, are not clickable, and convey no useful information.

Example from gabriel/mist-clone-mpack-deep-dive.md:

mist-clone-mpack-deep-dive.md::Clone…   (×20, all truncated the same)

The panel was actively degrading the UX — it looked broken because it was broken. It has been removed from mist_detail.html as of this commit.

The right replacement is a heading-based table of contents that extracts ## and ### headings from the markdown source and renders them as clickable scroll-anchors in the sidebar — the same UX pattern GitHub uses for READMEs, but integrated into the MuseHub sidebar design.

Goal

  • Long markdown mists have a sidebar TOC showing ## / ### headings as clickable links
  • Clicking a heading link smooth-scrolls to that heading in the rendered content
  • The active heading is highlighted as the user scrolls (scroll-spy)
  • Short mists (no headings, or fewer than 2 headings) hide the TOC entirely — no empty panel
  • The panel renders correctly on code mists (no headings → panel hidden)

Design

Heading extraction

Client-side JS: after the markdown is rendered into #artifact-content, query querySelectorAll('h2, h3') and build the TOC list dynamically. No server-side changes needed — the rendered HTML already has the headings.

Each heading needs a stable id attribute for anchor targeting. The markdown renderer should add slug IDs to headings (e.g. ## The full clone path<h2 id="the-full-clone-path">). Verify the current renderer (md_html) already does this; if not, the JS builder can inject the IDs itself before building links.

TOC panel HTML (injected by JS, replaces the removed symbol-anchors block)

<div class="ms-sidebar-card ms-toc-card" id="ms-toc">
  <div class="ms-sidebar-card-title">
    <!-- icon("list", 13) -->
    Contents
  </div>
  <ul class="ms-toc-list">
    <li class="ms-toc-item ms-toc-h2">
      <a href="#the-full-clone-path" class="ms-toc-link">The full clone path</a>
    </li>
    <li class="ms-toc-item ms-toc-h3">
      <a href="#why-null-oids-exist" class="ms-toc-link ms-toc-indent">Why null OIDs exist</a>
    </li>
    …
  </ul>
</div>

ms-toc-indent adds 12px left padding to visually nest ### under ##.

Scroll-spy

IntersectionObserver on all h2/h3 elements; when one enters the viewport, add ms-toc-link--active to its corresponding TOC entry and remove it from all others.

Minimum heading threshold

If the heading count is < 2, do not render the TOC panel. A one-heading document doesn't benefit from a TOC.

Phases

Phase 1 — Heading IDs and static TOC injection

  • TOC_01 Verify (or add) slug-id generation to markdown headings in the rendered output
  • TOC_02 JS: extract h2/h3 from #artifact-content after page load
  • TOC_03 JS: build and inject #ms-toc sidebar card
  • TOC_04 CSS: ms-toc-list, ms-toc-item, ms-toc-link, ms-toc-indent styles
  • TOC_05 Hide panel when heading count < 2

Phase 2 — Scroll-spy

  • TOC_06 IntersectionObserver highlights active heading in TOC
  • TOC_07 Active link style (ms-toc-link--active) — subtle, not distracting

Phase 3 — Code mist and non-markdown handling

  • TOC_08 Panel is absent (not empty) on code mists and MIDI mists
  • TOC_09 Panel is absent on very short markdown mists with < 2 headings

Acceptance criteria

  • Visiting gabriel/mist-clone-mpack-deep-dive.md shows a "Contents" sidebar panel with 6–8 section links matching the ## headings in the document
  • Clicking "The full clone path" smooth-scrolls to that section
  • Scrolling past "The null-OID bug" highlights that entry in the TOC
  • Visiting a code mist (.py, .ts) shows no TOC panel
  • No symbol-anchors panel ever appears anywhere on the mist detail page

Out of scope

  • h1 headings in the TOC (they're typically the document title — already in the page header)
  • h4/h5/h6 nesting
  • Server-side TOC generation (client-side is sufficient and avoids a render pipeline change)
  • Applying the same TOC to issue_detail.html or blob views — separate issues
  • Removing or redesigning symbol_anchors from the data model — the field stays, the display is just hidden until it's implemented correctly
Activity
gabriel opened this issue 72 days ago
No activity yet. Use the CLI to comment.