From e04bb611dc72d2da55f33cd9457bbfa81f43dced Mon Sep 17 00:00:00 2001
From: Cell <1024@lruihao.cn>
Date: Thu, 14 Aug 2025 15:29:23 +0800
Subject: [PATCH] :sparkles: Feat: enhance Mermaid configuration and fix
initialization bug (#617)
* :bug: Fix: Mermaid initialization conflict error
* :sparkles: Feat: enhance Mermaid configuration with security level, look, and font family options
---
assets/css/_partials/_single/_code.scss | 2 +-
.../_partials/_single/_diagram-copy-btn.scss | 20 +++++++++++++++----
assets/css/_shortcodes/_mermaid.scss | 3 ++-
assets/js/lib/mermaid.js | 10 ++++++++++
assets/js/theme.js | 19 +++++++++++++-----
hugo.toml | 10 +++++++++-
layouts/_partials/assets.html | 17 ++++++++--------
layouts/_partials/footer.html | 2 +-
layouts/_partials/header.html | 6 +++---
layouts/_partials/plugin/echarts.html | 2 +-
layouts/_partials/plugin/mermaid.html | 4 ++--
layouts/_partials/single/footer.html | 4 ++--
12 files changed, 70 insertions(+), 29 deletions(-)
create mode 100644 assets/js/lib/mermaid.js
diff --git a/assets/css/_partials/_single/_code.scss b/assets/css/_partials/_single/_code.scss
index baf6d9f3..fb40dec4 100644
--- a/assets/css/_partials/_single/_code.scss
+++ b/assets/css/_partials/_single/_code.scss
@@ -4,7 +4,7 @@ code {
}
// indented code
-pre:not(.mermaid[data-processed='true']) {
+pre:not(.mermaid[data-processed]) {
margin: 0;
line-height: 1.45em;
padding: 0.5rem;
diff --git a/assets/css/_partials/_single/_diagram-copy-btn.scss b/assets/css/_partials/_single/_diagram-copy-btn.scss
index 9aefb9f5..d0d047b1 100644
--- a/assets/css/_partials/_single/_diagram-copy-btn.scss
+++ b/assets/css/_partials/_single/_diagram-copy-btn.scss
@@ -1,3 +1,8 @@
+// Diagram container
+.diagram-container {
+ position: relative;
+}
+
// Diagram copy button styles
.diagram-copy-btn {
position: absolute;
@@ -50,8 +55,15 @@
}
}
-// Diagram containers
-.mermaid-container,
-.echarts-container {
- position: relative;
+@media only screen and (min-width: 1201px) {
+ .diagram-container {
+ .diagram-copy-btn {
+ display: none;
+ }
+ &:hover {
+ .diagram-copy-btn {
+ display: block;
+ }
+ }
+ }
}
diff --git a/assets/css/_shortcodes/_mermaid.scss b/assets/css/_shortcodes/_mermaid.scss
index a1c0e004..670fc222 100644
--- a/assets/css/_shortcodes/_mermaid.scss
+++ b/assets/css/_shortcodes/_mermaid.scss
@@ -1,7 +1,8 @@
.mermaid {
position: relative;
+ overflow: hidden !important;
- &[data-processed='true'] {
+ &[data-processed] {
text-align: center;
}
diff --git a/assets/js/lib/mermaid.js b/assets/js/lib/mermaid.js
new file mode 100644
index 00000000..e34bad6b
--- /dev/null
+++ b/assets/js/lib/mermaid.js
@@ -0,0 +1,10 @@
+{{- $mermaid := .Param "mermaid" -}}
+{{- $mermaidCDN := $mermaid.cdn | default "https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs" -}}
+
+import mermaid from "{{ $mermaidCDN }}";
+{{- with $mermaid.zenuml }}
+import zenuml from "{{ . }}";
+await mermaid.registerExternalDiagrams([zenuml]);
+{{- end }}
+mermaid.startOnLoad = false;
+window.mermaid = mermaid;
diff --git a/assets/js/theme.js b/assets/js/theme.js
index 07081e06..5aa6f5f7 100644
--- a/assets/js/theme.js
+++ b/assets/js/theme.js
@@ -665,30 +665,39 @@ class FixIt {
const loadMermaid = async () => {
processing = true;
+ // https://mermaid.js.org/config/schema-docs/config.html
window.mermaid.initialize({
- securityLevel: 'loose',
startOnLoad: false,
+ darkMode: this.isDark,
theme: this.isDark ? themes[1] : themes[0],
+ securityLevel: this.config.mermaid.securityLevel,
+ look: this.config.mermaid.look,
+ fontFamily: this.config.mermaid.fontFamily,
+ altFontFamily: this.config.mermaid.fontFamily
+ });
+ await window.mermaid.run({
+ querySelector: '.mermaid',
+ suppressErrors: true,
});
- await window.mermaid.run();
processing = false;
if (delayTask && typeof delayTask === 'function') {
- await delayTask();
+ delayTask();
delayTask = null;
+ // console.log('Delayed task executed');
}
};
const reloadMermaid = async () => {
await this.util.forEach(document.querySelectorAll('.mermaid[data-processed]'), (el) => {
- el.replaceChild(el.nextElementSibling.content.cloneNode(true), el.firstChild);
el.removeAttribute('data-processed');
+ el.parentElement.replaceChild(el.nextElementSibling.content.cloneNode(true), el);
});
await loadMermaid();
};
this.switchThemeEventSet.add(() => {
if (processing) {
- // console.log('delay the reload');
+ console.warn('Mermaid is still processing, delaying the reload.');
delayTask = reloadMermaid;
return;
}
diff --git a/hugo.toml b/hugo.toml
index b0e1dd27..f1c8f57e 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -699,7 +699,7 @@ mainSections = []
loop = false
# FixIt 0.2.15 | NEW Mermaid config
- # See https://github.com/mermaid-js/mermaid
+ # See http://fixit.lruihao.cn/documentation/content-management/diagrams-support/mermaid/
[params.mermaid]
# FixIt 0.4.0 | NEW Mermaid ESM module CDN source
# default is https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs
@@ -710,6 +710,14 @@ mainSections = []
zenuml = ""
# For values, see https://mermaid.js.org/config/theming.html#available-themes
themes = ["default", "dark"]
+ # FixIt 0.4.0 | NEW The security level for Mermaid diagrams
+ # optional values: ["strict", "loose", "antiscript", "sandbox"]
+ securityLevel = "loose"
+ # FixIt 0.4.0 | NEW The appearance style for Mermaid diagrams
+ # optional values: ["classic", "handDrawn"]
+ look = "handDrawn"
+ # FixIt 0.4.0 | NEW Specifies the font to be used in the rendered diagrams
+ fontFamily = ""
# FixIt 0.3.13 | NEW Admonitions custom config
# See https://fixit.lruihao.cn/documentation/content-management/shortcodes/extended/admonition/#custom-admonitions
diff --git a/layouts/_partials/assets.html b/layouts/_partials/assets.html
index 22fb23ad..359af760 100644
--- a/layouts/_partials/assets.html
+++ b/layouts/_partials/assets.html
@@ -130,14 +130,15 @@
{{- /* mermaid */ -}}
{{- if .Store.Get "hasMermaid" -}}
{{- $mermaid := .Param "mermaid" -}}
- {{- $mermaidCDN := $mermaid.cdn | default "https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs" -}}
- {{- $content := printf "import mermaid from %q;" $mermaidCDN -}}
- {{- with $mermaid.zenuml -}}
- {{- $content = printf "%v import zenuml from %q; await mermaid.registerExternalDiagrams([zenuml]);" $content . -}}
- {{- end -}}
- {{- $content = printf "%v window.mermaid = mermaid;" $content -}}
- {{- dict "Content" $content "Attr" `type="module"` | dict "Page" $ "Data" | partial "store/script.html" -}}
- {{- $config = dict "themes" $mermaid.themes | dict "mermaid" | merge $config -}}
+ {{- $config = dict
+ "themes" $mermaid.themes
+ "securityLevel" $mermaid.securityLevel
+ "look" $mermaid.look
+ "fontFamily" $mermaid.fontFamily
+ | dict "mermaid" | merge $config -}}
+ {{- $options := dict "Source" "js/lib/mermaid.js" "Template" "js/lib/mermaid.min.js" -}}
+ {{- $options = dict "Context" . "Minify" true "Fingerprint" $fingerprint "Attr" `type="module"` | merge $options -}}
+ {{- $options | dict "Page" $ "Data" | partial "store/script.html" -}}
{{- end -}}
{{- /* ECharts */ -}}
diff --git a/layouts/_partials/footer.html b/layouts/_partials/footer.html
index 8d0aecd6..0c103187 100644
--- a/layouts/_partials/footer.html
+++ b/layouts/_partials/footer.html
@@ -42,7 +42,7 @@
{{- /* Author */ -}}
{{- if ne $footerConfig.author false -}}
- {{ partial "plugin/link.html" (dict "Destination" ($.Site.Params.author.link | default (relURL "")) "Content" .Site.Params.author.name) -}}
+ {{ partial "plugin/link.html" (dict "Destination" ($.Site.Params.author.link | default (relLangURL "")) "Content" .Site.Params.author.name) -}}
{{- end -}}
diff --git a/layouts/_partials/header.html b/layouts/_partials/header.html
index 691f700e..40cf1efe 100644
--- a/layouts/_partials/header.html
+++ b/layouts/_partials/header.html
@@ -1,11 +1,11 @@
{{- $buildDrafts := .Site.BuildDrafts -}}
-{{- $relURL := relURL "" -}}
+{{- $relLangURL := relLangURL "" -}}
{{- /* Desktop header */ -}}