Switching Themes for Mermaid (Updated) (Italiano (Italian))

Switching Themes for Mermaid (Updated)

Thursday, 29 August 2024

//

8 minute read

Introduzione

Uso Mermaid.js per creare i diagrammi della droga che vedete in alcuni post. Come quello sotto Tuttavia, una cosa che mi ha irritato è che non era reattivo al cambiamento di tema (dark/lightM SK3 e sembrava che ci fossero informazioni molto scarse su come ottenere questo .

Questo è il risultato di poche ore di ricerca e di tentazioni per capire come farlo.

Potete trovare la fonte di mdeswitcher qui: mdeswitcher.js.

NOTA: L'ho aggiornato in modo significativo.

Il diagramma

graph LR
    A[Start] --> B[Initialize Mermaid with Theme]
    B --> C{Are there any elements matching 'div.mermaid'?}
    C --> |No| D[Exit]
    C --> |Yes| E[Save Original Data]
    E --> F{Did saving data succeed?}
    F --> |No| D[Exit]
    F --> |Yes| G[Set up Theme Event Listeners]
    G --> H[Check Local Storage for Dark Mode]
    H --> I{Is Dark Mode enabled?}
    I --> |Yes| J[Load Mermaid with Dark Theme]
    I --> |No| K[Load Mermaid with Default Theme]
    J --> L[Wait for Events]
    K --> L[Wait for Events]
    L --> M{Event Triggered?}
    M --> |Dark Theme Set| N[Reset Processed Data]
    N --> O[Load Mermaid with Dark Theme]
    M --> |Light Theme Set| P[Reset Processed Data]
    P --> Q[Load Mermaid with Default Theme]
    O --> L
    Q --> L
    L --> D[Exit]


Il problema

Il problema è che dovete iniziare Mermaid per stabilire il tema, e potete'non cambiarlo dopo questoM SK2 comunque, se volete reinitializzarlo su un diagramma già creato ; puòMSC4non ripristinare il diagramma visto che i dati non sonoMST5non sono immagazzinati nel DOM

La soluzione

Quindi dopo MUCH scavare e cercare di capire come fare questo, ho trovato una soluzione in Questo post sul problema di GitHub

Tuttavia aveva ancora qualche problema, quindi ho dovuto modificarlo un po' per farlo funzionare.

Temati

Questo sito è basato su un tema Tailwind che è arrivato con un terribile theme switcher.

Vedrete che questo fa varie cose nel cambiare il tema, stabilendo il tema per quello che è immagazzinato nella memoria locale M SK2 cambiando un paio di fogli di stili per simplemde & evidenziare.js e poi applicare il tema

export  function globalSetup() {
    const lightStylesheet = document.getElementById('light-mode');
    const darkStylesheet = document.getElementById('dark-mode');
    const simpleMdeDarkStylesheet = document.getElementById('simplemde-dark');
    const simpleMdeLightStylesheet = document.getElementById('simplemde-light');
    return {
        isMobileMenuOpen: false,
        isDarkMode: false,
        // Function to initialize the theme based on localStorage or system preference
        themeInit() {
            if (
                localStorage.theme === "dark" ||
                (!("theme" in localStorage) &&
                    window.matchMedia("(prefers-color-scheme: dark)").matches)
            ) {
                localStorage.theme = "dark";
                document.documentElement.classList.add("dark");
                document.documentElement.classList.remove("light");
                this.isDarkMode = true;
              
                this.applyTheme(); // Apply dark theme stylesheets
            } else {
                localStorage.theme = "base";
                document.documentElement.classList.remove("dark");
                document.documentElement.classList.add("light");
                this.isDarkMode = false;
                this.applyTheme(); // Apply light theme stylesheets
            }
        },

        // Function to switch the theme and update the stylesheets accordingly
        themeSwitch() {
            if (localStorage.theme === "dark") {
                localStorage.theme = "light";
                document.body.dispatchEvent(new CustomEvent('light-theme-set'));
                document.documentElement.classList.remove("dark");
                document.documentElement.classList.add("light");
                this.isDarkMode = false;
            } else {
                localStorage.theme = "dark";
                document.body.dispatchEvent(new CustomEvent('dark-theme-set'));
                document.documentElement.classList.add("dark");
                document.documentElement.classList.remove("light");
                this.isDarkMode = true;
            }
            this.applyTheme(); // Apply the theme stylesheets after switching
        },

        // Function to apply the appropriate stylesheets based on isDarkMode
        applyTheme() {
         
            if (this.isDarkMode) {
                // Enable dark mode stylesheets
                lightStylesheet.disabled = true;
                darkStylesheet.disabled = false;
                simpleMdeLightStylesheet.disabled = true;
                simpleMdeDarkStylesheet.disabled = false;
            } else {
                // Enable light mode stylesheets
                lightStylesheet.disabled = false;
                darkStylesheet.disabled = true;
                simpleMdeLightStylesheet.disabled = false;
                simpleMdeDarkStylesheet.disabled = true;
            }
        }
    };
}

Setup

I principali aggiustamenti per il mermaid theme switcher sono i seguenti:

  document.body.dispatchEvent(new CustomEvent('dark-theme-set'));
    document.body.dispatchEvent(new CustomEvent('light-theme-set'));

Questi due eventi sono usati nel nostro componente ThemeSwitcher per reinitialisare i diagrammi della Mermaid.

OnLoad / htmx:afterSwap

Nella mia. main.js file Ho configurato l'interruttore tematico. Ho anche importato il mdeswitch file che contiene il codice per cambiare i temi.

//Important: Memraid will ALWAYS intialize on window.onload, so we need to make sure we disable this behaviour:
import mermaid from "mermaid";

window.mermaid=mermaid;
mermaid.initialize({startOnLoad:false});

window.mermaidinit = function() {
    mermaid.initialize({ startOnLoad: false });
    try {
        window.initMermaid().then(r => console.log('Mermaid initialized'));
    } catch (e) {
        console.error('Failed to initialize Mermaid:', e);
    }

}

document.body.addEventListener('htmx:afterSwap', function(evt) {
    mermaidinit();
    //This should be called after the mermaid diagrams have been rendered.
    hljs.highlightAll();
});

window.onload = function(ev) {
    if(document.readyState === 'complete') {
        mermaidinit();
        hljs.highlightAll();
    }
};

MDESwtich

Questo è il file che contiene il codice per cambiare i temi per Mermaid. (Il terribile Diagramma sopra. mostra la sequenza degli eventi che accadono quando il tema è cambiato)

(function(window) {
    'use strict';

    const elementCode = 'div.mermaid';

    const loadMermaid = async (theme) => {

        mermaid.initialize({startOnLoad: false, theme: theme });
        console.log("Loading mermaid with theme:", theme);
        await mermaid.run({
            querySelector: elementCode,
        });
    };

    const saveOriginalData = async () => {
        try {
            console.log("Saving original data");
            const elements = document.querySelectorAll(elementCode);
            const count = elements.length;

            if (count === 0) return;

            const promises = Array.from(elements).map((element) => {
                if (element.getAttribute('data-processed') != null) {
                    console.log("Element already processed");
                    return;
                }
                element.setAttribute('data-original-code', element.innerHTML);
            });

            await Promise.all(promises);
        } catch (error) {
            console.error(error);
            throw error;
        }
    };

    const resetProcessed = async () => {
        try {
            console.log("Resetting processed data");
            const elements = document.querySelectorAll(elementCode);
            const count = elements.length;

            if (count === 0) return;

            const promises = Array.from(elements).map((element) => {
                if (element.getAttribute('data-original-code') != null) {
                    element.removeAttribute('data-processed');
                    element.innerHTML = element.getAttribute('data-original-code');
                }
                else {
                    console.log("Element already reset");
                }
            });

            await Promise.all(promises);
        } catch (error) {
            console.error(error);
            throw error;
        }
    };

    window.initMermaid = async () => {
        const mermaidElements = document.querySelectorAll(elementCode);
        if (mermaidElements.length === 0) return;

        try {
            await saveOriginalData();
        } catch (error) {
            console.error("Error saving original data:", error);
            return; // Early exit if saveOriginalData fails
        }

        const handleDarkThemeSet = async () => {
            try {
                await resetProcessed();
                await loadMermaid('dark');
                console.log("Dark theme set");
            } catch (error) {
                console.error("Error during dark theme set:", error);
            }
        };

        const handleLightThemeSet = async () => {
            try {
                await resetProcessed();
                await loadMermaid('default');
                console.log("Light theme set");
            } catch (error) {
                console.error("Error during light theme set:", error);
            }
        };
        document.body.removeEventListener('dark-theme-set', handleDarkThemeSet);
        document.body.removeEventListener('light-theme-set', handleLightThemeSet);
        document.body.addEventListener('dark-theme-set', handleDarkThemeSet);
        document.body.addEventListener('light-theme-set', handleLightThemeSet);

        const isDarkMode = localStorage.theme === 'dark';
        await loadMermaid(isDarkMode ? 'dark' : 'default').then(r => console.log('Initial load complete'));


    };

})(window);

Va dal basso in alto qui.

  1. init La funzione - è la funzione principale che viene chiamata quando la pagina è caricata.

Prima si salva il contenuto originale dei diagrammi delle Mermaid; questo è stato un problema nella versione che l'ho copiato da, hanno usato 'innerHTMLM SK3 che non funzionavaMSC4 per me perché alcuni diagrammi si basano su nuove linee che quel trattisceMNK5

Poi aggiunge due ascoltatori per l'evento. dark-theme-set e light-theme-set eventi. Quando questi eventi sono attivati ristabilisce i dati processati e poi reinitializza i diagrammi della Mermaid con il nuovo tema.

Controlla poi il local storage per il tema e inizialisca i diagrammi della Mermaid con il tema appropriato.

let isDarkMode = localStorage.theme === 'dark';
        if(isDarkMode) {
            loadMermaid('dark');
         }
         else{
             loadMermaid('default')
         }

Conservare i dati originali

La chiave di tutto questo è l'archiviazione, poi il ripristino del contenuto contenuto nella rappresentazione. <div class="mermaid"><div> che contieneno il marcho della mermaid dai nostri post.

Voi' vedrete che questo semplicemente crea una Promise che gira attraverso tutti gli elementi e conserva il contenuto originale in un data-original-code attribute.

    const saveOriginalData = async () => {
    try {
        console.log("Saving original data");
        const elements = document.querySelectorAll(elementCode);
        const count = elements.length;

        if (count === 0) return;

        const promises = Array.from(elements).map((element) => {
            if (element.getAttribute('data-processed') != null) {
                console.log("Element already processed");
                return;
            }
            element.setAttribute('data-original-code', element.innerHTML);
        });

        await Promise.all(promises);
    } catch (error) {
        console.error(error);
        throw error;
    }
};

resetProcessed è lo stesso tranne che all'inverso dove prende il marchiamento dal data-original-code attribute e lo riporta all'elemento.

Init

Ora abbiamo tutti questi dati e possiamo riinitalizzare la mermaid per applicare il nostro nuovo tema e rigenerare il diagramma SVG nel nostro output HTML.

    const elementCode = 'div.mermaid';

const loadMermaid = async (theme) => {

    mermaid.initialize({startOnLoad: false, theme: theme });
    console.log("Loading mermaid with theme:", theme);
    await mermaid.run({
        querySelector: elementCode,
    });
};

Conclusione

È stato un po' difficile capirlo, ma sono felice di averlo fatto. Spero che questo aiuti qualcun altro che sta cercando di fare la stessa cosa.

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.