Skip to content

vscode: markdown preview navigation chrome — floating TOC + quick-jump overlay + per-heading mini-toolbar for long Codev artifacts #861

Description

@amrmelsayed

Problem

Codev specs and plans routinely cross 200–400 lines. The built-in markdown preview ships with no persistent navigation chrome — the only ways to move between sections are scrolling, opening the VS Code Outline panel (separate sidebar, no scroll-sync with the preview), or hand-rolling anchor links via URL. For a long spec being reviewed, this is a real friction tax on the read-pass.

The preview is the natural reading surface for long Codev artifacts (see #859 for the add-comment companion). This issue gives it a navigation layer designed for the long-doc case.

Proposal — three preview-pane navigation affordances, one bundle

These three features ship together because they share infrastructure: DOM heading scanning, previewScripts keyboard/click wiring, previewStyles overlay positioning, and localStorage UI-state persistence. Splitting them into three issues would duplicate the same plumbing three times.

1. Floating TOC sidebar

A persistent panel on the right edge of the preview listing every <h1><h3> heading in the current doc.

  • Renders: previewScripts scans rendered DOM for <h1><h3>, builds a tree (or flat list with indentation by depth), renders into a position: fixed panel
  • Click entry → smooth-scrolls preview to that heading's anchor
  • Scroll-spy: highlights the entry corresponding to the section currently in view (uses IntersectionObserver on the headings)
  • Collapsible per H1: click an H1 row to expand/collapse its children; state persists per-file in localStorage
  • Floating toggle icon (e.g. ) in the top-right corner of the preview to hide/show the whole TOC; the rendered content widens to fill when TOC is hidden
  • Visual: previewStyles uses VS Code theme variables (--vscode-sideBar-background, --vscode-foreground, etc.); ~200px wide; subtle border-left

2. Quick-jump overlay (keyboard-driven)

A centered fuzzy-search overlay that lets the user jump to any heading without leaving the keyboard.

  • Trigger: configurable keybind, default / (mirrors GitHub's "search this page" + vim's search) when the preview has focus. Alternative Cmd+K G if / conflicts
  • Renders: centered modal-style overlay (previewScripts injects DOM, previewStyles positions and themes)
  • Behavior:
    • Type to fuzzy-filter the heading list (use a tiny fuzzy library or hand-roll — score by character coverage)
    • / to move selection; Enter to jump; Esc to dismiss
    • Selected row's parent path shown breadcrumb-style at the top of the overlay (Acceptance criteria > 4. Out of scope)
  • No external dependency: bundle the fuzzy logic inline; the heading list is small (typically <50 entries)

3. Per-heading floating mini-toolbar

A small overlay that appears on hover over any heading element, providing inline navigation actions.

  • Trigger: hover over <h1><h6>; toolbar fades in to the right of the heading
  • Buttons:
    • ↑ prev section — scrolls to the previous same-level heading
    • ↓ next section — scrolls to the next same-level heading
    • 🔗 copy link — copies <file.md>#<heading-anchor> to clipboard
    • ▾ collapse — toggles collapse of everything until the next same-level heading (uses CSS to hide siblings; state in localStorage)
  • Visual: small inline buttons, theme-aware; positioned to not collide with vscode: add review comments from the markdown preview pane (hover-+ per block, no editor mode-switch) #859's + add-comment affordance (different hover target — heading vs paragraph)

Why all three together

Surface Strength Weakness
Floating TOC Always-visible context; scroll-spy shows where you are Takes screen real-estate
Quick-jump overlay Keyboard-only, fast for power users Hidden until invoked
Per-heading toolbar Discoverable, in-context (right next to where you're reading) Per-section only, no whole-doc map

Different users converge on different patterns (mouse-driven prefer the TOC; keyboard-driven prefer the overlay; everyone uses the per-heading actions when they happen to hover). Shipping all three covers the surface area.

Path eligibility

Same gating as #859 and #860: only applies to .md files in codev/(plans|specs|reviews)/. The TOC, overlay, and toolbar are all no-ops on other markdown files (which already have the standard VS Code preview behavior).

Implementation sketch

Files

  • New: packages/vscode/src/markdown-preview/navigation.jspreviewScripts entry point; orchestrates DOM scanning, TOC rendering, overlay, per-heading toolbar
  • New: packages/vscode/src/markdown-preview/navigation.csspreviewStyles; positioning + theme variables
  • Both contributed via contributes.markdown.previewScripts and contributes.markdown.previewStyles in package.json

Path gating in webview script

The preview script needs to know the source document URI to gate. VS Code's markdown preview passes this via meta tags in the rendered HTML (<meta name="vscode-markdown-preview-source" content="<uri>">). Script reads this on load; bails (no-op) if the URI doesn't match the eligibility regex.

State persistence

localStorage keys, scoped per-file:

  • codev.toc.visible.<uri> — boolean, default true
  • codev.toc.collapsed.<uri> — array of collapsed H1 anchor IDs
  • codev.section.collapsed.<uri> — array of collapsed heading anchor IDs (from the toolbar collapse action)

No markdownItPlugins for this issue

All three features operate on the rendered DOM (post-markdown-it). No AST transformation needed. This keeps the contribution surface to just previewScripts + previewStyles.

Acceptance criteria

Floating TOC

  • Persistent panel on the right edge of the preview; shows every <h1><h3> heading
  • Click any entry → smooth-scrolls preview to that heading
  • Scroll-spy highlights the entry corresponding to the section currently visible
  • Collapsible per H1; collapse state persists per-file across reloads via localStorage
  • Floating toggle icon (e.g. ) hides/shows the whole TOC; rendered content reflows to fill
  • Visible only on .md files in codev/(plans|specs|reviews)/

Quick-jump overlay

  • Keybind (default /) opens a centered overlay listing all headings; configurable via package.json keybinding contribution
  • Type to fuzzy-filter; Arrow keys to move selection; Enter to jump; Esc to dismiss
  • Breadcrumb path shown for the selected row
  • Visible only on the eligible-path set

Per-heading mini-toolbar

  • On hover over any heading, a floating toolbar appears to the right of it
  • Buttons: prev section / next section / copy link / collapse
  • copy link writes <basename>.md#<anchor> to the clipboard
  • collapse toggles visibility of everything until the next same-level heading; state persists per-file
  • Does not conflict visually or behaviorally with vscode: add review comments from the markdown preview pane (hover-+ per block, no editor mode-switch) #859's + add-comment affordance (different hover target — heading element vs paragraph element)

General

  • All UI uses VS Code theme variables for color (no hardcoded values)
  • All features no-op on non-eligible .md files
  • No external runtime dependencies added to the extension package
  • No regression to VS Code's built-in markdown preview behavior (sync-editor-to-preview, sync-preview-to-editor, etc.)

Out of scope (v1)

  • Cross-file navigation (jump between specs/plans) — single doc only in v1
  • REVIEW marker minimap (right-edge column showing comment locations) — depends on vscode: add review comments from the markdown preview pane (hover-+ per block, no editor mode-switch) #859 Phase 2 (rendering markers in preview); separate filing
  • Reading progress bar / AC progress badge / frontmatter status badges — Document-state surfaces; separate themed filing
  • Outline panel enrichment (showing REVIEW markers as outline children) — different VS Code API entry point (DocumentSymbolProvider, not preview-side); separate filing if/when desired
  • Mobile / touch support — hover-triggered affordances assume a pointing device
  • Customizable TOC styling — fixed visual; no user settings in v1

Related

Why this is high leverage

For long Codev artifacts — which is the typical case — navigation friction is the read-pass friction. Today's preview is "scroll a big document"; with this layer it becomes "navigate a structured document." The three surfaces cover keyboard-driven, mouse-driven, and discovery-driven workflows simultaneously. Shipping all three as one PR is genuinely cheaper than splitting them because of the shared script/style infrastructure.

Metadata

Metadata

Assignees

Labels

area/vscodeArea: VS Code extension

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions