What is mermaid.js?
mermaid.js is a JavaScript library that allows you to graphically display complex charts and diagrams, such as flowcharts, diagrams, and Gantt charts, using its own text-based syntax (Mermaid syntax).
It is also adopted by various services like GitHub, Qiita, and Notion. This time, we will make mermaid.js usable in hugo.
Making mermaid.js usable in hugo
The procedure is as follows:
- Add the following to layouts/partials/extend_footer.html.
1
2
3
4
5
6
7
8
9
10
11
12
13
| {{ if or .Params.mermaid .Site.Params.mermaid }}
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.3.0/dist/mermaid.min.js"></script>
{{- $loadmermaid := resources.Get "js/load-mermaid.js" }}
<script src="{{ $loadmermaid.RelPermalink }}"></script>
<script>
window.initMermaid();
if (isDarkTheme()) {
setPrefTheme('dark');
} else {
setPrefTheme('light');
}
</script>
{{ end }}
|
mermaid.min.js is loaded only when mermaid: true is set via the if statement. This library is about 3MB and unexpectedly large.
- Create assets/js/load-mermaid.js. This process is used for initialization and to redraw when the theme is dynamically switched.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| (function(window){
'use strict'
const elementCode = '.mermaid'
const loadMermaid = function(theme) {
window.mermaid.initialize({theme})
window.mermaid.init({theme}, document.querySelectorAll(elementCode))
}
const saveOriginalData = function(){
return new Promise((resolve, reject) => {
try {
var els = document.querySelectorAll(elementCode),
count = els.length;
els.forEach(element => {
element.setAttribute('data-original-code', element.innerHTML)
count--
if(count == 0){
resolve()
}
});
} catch (error) {
reject(error)
}
})
}
const resetProcessed = function(){
return new Promise((resolve, reject) => {
try {
var els = document.querySelectorAll(elementCode),
count = els.length;
els.forEach(element => {
if(element.getAttribute('data-original-code') != null){
element.removeAttribute('data-processed')
element.innerHTML = element.getAttribute('data-original-code')
}
count--
if(count == 0){
resolve()
}
});
} catch (error) {
reject(error)
}
})
}
const init = ()=>{
saveOriginalData()
.catch( console.error )
document.body.addEventListener('dark-theme-set', ()=>{
resetProcessed()
.then(loadMermaid('dark'))
.catch(console.error)
})
document.body.addEventListener('light-theme-set', ()=>{
resetProcessed()
.then(loadMermaid('default'))
.catch(console.error)
})
}
window.initMermaid = init
})(window);
|
The base code was referenced from below:
- Modify the theme switching process in header.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| function switchTheme(theme) {
switch (theme) {
case 'light':
{{ if or .Params.mermaid .Site.Params.mermaid }}
document.body.dispatchEvent(new CustomEvent('light-theme-set'));
{{ end }}
document.body.classList.remove('dark');
break;
case 'dark':
{{ if or .Params.mermaid .Site.Params.mermaid }}
document.body.dispatchEvent(new CustomEvent('dark-theme-set'));
{{ end }}
document.body.classList.add('dark');
break;
// auto
default:
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
{{ if or .Params.mermaid .Site.Params.mermaid }}
document.body.dispatchEvent(new CustomEvent('dark-theme-set'));
{{ end }}
document.body.classList.add('dark');
}
}
}
|
- Create layouts/shortcodes/mermaid.html
1
2
3
| <div class="mermaid" align="{{ if .Get "align" }}{{ .Get "align" }}{{ else }}center{{ end }}">
{{ safeHTML .Inner }}
</div>
|
The preparation to use mermaid.js is now complete.
Trying out mermaid.js
- Add the following to the article’s front matter
- Add the following to the article body
Flowchart
1
2
3
4
5
6
| {{<mermaid align="center">}}
graph TD
A[Start] -->|Condition 1| B(Condition 2)
B --> C{Condition 3}
C -->|Condition 4| D[End]
{{</mermaid>}}
|
Output Result
graph TD
A[Start] -->|Condition 1| B(Condition 2)
B --> C{Condition 3}
C -->|Condition 4| D[End]
Gantt Chart
1
2
3
4
5
6
7
8
9
10
11
12
| {{<mermaid align="center">}}
gantt
section Project
Requirement Definition :done, a, 2024-05-25, 5d
Basic Design :done, b, after a, 5d
Detailed Design :done, c, after b, 5d
Manufacturing :active, d, after c, 10d
Unit Testing :crit, e, after d, 5d
Integration Testing : f, after e, 5d
System Testing : g, after f, 5d
Release :milestone, h, after g, 1d
{{</mermaid>}}
|
Output Result
gantt
section Project
Requirement Definition :done, a, 2024-05-25, 5d
Basic Design :done, b, after a, 5d
Detailed Design :done, c, after b, 5d
Manufacturing :active, d, after c, 10d
Unit Testing :crit, e, after d, 5d
Integration Testing : f, after e, 5d
System Testing : g, after f, 5d
Release :milestone, h, after g, 1d
Sequence Diagram
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| {{<mermaid align="center">}}
sequenceDiagram
participant user
participant view
participant controller
participant model
participant database
user->>view: ID/PW Input
view->>controller: Authentication Request
controller->>model: Authentication Request
model->>database: Authentication Request
database-->>model: Return Authentication Result
model-->>controller: Return Authentication Result
controller-->>view: Return Authentication Result
view-->>user: Display Authentication Result
{{</mermaid>}}
|
Output Result
sequenceDiagram
participant user
participant view
participant controller
participant model
participant database
user->>view: ID/PW Input
view->>controller: ajax query
controller->>model: Authentication Request
model->>database: Issue SQL
database-->>model: Return SQL Result
model-->>controller: Return Authentication Request Result
controller-->>view: Return ajax query result
view-->>user: Display Authentication Result
That is all.
References