diff --git a/astro.config.mjs b/astro.config.mjs index 537e5311e..454d0ff32 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -14,7 +14,7 @@ import rehypeExternalLinks from "rehype-external-links"; import rehypeKatex from "rehype-katex"; import rehypeSlug from "rehype-slug"; import remarkDirective from "remark-directive"; /* Handle directives */ -import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives"; +import { remarkGithubAdmonitions } from "./src/plugins/remark-github-admonitions.js"; import remarkMath from "remark-math"; import remarkSectionize from "remark-sectionize"; import { imageFallbackConfig, siteConfig } from "./src/config.ts"; @@ -122,7 +122,7 @@ export default defineConfig({ remarkMath, remarkReadingTime, remarkExcerpt, - remarkGithubAdmonitionsToDirectives, + remarkGithubAdmonitions, remarkDirective, remarkSectionize, parseDirectiveNode, diff --git a/src/plugins/remark-github-admonitions.js b/src/plugins/remark-github-admonitions.js new file mode 100644 index 000000000..6c680347e --- /dev/null +++ b/src/plugins/remark-github-admonitions.js @@ -0,0 +1,48 @@ +import { visit } from 'unist-util-visit'; + +export function remarkGithubAdmonitions() { + return (tree) => { + visit(tree, 'blockquote', (node, index, parent) => { + const children = node.children; + if (!children || children.length === 0) return; + + const firstChild = children[0]; + if (firstChild.type !== 'paragraph') return; + + const firstTextNode = firstChild.children[0]; + if (!firstTextNode || firstTextNode.type !== 'text') return; + + const text = firstTextNode.value; + // Match [!TYPE] at the start of the text, allowing for optional whitespace + const match = text.match(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]/i); + + if (match) { + const type = match[1].toLowerCase(); + + // Remove the [!TYPE] text + let newFirstTextValue = text.slice(match[0].length); + + // If there's a newline or space immediately after, trim it + if (newFirstTextValue.startsWith('\n') || newFirstTextValue.startsWith(' ')) { + newFirstTextValue = newFirstTextValue.slice(1); + } + + // Update the text node + firstTextNode.value = newFirstTextValue; + + // If the first paragraph becomes empty (just whitespace), remove it + if (newFirstTextValue.trim() === '' && firstChild.children.length === 1) { + node.children.shift(); + } + + // Transform the node to containerDirective + node.type = 'containerDirective'; + node.name = type; + node.attributes = {}; + + // Ensure data exists + node.data = node.data || {}; + } + }); + }; +}