Skip to content

vscode: markdown preview document-state surfaces — reading progress, AC progress, frontmatter status badges, reading time #862

@amrmelsayed

Description

@amrmelsayed

Problem

Long Codev specs/plans/reviews carry useful at-a-glance metadata that's not currently surfaced in the preview:

  • Where am I in the doc? (scroll position relative to length)
  • How done is it? (acceptance-criteria checkbox completion)
  • What's its approval state? (approved: / validated: YAML frontmatter)
  • How long will reading take? (word count → minutes)

All four are derivable from the doc content with zero new state. None require interaction. Today the architect either ignores them or hand-tallies — both bad. This issue surfaces all four as pure display chrome at the top of the preview.

Proposal — four document-state surfaces, one bundle

Bundled because they share infrastructure: a single sticky header bar at the top of the preview rendered via previewScripts + previewStyles, with no interaction (purely informational).

1. Reading progress bar

A thin colored bar fixed at the very top of the preview, tracking scroll position 0–100%.

  • Renders: 2–3px tall, full-width, accent color from VS Code theme (--vscode-progressBar-background)
  • Behavior: updates on scroll; smooth animation; fades to subtle background on hover so it doesn't fight other UI
  • Rationale: answers "how much more is there?" without scrolling to find out

2. Acceptance-criteria progress badge

A compact badge in the sticky header showing checkbox completion across the entire doc.

  • Format: AC 12 / 18 ✓ (or similar; 67% green when 80%+ complete, yellow otherwise)
  • Source: scan rendered DOM for <input type="checkbox"> elements (markdown-it renders - [ ] / - [x] as inputs); count checked vs total
  • Behavior: click → reserved for future (could jump to first unchecked); v1 no-op (display only)
  • Empty state: badge hidden when the doc has zero checkboxes

3. Frontmatter status badges

Parse YAML frontmatter at the top of the doc; render specific fields as colored chips.

Known Codev frontmatter fields (per codev/CLAUDE.md):

  • approved: 2026-01-29 → green chip ✓ approved · Jan 29

  • validated: [gemini, codex, claude] → blue chip validated by 3 (tooltip shows list)

  • (future: other fields render as gray "info" chips by default)

  • Source: simple YAML parse of the doc's first --- ... --- block (use js-yaml if not already bundled, or hand-roll for the small subset needed)

  • Behavior: static display; click → reserved for future; v1 no-op

  • Empty state: no chips when no frontmatter (today most committed files have it; pre-approval drafts don't)

4. Reading time estimate

Word-count derived estimate, shown in the sticky header.

  • Format: ~5 min read (using 225 wpm — standard for technical prose)
  • Source: count word-like tokens in rendered preview text (strip code blocks, headings, lists; count remaining)
  • Behavior: static; updates on save
  • Empty state: hidden if estimate <1 minute

Visual layout

Single sticky header bar at top of preview, below the reading progress strip:

████████████████░░░░░░░░░░░░░░░░░  ← progress bar (top edge)
0042-feature-x.md     ✓ approved  validated by 3   AC 12/18 ✓   ~5 min read
─────────────────────────────────────────────────────────────────────────
# Spec: Feature X
...

Path eligibility

Same as #859, #860, #861: only applies to .md files in codev/(plans|specs|reviews)/. Other markdown files get the standard preview unchanged.

Implementation sketch

Files

  • New: packages/vscode/src/markdown-preview/doc-state.jspreviewScripts entry; DOM-scanning + sticky-header rendering
  • New: packages/vscode/src/markdown-preview/doc-state.csspreviewStyles; layout + chip styling + progress bar positioning
  • Optionally new: a markdownItPlugin that emits the parsed frontmatter as a <meta> tag in the rendered HTML so the script doesn't have to re-parse the YAML in the browser. Cleaner separation of concerns; small additional code

Updates rendered on

  • load event (initial render)
  • Scroll (for the progress bar — throttled via requestAnimationFrame)
  • Webview-side message event when extension host signals doc change (markdown preview already has the plumbing for "doc rebuilt"; piggyback on it)

No interactivity in v1

All four surfaces are display-only. Click-handlers are reserved for future expansion (jump-to-first-unchecked-AC, etc.) but not wired in this PR.

Acceptance criteria

Reading progress bar

  • Thin (2–3px) bar fixed at top edge of preview; tracks scroll position 0–100%
  • Uses VS Code theme variable for color (--vscode-progressBar-background or similar)
  • Updates smoothly on scroll; throttled via requestAnimationFrame

Acceptance-criteria progress badge

  • Compact chip in sticky header showing <checked> / <total> count of all <input type="checkbox"> in rendered preview
  • Color hint: green at ≥80%, yellow otherwise (no red, by design — incomplete is the norm)
  • Hidden when the doc has zero checkboxes

Frontmatter status badges

  • Parses the leading --- ... --- YAML block
  • approved: <date> → green chip with date
  • validated: [...] → blue chip with count (tooltip shows full list on hover)
  • Other frontmatter fields rendered as gray info chips (forward-compat — new fields don't break rendering)
  • Hidden entirely when no frontmatter block present

Reading time estimate

  • Estimate based on 225 wpm of body text (code blocks / headings / list markers stripped)
  • Format: ~N min read (singular 1 min read when applicable)
  • Hidden when <1 minute

General

Out of scope (v1)

  • Interactive behaviors (click AC badge to jump to first unchecked; click frontmatter chip to filter; etc.) — pure display in v1, future expansion
  • Per-section AC counts — whole-doc only in v1
  • Custom frontmatter rendering rules (per-field display configuration) — fixed visual; the four known fields are special-cased; everything else is generic
  • Toggle to hide individual surfaces — all-on or all-off via standard markdown-preview extension disable
  • Status bar item variants (showing AC count in VS Code's status bar instead of in-preview) — separate filing if desired; this issue is preview-only
  • Settings to customize wpm / colors — fixed defaults; configuration adds complexity not warranted for v1

Composability

Why this is worth shipping together

Splitting into four issues would create four PRs that all touch package.json contributes.markdown.previewScripts, all reuse the same sticky-header positioning CSS, all need the same eligibility-regex gating. Bundling lands the entire status chrome in one PR — and as a set, the four surfaces tell a complete "what's the state of this doc?" story. Individually they're each useful but smaller wins.

Metadata

Metadata

Assignees

Labels

area/vscodeArea: VS Code extension

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions