Skip to content

fix: render YAML frontmatter as a metadata card in markdown preview - #391

Open
RizzoTho wants to merge 1 commit into
agegr:mainfrom
RizzoTho:fix/markdown-yaml-frontmatter-preview
Open

fix: render YAML frontmatter as a metadata card in markdown preview#391
RizzoTho wants to merge 1 commit into
agegr:mainfrom
RizzoTho:fix/markdown-yaml-frontmatter-preview

Conversation

@RizzoTho

@RizzoTho RizzoTho commented Aug 5, 2026

Copy link
Copy Markdown

Summary

The markdown file preview (and chat messages) render YAML frontmatter as broken CommonMark: the opening --- becomes an <hr>, and the closing --- is read as a setext heading underline, so the raw YAML (title: My Doc, …) shows up as a giant bold heading between two horizontal rules in the preview.

Change

  • lib/markdown.ts — added remark-frontmatter (yaml only) to both render pipelines. The block now parses as a yaml node and is dropped during mdast→hast conversion, so raw metadata never leaks into chat or preview output (this also stops remark-math from interpreting $ inside the metadata).
  • lib/markdown.ts — new parseFrontmatter() helper: a leading---- regex that mirrors what remark-frontmatter(["yaml"]) recognizes, plus a js-yaml parse.
  • components/FrontmatterCard.tsx (new) — renders the metadata as a card above the preview body: title as a heading, tags/categories/keywords as chips, remaining keys as a key/value table with http(s)/mailto values as links.
  • components/FileViewer.tsx — renders the card in preview mode.
  • app/globals.css — card styles built on existing CSS variables (light/dark aware).

Behavior:

  • Malformed YAML → no card, but the block is still hidden by the remark plugin (no heading/<hr> leak).
  • Documents without frontmatter → rendered exactly as before.
  • Chat messages containing a frontmatter block → hidden silently (no card there; the card is preview-only).

Verification

  • tsc --noEmit clean
  • eslint clean
  • Unified pipeline checked directly: ---\ntitle: …\n--- now yields a yaml node that produces zero output; the setext-trap case and --- appearing mid-document still parse as CommonMark (verified with a matrix of 5 cases)
  • Manual: opened a .md file with frontmatter in the file preview (title + tags + key/value rows render as a card), and a file without frontmatter (unchanged)

react-markdown has no frontmatter support, so a leading `---` block was
parsed as CommonMark instead: the opening `---` became an <hr> and the
closing `---` turned the YAML lines into a setext heading, leaking raw
metadata like `title: My Doc` into the rendered preview between two
horizontal rules (and letting remark-math mangle any $ inside it).

- Add remark-frontmatter (yaml only) to both render pipelines so the
  block parses as a `yaml` node and disappears from the rendered output.
- Add parseFrontmatter() (lib/markdown.ts) backed by js-yaml, and a
  FrontmatterCard that renders the metadata above the preview body:
  `title` as a heading, `tags`/`categories`/`keywords` as chips, remaining
  keys as a key/value table with http(s)/mailto values as links.
- Malformed YAML shows no card but is still hidden by the remark plugin;
  documents without frontmatter render exactly as before.

Verified with tsc --noEmit and eslint; the parse pipeline was also
checked with unified directly (frontmatter yields no output, and the
setext-trap / mid-document `---` cases still parse as CommonMark).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant