Skip to content

feat(markdown): render GitHub-style alerts in the webview (#258)#275

Open
proyectoauraorg wants to merge 1 commit into
Zoo-Code-Org:mainfrom
proyectoauraorg:feat/258-github-markdown-alerts
Open

feat(markdown): render GitHub-style alerts in the webview (#258)#275
proyectoauraorg wants to merge 1 commit into
Zoo-Code-Org:mainfrom
proyectoauraorg:feat/258-github-markdown-alerts

Conversation

@proyectoauraorg
Copy link
Copy Markdown
Contributor

@proyectoauraorg proyectoauraorg commented May 24, 2026

Summary

GitHub-style alerts (> [!NOTE], > [!TIP], > [!IMPORTANT], > [!WARNING], > [!CAUTION]) were rendered as plain blockquotes, losing their semantic meaning and visual priority.

Change

  • A focused custom remark transform (remarkGithubAlerts, no new dependency) walks the mdast, detects a leading alert marker (case-insensitive) in a blockquote's first paragraph, strips the marker, and tags the node with data-alert-type + markdown-alert* classes.
  • A blockquote component customization in MarkdownBlock renders a codicon + label header and per-type accent styling using VS Code theme variables (light/dark/high-contrast friendly).
  • Normal blockquotes and unsupported markers render exactly as before.

Tests

  • markdown.spec.ts: each alert type, case-insensitivity, marker-on-own-line, nested alerts, unsupported markers, mid-text markers, and normal blockquote unchanged.
  • MarkdownBlock.spec.tsx: all five types (class + icon + stripped marker), case-insensitivity, inline markdown inside alerts, normal blockquote unchanged, unsupported-marker fallback.

Closes #258

Summary by CodeRabbit

  • New Features
    • Markdown renderer now supports GitHub-style alert blockquotes with five distinct types: NOTE, TIP, IMPORTANT, WARNING, and CAUTION. Each alert type includes a unique icon indicator and color-coded styling for improved visual hierarchy and clarity in documentation.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 04ab0625-e907-4799-9b0d-bf35d3f41f61

📥 Commits

Reviewing files that changed from the base of the PR and between b761a0a and e5d18b2.

📒 Files selected for processing (4)
  • webview-ui/src/components/common/MarkdownBlock.tsx
  • webview-ui/src/components/common/__tests__/MarkdownBlock.spec.tsx
  • webview-ui/src/utils/__tests__/markdown.spec.ts
  • webview-ui/src/utils/markdown.ts

📝 Walkthrough

Walkthrough

This PR adds GitHub-style alert blockquote support to the Markdown renderer via a new remark plugin and styled component rendering. Alert markers ([!NOTE], [!TIP], [!IMPORTANT], [!WARNING], [!CAUTION]) are detected in blockquotes, stripped from rendered content, and blockquotes are annotated with CSS classes and data attributes. Normal blockquotes remain unchanged.

Changes

GitHub-style Markdown alerts

Layer / File(s) Summary
Alert type definitions and plugin implementation
webview-ui/src/utils/markdown.ts
Alert types (ALERT_TYPES, AlertType) and regex pattern are exported. remarkGithubAlerts() plugin traverses the AST, detects case-insensitive [!TYPE] markers in blockquote first paragraphs, strips marker text, removes now-empty paragraphs, and annotates blockquotes with markdown-alert classes and data-alert-type attributes.
Plugin unit tests
webview-ui/src/utils/__tests__/markdown.spec.ts
AST builder utilities and transform helper added. Test suite covers all five alert types, case-insensitive marker recognition, marker-paragraph removal when no inline content follows, non-alert blockquotes left unchanged, unsupported/mid-text markers rendered as normal blockquotes, and nested alert blockquotes.
Component integration, styling, and wiring
webview-ui/src/components/common/MarkdownBlock.tsx
Alert type imports and icon/label mappings from codicons added. CSS extends StyledMarkdown with .markdown-alert classes, per-type accent colors, and title/icon presentation. Blockquote component override detects data-alert-type and renders alert header (icon + label) or falls back to normal blockquote. Plugin added to remarkPlugins pipeline.
Component end-to-end tests
webview-ui/src/components/common/__tests__/MarkdownBlock.spec.tsx
Tests verify correct data-alert-type values, markdown-alert CSS classes, and icon rendering per alert type. Marker suppression and case-insensitivity confirmed. Inline markdown (bold, code, links) parsed within alert bodies. Normal and unsupported blockquotes render without alert styling or injected headers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit's ears perk up with delight,
For alerts in markdown now shine so bright!
With notes and tips in colors so fine,
Each warning glows with a badge divine.
From GitHub's style to our webview's sight,
The blockquotes transform—a wonderful sight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding GitHub-style alert rendering to the Markdown component in the webview.
Description check ✅ Passed The description covers key implementation details (custom remark transform, component customization, theme support), testing approach, and explicitly closes issue #258, though it deviates from the template structure.
Linked Issues check ✅ Passed All requirements from issue #258 are met: five alert types recognized, distinct rendering implemented, normal blockquotes unchanged, VS Code theme variables used, and no new dependencies added.
Out of Scope Changes check ✅ Passed All code changes directly support the objectives in issue #258; no out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

webview-ui/src/components/common/MarkdownBlock.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

webview-ui/src/components/common/__tests__/MarkdownBlock.spec.tsx

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

webview-ui/src/utils/__tests__/markdown.spec.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

  • 1 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 24, 2026

Codecov Report

❌ Patch coverage is 96.26866% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
webview-ui/src/utils/markdown.ts 89.13% 4 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@edelauna edelauna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice - can you add some screenshots of it working.


// Matches a leading alert marker like "[!NOTE]" (case-insensitive) optionally
// followed by trailing whitespace/newline on the first line of a blockquote.
const ALERT_MARKER_REGEX = /^\[!(note|tip|important|warning|caution)\][^\S\r\n]*\r?\n?/i
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternation group here (note|tip|important|warning|caution) duplicates ALERT_TYPES — adding a new type requires updating both. Could this be derived instead?

Suggested change
const ALERT_MARKER_REGEX = /^\[!(note|tip|important|warning|caution)\][^\S\r\n]*\r?\n?/i
const ALERT_MARKER_REGEX = new RegExp(`^\\[!(${ALERT_TYPES.join("|")})\\][^\\S\\r\\n]*\\r?\\n?`, "i")

* normal blockquotes continue to render exactly as before.
*/
export function remarkGithubAlerts() {
return (tree: any) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@types/mdast is available transitively via remark-gfm, and unist-util-visit v5 is already a dependency. Should the transformer be typed as Plugin<[], Root> with Root from mdast, so callers get compile-time safety when passing this to remarkPlugins?

Comment on lines +55 to +68
function walkAlertBlockquotes(node: any): void {
if (!node || typeof node !== "object") {
return
}

if (node.type === "blockquote") {
annotateAlertBlockquote(node)
}

if (Array.isArray(node.children)) {
for (const child of node.children) {
walkAlertBlockquotes(child)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unist-util-visit is already imported in MarkdownBlock.tsx and listed in package.json. Would visit(tree, "blockquote", annotateAlertBlockquote) work here instead of the hand-rolled walker?

describe("remarkGithubAlerts", () => {
it.each(ALERT_TYPES)("annotates a [!%s] alert blockquote", (type) => {
const upper = type.toUpperCase()
const tree = root(blockquote(paragraph(text(`[!${upper}]\nBody text`))))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does remark actually produce paragraph(text("[!NOTE]\nBody text")) — a single text node with an embedded newline? My understanding is it emits [text("[!NOTE]"), break, text("Body text")] across separate nodes. If so, this tree shape is never produced by the real parser. The integration tests in MarkdownBlock.spec.tsx do cover the real parse path, but it might be worth a quick sanity check here.

Comment on lines +372 to +388
blockquote: ({ children, className, ...props }: any) => {
// The remarkGithubAlerts plugin tags alert blockquotes with a
// `data-alert-type` attribute and `markdown-alert*` classes.
// Anything without that attribute is a normal blockquote and
// must render unchanged.
const alertType = props["data-alert-type"] as AlertType | undefined

if (!alertType || !(alertType in ALERT_ICONS)) {
return (
<blockquote className={className} {...props}>
{children}
</blockquote>
)
}

return (
<blockquote className={className} {...props}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...props spreads all hast-derived attributes onto the DOM element. Today only data-alert-type and className are set by the plugin, but any future hProperty addition would silently reach the DOM. Would it be safer to destructure only the known props and discard the rest?

…rg#258)

GitHub-style alerts ([!NOTE], [!TIP], [!IMPORTANT], [!WARNING], [!CAUTION])
were rendered as plain blockquotes, losing their semantic meaning and visual
priority. Adds a focused remark transform (no new dependency) that detects a
leading alert marker in a blockquote and tags it, plus a blockquote component
that renders a codicon + label header and per-type accent styling using VS Code
theme variables. Normal blockquotes (and unsupported markers) render unchanged.

Closes Zoo-Code-Org#258
@proyectoauraorg proyectoauraorg force-pushed the feat/258-github-markdown-alerts branch from ac40bdc to e5d18b2 Compare May 26, 2026 05:59
@proyectoauraorg
Copy link
Copy Markdown
Contributor Author

Thanks for the review @edelauna! Here are responses to your feedback:

Screenshots: Will add screenshots of the alert blockquote rendering (NOTE, TIP, WARNING, CAUTION variants) — aiming to have those up by EOD.

Code comments:

  1. ALERT_MARKER_REGEX duplication — Good catch. Will derive it from ALERT_TYPES as you suggested so a single source of truth is maintained.

  2. @types/mdast typing — Agreed, will type the transformer as Plugin<[], Root> with Root from mdast for compile-time safety.

  3. Use unist-util-visit — Yes, the hand-rolled walker should be replaced. visit(tree, "blockquote", annotateAlertBlockquote) is cleaner and avoids duplicate traversal logic.

  4. AST shape sanity check — Good eye. Will verify the actual remark output structure and adjust the test fixtures to match real parser output rather than assumed tree shapes.

  5. ...props spread safety — Makes sense. Will destructure only known props (data-alert-type, className) and discard the rest to prevent future hProperty additions from leaking to the DOM.

@proyectoauraorg
Copy link
Copy Markdown
Contributor Author

Conflicts resolved and branch rebased on latest main. CI is passing. Ready for re-review. 🙏

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.

[ENHANCEMENT] Add GitHub-style Markdown alert rendering

2 participants