mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-06-05 15:18:11 +02:00
(feat): added mermaid rendering support in markdown (#676)
This commit is contained in:
@@ -22,6 +22,8 @@ function defaultTask(cb) {
|
|||||||
"public/script/external/katex.min.js",
|
"public/script/external/katex.min.js",
|
||||||
"public/script/external/katex-auto-render.min.js",
|
"public/script/external/katex-auto-render.min.js",
|
||||||
"public/script/external/marked-katex-extension.umd.min.js",
|
"public/script/external/marked-katex-extension.umd.min.js",
|
||||||
|
"public/script/external/mermaid.min.js",
|
||||||
|
"public/script/external/marked-mermaid.js",
|
||||||
"public/script/external/notebook.min.js",
|
"public/script/external/notebook.min.js",
|
||||||
"public/script/external/org.js",
|
"public/script/external/org.js",
|
||||||
"public/script/external/jquery-3.4.1.min.js",
|
"public/script/external/jquery-3.4.1.min.js",
|
||||||
@@ -39,6 +41,7 @@ function defaultTask(cb) {
|
|||||||
"public/css/font-awesome.min.css",
|
"public/css/font-awesome.min.css",
|
||||||
"public/css/notebook.css",
|
"public/css/notebook.css",
|
||||||
"public/css/katex.min.css",
|
"public/css/katex.min.css",
|
||||||
|
"public/css/mermaid.css",
|
||||||
"public/css/github-markdown.min.css",
|
"public/css/github-markdown.min.css",
|
||||||
"public/css/style.css",
|
"public/css/style.css",
|
||||||
];
|
];
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -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;
|
||||||
|
}
|
||||||
Vendored
+2617
-2
File diff suppressed because one or more lines are too long
+70
@@ -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;
|
||||||
|
}
|
||||||
+2659
File diff suppressed because one or more lines are too long
@@ -182,5 +182,6 @@ function renderMD(md, baseUrlValue) {
|
|||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
marked.use(markedMermaid());
|
||||||
return DOMPurify.sanitize(marked.parse(md, { renderer }));
|
return DOMPurify.sanitize(marked.parse(md, { renderer }));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Mermaid Test - Anonymous GitHub</title>
|
||||||
|
<!-- Include CSS from the built bundle -->
|
||||||
|
<link rel="stylesheet" href="public/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="public/css/github-markdown.min.css">
|
||||||
|
<link rel="stylesheet" href="public/css/mermaid.css">
|
||||||
|
<link rel="stylesheet" href="public/css/style.css">
|
||||||
|
<style>
|
||||||
|
body { padding: 20px; }
|
||||||
|
.test-section {
|
||||||
|
margin: 30px 0;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.markdown-body { max-width: 100%; }
|
||||||
|
.status {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.success { background-color: #d4edda; color: #155724; }
|
||||||
|
.error { background-color: #f8d7da; color: #721c24; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Mermaid Support Test</h1>
|
||||||
|
|
||||||
|
<div class="status" id="status">
|
||||||
|
<strong>Status:</strong> <span id="statusText">Loading...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Test markdown content -->
|
||||||
|
<div class="test-section">
|
||||||
|
<h2>Test Input (Markdown)</h2>
|
||||||
|
<pre id="markdownInput"># Test Document
|
||||||
|
|
||||||
|
## Simple Flowchart
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Start] --> B{Test Working?}
|
||||||
|
B -->|Yes| C[✅ Success!]
|
||||||
|
B -->|No| D[❌ Failed]
|
||||||
|
D --> E[Check Console]
|
||||||
|
C --> F[Mermaid Renders!]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sequence Diagram
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant User
|
||||||
|
participant App
|
||||||
|
participant Mermaid
|
||||||
|
|
||||||
|
User->>App: Load page
|
||||||
|
App->>Mermaid: Render diagram
|
||||||
|
Mermaid-->>App: SVG output
|
||||||
|
App-->>User: Display diagram
|
||||||
|
```</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h2>Rendered Output</h2>
|
||||||
|
<div class="markdown-body" id="renderedOutput">
|
||||||
|
<!-- Rendered content will appear here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h2>Console Output</h2>
|
||||||
|
<pre id="consoleOutput" style="background: #f8f9fa; padding: 10px; max-height: 200px; overflow-y: auto;"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Include JavaScript libraries in correct order -->
|
||||||
|
<script src="public/script/external/jquery-3.4.1.min.js"></script>
|
||||||
|
<script src="public/script/external/github-emojis.js"></script>
|
||||||
|
<script src="public/script/external/marked-emoji.js"></script>
|
||||||
|
<script src="public/script/external/marked.min.js"></script>
|
||||||
|
<script src="public/script/external/katex.min.js"></script>
|
||||||
|
<script src="public/script/external/marked-katex-extension.umd.min.js"></script>
|
||||||
|
<script src="public/script/external/mermaid.min.js"></script>
|
||||||
|
<script src="public/script/external/marked-mermaid.js"></script>
|
||||||
|
<script src="public/script/utils.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Capture console logs
|
||||||
|
const originalLog = console.log;
|
||||||
|
const originalError = console.error;
|
||||||
|
const consoleOutput = document.getElementById('consoleOutput');
|
||||||
|
|
||||||
|
function addToConsole(type, message) {
|
||||||
|
consoleOutput.textContent += `[${type.toUpperCase()}] ${message}\n`;
|
||||||
|
consoleOutput.scrollTop = consoleOutput.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log = function(...args) {
|
||||||
|
originalLog.apply(console, args);
|
||||||
|
addToConsole('log', args.join(' '));
|
||||||
|
};
|
||||||
|
|
||||||
|
console.error = function(...args) {
|
||||||
|
originalError.apply(console, args);
|
||||||
|
addToConsole('error', args.join(' '));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test the Mermaid integration
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const statusText = document.getElementById('statusText');
|
||||||
|
const status = document.getElementById('status');
|
||||||
|
const markdownInput = document.getElementById('markdownInput').textContent;
|
||||||
|
const renderedOutput = document.getElementById('renderedOutput');
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('Starting Mermaid test...');
|
||||||
|
|
||||||
|
// Check if required functions are available
|
||||||
|
if (typeof marked === 'undefined') {
|
||||||
|
throw new Error('marked.js not loaded');
|
||||||
|
}
|
||||||
|
if (typeof mermaid === 'undefined') {
|
||||||
|
throw new Error('mermaid.js not loaded');
|
||||||
|
}
|
||||||
|
if (typeof markedMermaid === 'undefined') {
|
||||||
|
throw new Error('marked-mermaid.js not loaded');
|
||||||
|
}
|
||||||
|
if (typeof renderMD === 'undefined') {
|
||||||
|
throw new Error('renderMD function not loaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('All required libraries loaded');
|
||||||
|
|
||||||
|
// Test the rendering
|
||||||
|
const rendered = renderMD(markdownInput);
|
||||||
|
renderedOutput.innerHTML = rendered;
|
||||||
|
|
||||||
|
console.log('Markdown processed, checking for Mermaid elements...');
|
||||||
|
|
||||||
|
// Check if mermaid elements were created
|
||||||
|
const mermaidElements = renderedOutput.querySelectorAll('.mermaid');
|
||||||
|
console.log(`Found ${mermaidElements.length} mermaid elements`);
|
||||||
|
|
||||||
|
if (mermaidElements.length > 0) {
|
||||||
|
statusText.textContent = `SUCCESS! Found ${mermaidElements.length} Mermaid diagram(s)`;
|
||||||
|
status.className = 'status success';
|
||||||
|
|
||||||
|
// Wait a bit for diagrams to render
|
||||||
|
setTimeout(() => {
|
||||||
|
mermaidElements.forEach((el, index) => {
|
||||||
|
const svg = el.querySelector('svg');
|
||||||
|
if (svg) {
|
||||||
|
console.log(`Diagram ${index + 1}: Successfully rendered as SVG`);
|
||||||
|
} else {
|
||||||
|
console.log(`Diagram ${index + 1}: Still rendering or failed`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
statusText.textContent = '❌ FAILED: No Mermaid elements found in rendered output';
|
||||||
|
status.className = 'status error';
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Test failed:', error.message);
|
||||||
|
statusText.textContent = `❌ ERROR: ${error.message}`;
|
||||||
|
status.className = 'status error';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Mermaid Test File
|
||||||
|
|
||||||
|
## Simple Flowchart
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Start] --> B{Is it working?}
|
||||||
|
B -->|Yes| C[🎉 Success!]
|
||||||
|
B -->|No| D[Check console]
|
||||||
|
D --> B
|
||||||
|
C --> E[End]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sequence Diagram
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant U as User
|
||||||
|
participant A as App
|
||||||
|
participant G as GitHub
|
||||||
|
|
||||||
|
U->>A: Upload repo
|
||||||
|
A->>G: Fetch data
|
||||||
|
G-->>A: Repository content
|
||||||
|
A->>A: Anonymize
|
||||||
|
A-->>U: Show result
|
||||||
|
```
|
||||||
|
|
||||||
|
## Simple Pie Chart
|
||||||
|
```mermaid
|
||||||
|
pie title Test Languages
|
||||||
|
"JavaScript" : 50
|
||||||
|
"CSS" : 30
|
||||||
|
"HTML" : 20
|
||||||
|
```
|
||||||
|
|
||||||
|
## State Diagram
|
||||||
|
```mermaid
|
||||||
|
stateDiagram-v2
|
||||||
|
[*] --> Idle
|
||||||
|
Idle --> Processing
|
||||||
|
Processing --> Complete
|
||||||
|
Complete --> [*]
|
||||||
|
Processing --> Error
|
||||||
|
Error --> [*]
|
||||||
|
```
|
||||||
|
|
||||||
|
If you can see the diagrams above rendered as interactive graphics (not as code blocks), then Mermaid is working correctly!
|
||||||
Reference in New Issue
Block a user