feat(markdown): render GitHub-style alerts in the webview (#258)#275
feat(markdown): render GitHub-style alerts in the webview (#258)#275proyectoauraorg wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR adds GitHub-style alert blockquote support to the Markdown renderer via a new remark plugin and styled component rendering. Alert markers ( ChangesGitHub-style Markdown alerts
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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
webview-ui/src/components/common/MarkdownBlock.tsxESLint 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.tsxESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox. webview-ui/src/utils/__tests__/markdown.spec.tsESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.
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. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
edelauna
left a comment
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
The alternation group here (note|tip|important|warning|caution) duplicates ALERT_TYPES — adding a new type requires updating both. Could this be derived instead?
| 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) => { |
There was a problem hiding this comment.
@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?
| 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) | ||
| } | ||
| } |
There was a problem hiding this comment.
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`)))) |
There was a problem hiding this comment.
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.
| 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}> |
There was a problem hiding this comment.
...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
ac40bdc to
e5d18b2
Compare
|
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:
|
|
Conflicts resolved and branch rebased on latest main. CI is passing. Ready for re-review. 🙏 |
Summary
GitHub-style alerts (
> [!NOTE],> [!TIP],> [!IMPORTANT],> [!WARNING],> [!CAUTION]) were rendered as plain blockquotes, losing their semantic meaning and visual priority.Change
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 withdata-alert-type+markdown-alert*classes.blockquotecomponent customization inMarkdownBlockrenders a codicon + label header and per-type accent styling using VS Code theme variables (light/dark/high-contrast friendly).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