Skip to content

Commit 4298ccc

Browse files
author
Mujahed Altahleh
committed
Add Mermaid.js configuration and styling for improved diagram rendering and theme support
1 parent 4829291 commit 4298ccc

3 files changed

Lines changed: 198 additions & 3 deletions

File tree

docs/javascripts/mermaid.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Mermaid configuration for faster loading and better rendering
2+
document.addEventListener("DOMContentLoaded", function() {
3+
// Configure Mermaid to prevent FOUC (Flash of Unstyled Content)
4+
if (typeof mermaid !== 'undefined') {
5+
mermaid.initialize({
6+
startOnLoad: false,
7+
theme: 'default',
8+
themeVariables: {
9+
primaryColor: '#2196F3',
10+
primaryTextColor: '#fff',
11+
primaryBorderColor: '#1976D2',
12+
lineColor: '#757575',
13+
secondaryColor: '#E3F2FD',
14+
tertiaryColor: '#f5f5f5'
15+
},
16+
flowchart: {
17+
useMaxWidth: true,
18+
htmlLabels: true,
19+
curve: 'basis'
20+
},
21+
sequence: {
22+
diagramMarginX: 50,
23+
diagramMarginY: 10,
24+
actorMargin: 50,
25+
width: 150,
26+
height: 65,
27+
boxMargin: 10,
28+
boxTextMargin: 5,
29+
noteMargin: 10,
30+
messageMargin: 35,
31+
mirrorActors: true,
32+
bottomMarginAdj: 1,
33+
useMaxWidth: true
34+
},
35+
gitgraph: {
36+
mainBranchName: 'main',
37+
showCommitLabel: true,
38+
showBranches: true,
39+
rotateCommitLabel: true
40+
}
41+
});
42+
43+
// Wait for the page to be fully loaded before rendering
44+
const renderMermaidDiagrams = () => {
45+
const diagrams = document.querySelectorAll('.mermaid');
46+
diagrams.forEach((diagram, index) => {
47+
if (!diagram.hasAttribute('data-processed')) {
48+
// Hide the diagram initially to prevent FOUC
49+
diagram.style.visibility = 'hidden';
50+
diagram.style.opacity = '0';
51+
52+
// Process the diagram
53+
mermaid.init(undefined, diagram).then(() => {
54+
// Show the diagram after processing
55+
diagram.style.transition = 'opacity 0.3s ease-in-out';
56+
diagram.style.visibility = 'visible';
57+
diagram.style.opacity = '1';
58+
}).catch((error) => {
59+
console.error('Mermaid rendering error:', error);
60+
// Show the original text if rendering fails
61+
diagram.style.visibility = 'visible';
62+
diagram.style.opacity = '1';
63+
});
64+
}
65+
});
66+
};
67+
68+
// Render diagrams when page loads
69+
renderMermaidDiagrams();
70+
71+
// Re-render diagrams when navigating (for SPA-like behavior)
72+
const observer = new MutationObserver((mutations) => {
73+
mutations.forEach((mutation) => {
74+
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
75+
// Check if new mermaid diagrams were added
76+
const hasMermaid = Array.from(mutation.addedNodes).some(node =>
77+
node.nodeType === Node.ELEMENT_NODE &&
78+
(node.classList.contains('mermaid') || node.querySelector('.mermaid'))
79+
);
80+
if (hasMermaid) {
81+
setTimeout(renderMermaidDiagrams, 100);
82+
}
83+
}
84+
});
85+
});
86+
87+
observer.observe(document.body, {
88+
childList: true,
89+
subtree: true
90+
});
91+
}
92+
});
93+
94+
// Theme switching support for Mermaid
95+
document.addEventListener('DOMContentLoaded', function() {
96+
const themeToggleButtons = document.querySelectorAll('[data-md-color-scheme]');
97+
98+
themeToggleButtons.forEach(button => {
99+
button.addEventListener('click', function() {
100+
setTimeout(() => {
101+
const isDark = document.body.getAttribute('data-md-color-scheme') === 'slate';
102+
if (typeof mermaid !== 'undefined') {
103+
mermaid.initialize({
104+
theme: isDark ? 'dark' : 'default',
105+
themeVariables: isDark ? {
106+
primaryColor: '#BB86FC',
107+
primaryTextColor: '#000',
108+
primaryBorderColor: '#3700B3',
109+
lineColor: '#CF6679',
110+
secondaryColor: '#03DAC6',
111+
tertiaryColor: '#121212'
112+
} : {
113+
primaryColor: '#2196F3',
114+
primaryTextColor: '#fff',
115+
primaryBorderColor: '#1976D2',
116+
lineColor: '#757575',
117+
secondaryColor: '#E3F2FD',
118+
tertiaryColor: '#f5f5f5'
119+
}
120+
});
121+
122+
// Re-render all diagrams with new theme
123+
const diagrams = document.querySelectorAll('.mermaid[data-processed="true"]');
124+
diagrams.forEach(diagram => {
125+
diagram.removeAttribute('data-processed');
126+
const originalContent = diagram.getAttribute('data-original') || diagram.textContent;
127+
diagram.innerHTML = originalContent;
128+
mermaid.init(undefined, diagram);
129+
});
130+
}
131+
}, 100);
132+
});
133+
});
134+
});

