note

This article was last updated on April 22, 2023, 10 months ago. The content may be out of date.

Mermaid is a javascript library that can render text definitions as diagrams. It’s not supported by PaperMod. There are two major problems that I encountered when adding mermaid support.

Mermaid Diagrams not Showing

I tried the method described in this comment. It only worked in my local development environment. And when I put mermaid related snippets in extend_footer.html like the author suggested, it won’t even work.


Cause

The head and the footer of the theme is handled by baseof.html and they’re both partials. However, when rendering, head is not cached but footer is not. hasMermaid variable is only be set when hugo finishes processing the content of the post. The content is based on commit 575cc0c.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="{{ site.Language }}" dir="{{ .Language.LanguageDirection | default "auto" }}">

<head>
    {{- partial "head.html" . }}
</head>

<body class="
{{- if (or (ne .Kind `page` ) (eq .Layout `archives`) (eq .Layout `search`)) -}}
{{- print "list" -}}
{{- end -}}
{{- if eq site.Params.defaultTheme `dark` -}}
{{- print " dark" }}
{{- end -}}
" id="top">
    {{- partialCached "header.html" . .Page -}}
    <main class="main">
        {{- block "main" . }}{{ end }}
    </main>
    {{ partialCached "footer.html" . .Layout .Kind (.Param "hideFooter") (.Param "ShowCodeCopyButtons") -}}
</body>

</html>

When in my local development environment, hugo is running in fast render mode. By using store, this variable is not reset. When hugo rebuilds the site, the variable is picked up in extend_head.html so mermaid diagrams display properly.

But when deploying the site, hugo doesn’t rebuild the site. This variable is not set until hugo is done with the content of the post.

Because footer is a cached partial, hugo reuse the same footer across the site. Some pages don’t have mermaid, and they’re usually built first. extend_footer.html doesn’t work either.

Solution

Modify baseof.html and add a new partial mermaid.html that renders mermaid diagrams when hasMermaid variable is set.

Dark Mode Toggle

When using the dark mode toggle, mermaid diagrams doesn’t update their themes. This is expected since the code used to initialize mermaid diagrams doesn’t take dark mode into consideration.

Solution

By inspecting the source code of the PaperMod theme, when in dark mode document.body.classList.contains('dark') will return true, whether dark mode is set auto or manual. That’s the first step. Now we can choose the correct theme when the page is loaded.

But when dark mode is toggled, dark class on document.body will be added or removed, and we’ll watch this as well. Javascript has provided MutationObserver for use to watch any change that might happen to an html element.

var observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
        const theme = document.body.classList.contains('dark')? 'dark': 'default';
        if (oldTheme !== theme) {
            oldTheme = theme;
            // rerender mermaid diagrams
        }
    });
});

observer.observe(document.body, {
    attributes: true,
    attributeFilter: ['class']
});

To rerender mermaid diagrams, I have looked up the mermaid documentation and based on this comment.

  1. Restore the innerhtml of the mermaid diagram elements to their original text (requires saving them before they’re rendered)
  2. Remove the data-processed attribute from these elements
  3. Reinitialize mermaid
  4. Rerender

warning

mermaid.init is deprecated according to the mermaid documentation.