Skip to content

YAML front-matter handling, default theme option, and code block UI enhancement#20

Open
Al3cLee wants to merge 3 commits into
selimacerbas:mainfrom
Al3cLee:main
Open

YAML front-matter handling, default theme option, and code block UI enhancement#20
Al3cLee wants to merge 3 commits into
selimacerbas:mainfrom
Al3cLee:main

Conversation

@Al3cLee
Copy link
Copy Markdown

@Al3cLee Al3cLee commented May 2, 2026

Summary

I identified some UI related small issues and fixed them with Claude:

Three independent improvements to the browser preview, all confined to assets/index.html and lua/markdown_preview/init.lua. No server logic was changed.

These have been all tested on Neovim v0.12.2.

1. YAML front-matter collapsible panel (hide_yaml)

YAML front-matter was previously shown as ordinary contents the preview. It is now displayed as a collapsible <details> panel at the top of the page, above the document content, below the "markdown preview" UI banner.

Behaviour:

  • The panel is collapsed by default. Click the ▶ Front matter label to expand it and see the raw YAML in a code block.
  • If the file has no front-matter, the panel is hidden entirely.
  • Open/closed state is preserved across live reloads (editing the file does not collapse the panel).
  • Set hide_yaml = true in setup() to suppress the panel entirely; you will not even see the collapsible panel.

Configuration:

require("markdown_preview").setup({
    hide_yaml = true,  -- default: false
})

Implementation note: markdown-it-front-matter on jsDelivr only ships a CommonJS build with no UMD/global wrapper, so the existing <script> CDN tag silently did nothing (window.markdownItFrontMatter was always undefined). The plugin was replaced with an equivalent block rule inlined directly inside the ES module script.

2. Configurable default theme (default_theme)

The browser preview previously always opened in dark mode (hardcoded). The initial theme is now configurable.

Configuration:

require("markdown_preview").setup({
    default_theme = "light",  -- "dark" (default) or "light"
})

The value is injected into index.html at server start via the same placeholder substitution pattern used for bottom_padding. The in-browser theme toggle button continues to work regardless of the configured default.

3. Sticky lang badge and copy button on wide code blocks

When a code block's content was wider than the viewport and the user scrolled it horizontally, the language badge and copy button scrolled off with the content. They now stay fixed at the top-right corner of the visible block.

Root cause: <pre> had both position: relative and overflow-x: auto. Absolutely-positioned children are anchored to the element's scrollable content area, not its visible viewport.

Fix: Each <pre> is now wrapped in a <div class="code-wrap"> that carries position: relative. The <pre> itself retains only overflow-x: auto. The badge and copy button are children of the wrapper, so they are always anchored to the visible corner of the block regardless of horizontal scroll position.

The ::before pseudo-element lang badge (which cannot be independently re-parented) was replaced with a real <span class="code-lang"> DOM element injected by the existing attachCopyButtons() function.

Files changed

File Changes
lua/markdown_preview/init.lua Added default_theme and hide_yaml config keys; two new placeholder substitutions in write_index
assets/index.html Front-matter panel HTML + CSS + inlined plugin; __DEFAULT_THEME__ / __HIDE_YAML__ placeholders; .code-wrap wrapper CSS + JS refactor of attachCopyButtons

Al3cLee added 3 commits May 2, 2026 15:45
- default_theme ("dark"|"light"): controls the initial theme the browser
  preview loads with, replacing the previously hardcoded dark mode.
  The value is injected into index.html at server start via the existing
  __BOTTOM_PADDING__ substitution pattern.

- hide_yaml (bool, default false): when false, YAML front-matter is
  displayed in a collapsible <details> panel at the top of the preview
  (above the document content). The panel shows the raw YAML in a styled
  code block and preserves its open/closed state across live reloads.
  Set to true to suppress the panel entirely.

Both options are wired through setup() and require no server changes.
The markdown-it-front-matter package on jsDelivr only ships a CommonJS
build (module.exports = ...) with no UMD wrapper, so loading it via
<script> tag never exposes window.markdownItFrontMatter. The plugin
registration guard was always false, lastFrontMatter was never set,
and the panel never appeared.

Fix: remove the broken <script> CDN tag and inline an equivalent
front-matter block rule directly inside the ES module script. The
inlined rule correctly extracts the YAML between --- delimiters and
sets lastFrontMatter synchronously during md.render(), which sync()
reads immediately after to show/hide the panel.

Also reset lastFrontMatter to null before each md.render() so that
removing front-matter from a file correctly hides the panel.
The lang badge and copy button were positioned absolute inside <pre>,
which has overflow-x: auto. This made them scroll horizontally with
the code content instead of staying fixed at the top-right corner.

Fix: wrap each <pre> in a <div class="code-wrap"> that holds
position: relative. The <pre> itself only keeps overflow-x: auto.
Badge and button are absolute children of the wrapper, so they are
anchored to the visible viewport of the block regardless of horizontal
scroll position.

The ::before pseudo-element lang badge (which cannot be independently
positioned relative to a parent) is replaced with a real <span
class="code-lang"> DOM element injected by attachCopyButtons().
All copy-button CSS selectors are re-scoped from pre to .code-wrap.
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