docs/stylesheets/extra.css

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,52 @@
6464
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
6565
}
6666

67-
/* Mermaid diagram styling */
67+
/* Mermaid diagram styling and optimization */
6868
.mermaid {
6969
text-align: center;
7070
margin: 1em 0;
71+
/* Prevent flash of unstyled content */
72+
opacity: 0;
73+
visibility: hidden;
74+
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
75+
/* Improve rendering performance */
76+
contain: layout;
77+
will-change: opacity, visibility;
78+
}
79+
80+
.mermaid[data-processed="true"] {
81+
opacity: 1;
82+
visibility: visible;
83+
}
84+
85+
/* Mermaid loading state */
86+
.mermaid:not([data-processed]) {
87+
position: relative;
88+
min-height: 200px;
89+
}
90+
91+
.mermaid:not([data-processed])::before {
92+
content: "Loading diagram...";
93+
position: absolute;
94+
top: 50%;
95+
left: 50%;
96+
transform: translate(-50%, -50%);
97+
color: var(--md-default-fg-color--light);
98+
font-style: italic;
99+
opacity: 0.7;
100+
}
101+
102+
/* Dark mode Mermaid adjustments */
103+
[data-md-color-scheme="slate"] .mermaid {
104+
filter: brightness(0.9) contrast(1.1);
105+
}
106+
107+
/* Mermaid responsive improvements */
108+
@media screen and (max-width: 768px) {
109+
.mermaid {
110+
margin: 0.5em 0;
111+
font-size: 0.9em;
112+
}
71113
}
72114

73115
/* Custom icons for different content types */

mkdocs.yml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ theme:
3434
- navigation.expand
3535
- navigation.path
3636
- navigation.top
37+
- navigation.footer
3738
- search.highlight
3839
- search.share
3940
- content.code.copy
4041
- content.code.annotate
4142
- content.action.edit
4243
- content.action.view
44+
- content.tooltips
4345
- toc.follow
4446
- toc.integrate
4547

@@ -98,6 +100,12 @@ markdown_extensions:
98100
plugins:
99101
- search:
100102
separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])'
103+
- git-revision-date-localized:
104+
enable_creation_date: true
105+
type: timeago
106+
timezone: UTC
107+
locale: en
108+
fallback_to_build_date: true
101109
- minify:
102110
minify_html: true
103111

@@ -108,10 +116,18 @@ extra_css:
108116
extra_javascript:
109117
- javascripts/mathjax.js
110118
- https://polyfill.io/v3/polyfill.min.js?features=es6
111-
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
119+
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mtml-chtml.js
120+
- https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js
121+
- javascripts/mermaid.js
112122

113123
# Extra
114124
extra:
125+
version:
126+
provider: mike
127+
default: latest
128+
revision_date: !ENV [CI_COMMIT_TIMESTAMP, REVISION_DATE]
129+
last_updated: !ENV [BUILD_DATE, 2025-09-21]
130+
generator: false
115131
analytics:
116132
provider: google
117133
property: !ENV GOOGLE_ANALYTICS_KEY
@@ -122,6 +138,9 @@ extra:
122138
link: https://twitter.com/mtahle
123139
- icon: fontawesome/brands/linkedin
124140
link: https://linkedin.com/in/mtahle
141+
status:
142+
new: Recently added
143+
deprecated: Deprecated
125144

126145
# Navigation
127146
nav:
@@ -157,4 +176,4 @@ nav:
157176
- Podcasts: resources/podcast.md
158177

159178
# Copyright
160-
copyright: Copyright © 2024 Mujahed Altahleh
179+
copyright: Copyright © 2025 Mujahed Altahleh

0 commit comments

Comments
 (0)