NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Thursday, 29 August 2024
//Less than a minute
Jag använder Mermaid.js för att skapa knarkdiagram du ser i några inlägg. Som den där nere. Men något som irriterade mig är att det inte var reaktivt att byta teman (mörk/ljus) och det verkade finnas mycket dålig information ute om att uppnå detta.
Detta är resultatet av några timmars grävande och försök att räkna ut hur man gör detta.
Här hittar du källan för mdeswitcher: mdeswitcher.js.
OBS: Jag har uppdaterat detta väsentligt.
Problemet är att du måste initiera Mermaid att ställa in temat, och du kan inte ändra det efter det. HUR som helst om du vill återinitiera det på ett redan skapat diagram; det kan inte göra om diagrammet eftersom data inte lagras i DOM.
Så efter MYCKET gräva och försöka räkna ut hur man gör detta, hittade jag en lösning i detta GitHub nummer inlägg
Men det hade fortfarande några problem, så jag var tvungen att ändra det lite för att få det att fungera.
Denna webbplats är baserad på en Tailwind tema som kom med en ganska hemsk tema switcher.
Du kommer att se att detta gör olika saker runt att byta tema, ställa in temat för vad som lagras i lokal lagring, ändra ett par stilar för simplemde & highlight.js och sedan tillämpa temat.
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;
}
}
};
}
De viktigaste tilläggen för Mermaid tema switcher är följande:
document.body.dispatchEvent(new CustomEvent('dark-theme-set'));
document.body.dispatchEvent(new CustomEvent('light-theme-set'));
Dessa två händelser används i vår ThemeSwitcher komponent för att återinitiera Mermaid diagram.
I min main.js
fil Jag ställer in temaomkopplaren. Jag importerar också mdeswitch
fil som innehåller koden för att byta teman.
//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();
}
};
Detta är filen som innehåller koden för att byta teman för Mermaid. (De fruktansvärda diagram ovan visar sekvensen av händelser som inträffar när temat ändras)
(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);
Går ner till toppen här.
init
- funktionen är huvudfunktionen som kallas när sidan laddas.Det sparar först det ursprungliga innehållet i Mermaid diagram; Detta var ett problem i den version jag kopierade det från, de använde "innerHTML" som inte fungerade för mig som vissa diagram förlitar sig på nya linjer som att remsor.
Det lägger sedan till två evenemang lyssnare för dark-theme-set
och light-theme-set
händelser. När dessa händelser avfyras återställs den bearbetade datan och återinitierar sedan Mermaid-diagrammet med det nya temat.
Det kontrollerar sedan den lokala lagringen för temat och initierar Mermaid diagram med lämplig tema.
let isDarkMode = localStorage.theme === 'dark';
if(isDarkMode) {
loadMermaid('dark');
}
else{
loadMermaid('default')
}
Nyckeln till hela denna sak är att lagra sedan återställa innehållet i den renderade <div class="mermaid"><div>
som innehåller sjöjungfrun markup från våra poster.
Du kommer att se detta bara sätter upp ett löfte som slingor genom alla element och lagrar det ursprungliga innehållet i en data-original-code
Egenskap.
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
är samma utom i omvänd riktning där det tar pålägg från data-original-code
attribut och ställer tillbaka det till elementet.
Nu har vi alla dessa data vi kan återinitiera sjöjungfru för att tillämpa vårt nya tema och rendera SVG diagrammet i vår HTML-utgång.
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,
});
};
Det här var lite jobbigt att lista ut, men jag är glad att jag gjorde det. Jag hoppas att detta hjälper någon annan som försöker göra samma sak.