Created
August 24, 2025 21:53
-
-
Save davidteather/91c0e02120897d4b2b8376a351420474 to your computer and use it in GitHub Desktop.
rehype-inline-svg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function rehypeInlineSvg() { | |
| return (tree) => { | |
| visit(tree, 'element', (node) => { | |
| if (node.tagName === 'code' && node.properties.className && node.properties.className.length > 0 && node.properties.className[0] === 'language-mermaid') { | |
| // We need to look up any elements in the value that are like <img src='/icons/worm.svg' width='25' height='25' /> | |
| // and then directly replace the img with the svg content inline | |
| var mermaidCode = node.children[0].value; | |
| // regex to find all the img tags | |
| const imgRegex = /<img[^>]*\/>/g; | |
| const imgMatches = mermaidCode.match(imgRegex); | |
| if (imgMatches) { | |
| for (const imgMatch of imgMatches) { | |
| const imgNode = unified().use(rehypeParse).parse(imgMatch); | |
| const imgElement = imgNode.children[0].children[1].children[0]; | |
| const src = imgElement.properties.src; | |
| // Check if the file is an SVG if so inline time | |
| if (src.endsWith('.svg')) { | |
| let svgPath; | |
| if (src.startsWith('/')) { | |
| const publicFolder = process.env.PUBLIC_FOLDER_PATH || 'public'; | |
| svgPath = resolve(publicFolder, `.${src}`); | |
| } else { | |
| svgPath = join(process.cwd(), src); | |
| } | |
| try { | |
| var svgContent = readFileSync(svgPath, 'utf-8'); | |
| // cut off anything before the first <svg tag | |
| svgContent = svgContent.substring(svgContent.indexOf('<svg')); | |
| const inlineSvgNode = unified() | |
| .use(rehypeParse, { fragment: true }) | |
| .parse(svgContent); | |
| const svgElement = inlineSvgNode.children[0]; | |
| // Modify each <path> element inside the <svg> | |
| // You might want to modify this to be conditional | |
| visit(svgElement, 'element', (svgNode) => { | |
| if (svgNode.tagName === 'path') { | |
| svgNode.properties.style = svgNode.properties.style || ''; | |
| var fill = svgNode.properties.fill; | |
| svgNode.properties.style += `fill: ${fill || 'inherit'} !important;`; | |
| svgNode.properties.style += `stroke-width: 0 !important;`; | |
| delete svgNode.properties.fill; | |
| } | |
| }); | |
| // Copy relevant properties from the <img> to the <svg> tag | |
| svgElement.properties = svgElement.properties || {}; | |
| if (imgElement.properties.width) { | |
| svgElement.properties.width = imgElement.properties.width; | |
| } | |
| if (imgElement.properties.height) { | |
| svgElement.properties.height = imgElement.properties.height; | |
| } | |
| if (imgElement.properties.style) { | |
| svgElement.properties.style = imgElement.properties.style; | |
| } | |
| if (imgElement.properties.className) { | |
| svgElement.properties.className = imgElement.properties.className; | |
| } | |
| const inlineSvgHtml = unified().use(rehypeStringify).stringify(inlineSvgNode).replaceAll("\n", "").replaceAll("\t", ""); | |
| // Replace with the inline SVG code | |
| mermaidCode = mermaidCode.replace(imgMatch, inlineSvgHtml); | |
| } catch (error) { | |
| console.error(`Failed to inline SVG at ${svgPath}:`, error); | |
| } | |
| } | |
| } | |
| node.children[0].value = mermaidCode; | |
| } | |
| } | |
| }); | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment