Overview
lpd-mdx-preview is a VS Code extension that renders .mdx and .md files in a side panel with governed Mintlify built-ins, Livepeer custom component renderers, and Mermaid diagrams. It is the primary local authoring preview tool for this repo, but runtime-dependent surfaces still need verification in a Mintlify dev session.
Keybinding: Cmd+Shift+V (Mac) / Ctrl+Shift+V (Windows/Linux)
Location: tools/editor-extensions/lpd-mdx-preview/
Repo Context
Installation
Works in VS Code, Cursor, and Windsurf (all VS Code forks). The same.vsix file installs in all three.
All editors at once (recommended):
~/.vscode, ~/.cursor, ~/.windsurf) and deploys to each.
The installer verifies that the checked-in .vsix matches source before installing. If the package is stale, the install fails and prints the exact rebuild command.
Manual install:
Extensions sidebar → ... menu → Install from VSIX → select tools/editor-extensions/lpd-mdx-preview/lpd-mdx-preview-0.0.2.vsix.
Rebuild after source changes:
install.sh or reinstall manually.
Usage
Open preview
Open preview
.mdx or .md file, then press Cmd+Shift+V (Mac) or Ctrl+Shift+V (Windows/Linux).The preview opens in a side panel and updates automatically as you type (300ms debounce).Theme
Theme
auto mode). You can override this in settings:auto | light | darkFrontmatter display
Frontmatter display
title, pageType, audience, status, purpose, and lastVerified.Mermaid diagrams
Mermaid diagrams
mermaid are rendered using the bundled Mermaid.js with Livepeer theme colours. Diagrams update live as you edit.Component Rendering Tiers
.jsx files) fall into Tier 3 — they render as labelled placeholders with their children content visible. Most Mintlify built-ins and the Livepeer component library render as styled HTML, but runtime-heavy built-ins such as OpenAPI remain approximate.Component Reference
Tier 1 — Mintlify Built-ins
Note / Tip / Warning / Info
Note / Tip / Warning / Info
| Prop | Type | Default | Description |
|---|---|---|---|
| (none) | — | — | Content passed as children |
Callout
Callout
| Prop | Type | Default | Description |
|---|---|---|---|
icon | string | info | Font Awesome icon name (e.g. rocket, star) |
Card
Card
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Card heading |
icon | string | — | Font Awesome icon name |
href | string | — | Link target; wraps card in <a> |
arrow | boolean | false | Appends → to title |
horizontal | boolean | false | Inline flex layout |
CardGroup
CardGroup
<Card> components.| Prop | Type | Default | Description |
|---|---|---|---|
cols | 1 | 2 | 3 | 4 | 2 | Number of grid columns |
Tabs / Tab
Tabs / Tab
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | Tab | Tab label |
icon | string | — | Font Awesome icon name |
Accordion / AccordionGroup
Accordion / AccordionGroup
<details>/<summary> in the preview.| Prop | Type | Default | Description |
|---|---|---|---|
title | string | Details | Summary/header text |
icon | string | — | Font Awesome icon name |
Steps / Step
Steps / Step
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Step heading |
Frame
Frame
Columns
Columns
Expandable
Expandable
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | Show more | Toggle label |
CodeBlock
CodeBlock
<pre><code> in the preview without syntax highlighting.| Prop | Type | Default | Description |
|---|---|---|---|
language | string | — | Language identifier (e.g. bash, json) |
Icon
Icon
| Prop | Type | Default | Description |
|---|---|---|---|
icon | string | — | Font Awesome icon name |
name | string | — | Alias for icon |
Update
Update
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Date or version label |
date | string | — | Alias for label |
ResponseField
ResponseField
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | — | Field name (rendered in accent colour) |
type | string | — | Data type label |
ParamField
ParamField
| Prop | Type | Default | Description |
|---|---|---|---|
path | string | — | Path parameter name |
query | string | — | Query parameter name |
body | string | — | Request-body field name |
header | string | — | Header name |
type | string | — | Data type label |
required | boolean | false | Adds a required marker |
Danger
Danger
Badge
Badge
| Prop | Type | Default | Description |
|---|---|---|---|
color | string | var(--accent) | Accent colour used for border, text, and background tint |
text | string | — | Fallback text when no children are passed |
CodeGroup
CodeGroup
Tree / Tree.Folder / Tree.File
Tree / Tree.Folder / Tree.File
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | folder | Folder label |
defaultOpen | boolean | false | Expands the folder by default |
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | file | File label |
OpenAPI
OpenAPI
| Prop | Type | Default | Description |
|---|---|---|---|
method | string | — | HTTP method label |
path | string | — | API path shown in the placeholder |
openapi | string | — | Alias for path |
StyledTable / TableRow / TableCell
StyledTable / TableRow / TableCell
| Prop | Type | Default | Description |
|---|---|---|---|
header | boolean | false | Renders row with header background |
| Prop | Type | Default | Description |
|---|---|---|---|
header | boolean | false | Renders as <th> with bold weight |
Tier 2 — Livepeer Custom Components
Spacing
CustomDivider
CustomDivider
snippets/components/elements/spacing/Divider.jsx| Prop | Type | Default | Description |
|---|---|---|---|
middleText | string | — | Text centred in the divider |
text | string | — | Alias for middleText |
Spacer
Spacer
| Prop | Type | Default | Description |
|---|---|---|---|
height | string | 24px | CSS height value |
size | string | — | Alias for height |
Divider
Divider
<hr> divider. No props.Containers
CenteredContainer
CenteredContainer
snippets/components/wrappers/containers/Containers.jsx| Prop | Type | Default | Description |
|---|---|---|---|
maxWidth | string | 100% | CSS max-width value |
BorderedBox
BorderedBox
| Prop | Type | Default | Description |
|---|---|---|---|
borderColor | string | var(--border) | CSS border colour |
backgroundColor | string | var(--card-bg) | CSS background colour |
padding | string | 16px | CSS padding |
FullWidthContainer
FullWidthContainer
FlexContainer
FlexContainer
| Prop | Type | Default | Description |
|---|---|---|---|
direction | string | — | CSS flex-direction (row, column) |
gap | string | 12px | CSS gap |
align | string | — | CSS align-items |
justify | string | — | CSS justify-content |
wrap | boolean | false | Enables flex-wrap: wrap |
GridContainer
GridContainer
| Prop | Type | Default | Description |
|---|---|---|---|
columns | string | — | CSS grid-template-columns value |
gap | string | 12px | CSS gap |
ScrollBox
ScrollBox
| Prop | Type | Default | Description |
|---|---|---|---|
maxHeight | string | 400px | CSS max-height value |
Diagrams
ScrollableDiagram
ScrollableDiagram
snippets/components/displays/diagrams/ZoomableDiagram.jsx| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Label shown above the diagram |
maxHeight | string | — | CSS max-height to constrain tall diagrams |
Links
LinkArrow
LinkArrow
→ suffix.Location: snippets/components/elements/links/Links.jsx| Prop | Type | Default | Description |
|---|---|---|---|
href | string | # | Link target |
label | string | — | Link text |
text | string | — | Alias for label |
newline | boolean | true | If false, renders inline (no line break) |
GotoLink
GotoLink
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | # | Link target |
label | string | — | Override link text (otherwise uses children) |
GotoCard
GotoCard
| Prop | Type | Default | Description |
|---|---|---|---|
href | string | # | Link target |
Text & Headings
Subtitle
Subtitle
Quote / FrameQuote
Quote / FrameQuote
FrameQuote adds an outer border frame. No props.H1 / H2 / H3 / H4 / H5 / H6
H1 / H2 / H3 / H4 / H5 / H6
| Prop | Type | Default | Description |
|---|---|---|---|
icon | string | — | Font Awesome icon name shown before heading text |
P
P
CopyText
CopyText
| Prop | Type | Default | Description |
|---|---|---|---|
text | string | — | Text to display as inline code |
value | string | — | Alias for text |
CardTitleTextWithArrow / AccordionTitleWithArrow
CardTitleTextWithArrow / AccordionTitleWithArrow
→ suffix. No props — content as children.PageHeader
PageHeader
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Main heading |
subtitle | string | — | Subtitle below the heading |
Cards
DisplayCard
DisplayCard
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Card heading |
icon | string | — | Font Awesome icon name |
WidthCard
WidthCard
| Prop | Type | Default | Description |
|---|---|---|---|
width | string | 100% | CSS max-width |
maxWidth | string | — | Alias for width |
InlineImageCard
InlineImageCard
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Image source URL |
InteractiveCard
InteractiveCard
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Card heading |
CardCarousel
CardCarousel
Callout Banners
CustomCallout
CustomCallout
| Prop | Type | Default | Description |
|---|---|---|---|
icon | string | ℹ️ | Icon character or emoji |
TipWithArrow
TipWithArrow
💡 icon. No props — content as children.ComingSoonCallout / PreviewCallout / ReviewCallout
ComingSoonCallout / PreviewCallout / ReviewCallout
Media
Image
Image
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Image URL |
alt | string | — | Alt text |
caption | string | — | Caption displayed below image |
LinkImage
LinkImage
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Image URL |
href | string | # | Link target |
alt | string | — | Alt text |
YouTubeVideo
YouTubeVideo
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | YouTube video ID |
videoId | string | — | Alias for id |
TitledVideo
TitledVideo
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Heading displayed above the media |
Steps
StyledSteps / StyledStep
StyledSteps / StyledStep
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Step heading |
ListSteps
ListSteps
StyledSteps. Same rendering, same props.Grids & Layouts
QuadGrid
QuadGrid
AccordionLayout / AccordionGroupList
AccordionLayout / AccordionGroupList
Tables
DynamicTable
DynamicTable
SearchTable
SearchTable
useState). Renders as a static mock in the preview: non-functional search bar + category dropdown chrome + full table body. An ⚡ interactive — static in preview badge is shown to set expectations.| Prop | Type | Default | Purpose |
|---|---|---|---|
searchPlaceholder | string | Search… | Placeholder text in the search input |
categoryLabel | string | All categories | Label for the category dropdown |
searchColumns | array | — | Columns to include in search (passed to SearchTable.jsx) |
Hero & Portal Scaffolding
HeroSectionContainer / HeroContentContainer / PortalHeroContent / PortalContentContainer
HeroSectionContainer / HeroContentContainer / PortalHeroContent / PortalContentContainer
Icons & Indicators
LivepeerIcon
LivepeerIcon
BlinkingIcon
BlinkingIcon
| Prop | Type | Default | Description |
|---|---|---|---|
icon | string | terminal | Font Awesome icon name |
DownloadButton
DownloadButton
Embeds & Social
MarkdownEmbed
MarkdownEmbed
ExternalContent
ExternalContent
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | External Content | Header label |
SocialLinks
SocialLinks
Math
MathInline / MathBlock
MathInline / MathBlock
<code> in preview (not LaTeX-rendered).| Prop | Type | Default | Description |
|---|---|---|---|
expression | string | — | Mathematical expression string |
math | string | — | Alias for expression |
Tier 3 — Placeholder Rendering
Any component not in Tier 1 or Tier 2 renders as:lib/component-map.js under the livepeerComponents object.
Interactive components
Some Tier 2 components use React hooks (useState, useEffect) and are fully interactive in deployed Mintlify but cannot run in the VS Code webview (Node.js environment, no React runtime). These render as static mocks — they show the correct UI chrome but do not respond to input.
Currently affected: SearchTable, SocialLinks, MarkdownEmbed, and OpenAPI.
These components display an ⚡ interactive — static in preview badge so authors know to verify their behaviour in a Mintlify dev session, not just the local preview.
Data-feed integrators (ShowcaseCards, CoinGeckoExchanges, LumaEvents, DiscordAnnouncements, TwitterTimeline) fall to Tier 3 placeholders for the same reason — they fetch live data and cannot be meaningfully mocked offline.
Configuration
| Setting | Type | Default | Options | Description |
|---|---|---|---|---|
livepeer.mdxPreview.theme | string | auto | auto | light | dark | Preview colour theme. auto matches VS Code. |
Architecture
extension.js — Entry point
extension.js — Entry point
livepeer.openMdxPreview, livepeer.openMdxPreviewToSide), the Cmd+Shift+V keybinding, and two event listeners (document change → debounced re-render; theme change → full re-render). Manages a Map of open panels keyed by document URI.lib/mdx-parser.js — Segment parser
lib/mdx-parser.js — Segment parser
frontmatter, import, markdown, mermaid, codeblock, jsx, jsx-expression. Regex-based extraction — not a full MDX compiler, for robustness with non-standard MDX.lib/mintlify-components.js — Tier 1 renderers
lib/mintlify-components.js — Tier 1 renderers
Tree.Folder / Tree.File rendering and descriptive placeholders where full runtime parity is not practical in the preview. Each function signature: (props, childrenHtml) => htmlString.lib/component-map.js — Tier 2 renderers + dispatch
lib/component-map.js — Tier 2 renderers + dispatch
COMPONENT_MAP. Exports renderSegments() which dispatches each segment to its renderer or falls through to renderPlaceholder().lib/webview-template.js — HTML shell
lib/webview-template.js — HTML shell
fa 6.5.1), local CSS/JS vscode-resource: URIs, and the rendered body.media/preview.js — Client-side logic
media/preview.js — Client-side logic
.lpd-md-raw blocks with markdown-it, and handles tab switching interactions.media/preview.css — Theme & component styles
media/preview.css — Theme & component styles
style.css. Styles for all Tier 1 and Tier 2 component classes.Future Features
Lazy-load Mermaid.js ✓ Implemented
Lazy-load Mermaid.js ✓ Implemented
renderSegments() returns { html, hasMermaid }. The webview template conditionally injects <script src="${mermaidUri}"> only when hasMermaid is true. Pages without Mermaid diagrams skip the 2.45 MB bundle entirely.Promote Tier 3 components on demand
Promote Tier 3 components on demand
lib/component-map.js under livepeerComponents. The function signature is (props, childrenHtml) => htmlString.Priority candidates based on usage frequency in the repo:Snippet(used in composable page patterns)- data-feed integrators that could be represented by stable static mocks
- additional low-use repo components that currently fall through to generic placeholders
Syntax highlighting for code blocks
Syntax highlighting for code blocks
<pre><code> without syntax colouring. Adding highlight.js (vendored, ~50 KB minified) as a third media asset and calling hljs.highlightAll() in preview.js would add language-aware colouring for all fenced blocks.Live scroll sync
Live scroll sync
editor/scroll messages via the webview messaging API. The same pattern can be applied here: on onDidChangeTextEditorVisibleRanges, post a message to the webview to scroll to the corresponding rendered element.Custom component hot-reload ✓ Implemented
Custom component hot-reload ✓ Implemented
onDidSaveTextDocument watches for any .jsx save in the workspace and re-renders all open preview panels. Component source changes are reflected immediately without touching the .mdx file.Collapsible JSX comment blocks ✓ Implemented (v0.0.2)
Collapsible JSX comment blocks ✓ Implemented (v0.0.2)
{/* ... */} comment blocks — typically template instructions or reviewer flags — are rendered as collapsed <details> elements instead of leaking into the preview as visible text. Single-line {/* ... */} comments are still silently stripped. The collapsible uses a dashed border and muted palette to distinguish it from content.Parser: lib/mdx-parser.js detects {/* without a same-line */} and collects lines until the closing */}, emitting a jsx-comment segment.Renderer: lib/component-map.js handles jsx-comment as <details class="lpd-comment"> with a 💬 comment summary and pre-formatted body.