(feat): added mermaid rendering support in markdown (#676)

This commit is contained in:
Thomas Durieux
2026-04-15 09:56:35 +02:00
committed by GitHub
parent 85f05cd698
commit 2621dfd7fc
9 changed files with 5657 additions and 3 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+84
View File
@@ -0,0 +1,84 @@
/* Mermaid diagram styles */
.mermaid {
text-align: center;
margin: 1em 0;
overflow: auto;
}
/* Ensure diagrams are responsive */
.mermaid svg {
max-width: 100%;
height: auto;
}
/* Dark mode support for Mermaid diagrams */
.dark-mode .mermaid {
filter: invert(1) hue-rotate(180deg);
}
.dark-mode .mermaid svg {
background: transparent;
}
/* Ensure text remains readable in dark mode */
.dark-mode .mermaid .nodeLabel,
.dark-mode .mermaid .edgeLabel {
filter: invert(1) hue-rotate(180deg);
}
/* Custom styling for different diagram types */
.mermaid .node rect,
.mermaid .node circle,
.mermaid .node ellipse,
.mermaid .node polygon {
stroke-width: 2px;
}
/* Flowchart specific styles */
.mermaid .flowchart-link {
stroke-width: 2px;
}
/* Sequence diagram specific styles */
.mermaid .actor {
fill: #f9f9f9;
stroke: #333;
stroke-width: 2px;
}
.mermaid .messageLine0,
.mermaid .messageLine1 {
stroke: #333;
stroke-width: 1.5px;
}
/* Gantt chart specific styles */
.mermaid .section0,
.mermaid .section1,
.mermaid .section2,
.mermaid .section3 {
opacity: 0.8;
}
/* Pie chart specific styles */
.mermaid .pieChart .slice {
opacity: 0.9;
}
/* Make sure diagrams are visible in the markdown content area */
.markdown-body .mermaid {
background: transparent;
border: none;
padding: 10px;
}
/* Error handling for failed diagrams */
.mermaid .error {
color: #d32f2f;
font-family: monospace;
font-size: 12px;
padding: 10px;
border: 1px solid #d32f2f;
border-radius: 4px;
background-color: #ffebee;
}
+2617 -2
View File
File diff suppressed because one or more lines are too long
+70
View File
@@ -0,0 +1,70 @@
// Marked.js extension for Mermaid diagrams
function markedMermaid(options) {
options = options || {};
return {
extensions: [
{
name: 'mermaid',
level: 'block',
start(src) {
return src.match(/^```mermaid/m)?.index;
},
tokenizer(src, tokens) {
const rule = /^```mermaid\n([\s\S]*?)\n```/;
const match = rule.exec(src);
if (match) {
return {
type: 'mermaid',
raw: match[0],
text: match[1].trim()
};
}
},
renderer(token) {
const id = 'mermaid-' + Math.random().toString(36).substr(2, 9);
// Initialize Mermaid if not already done
if (typeof mermaid !== 'undefined' && !window.mermaidInitialized) {
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
window.mermaidInitialized = true;
}
// Create a div that will be processed by Mermaid
const div = `<div class="mermaid" id="${id}">${token.text}</div>`;
// Schedule Mermaid rendering for after DOM insertion
setTimeout(() => {
if (typeof mermaid !== 'undefined') {
try {
const element = document.getElementById(id);
if (element && !element.getAttribute('data-processed')) {
mermaid.init(undefined, element);
element.setAttribute('data-processed', 'true');
}
} catch (error) {
console.error('Mermaid rendering error:', error);
}
}
}, 0);
return div;
}
}
]
};
}
// Make it available globally
if (typeof window !== 'undefined') {
window.markedMermaid = markedMermaid;
}
// CommonJS/Node.js export
if (typeof module !== 'undefined' && module.exports) {
module.exports = markedMermaid;
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -182,5 +182,6 @@ function renderMD(md, baseUrlValue) {
throwOnError: false,
})
);
marked.use(markedMermaid());
return DOMPurify.sanitize(marked.parse(md, { renderer }));
}