Att byta tema för sjöjungfrun (Aktualiserad)
Inleiding
Jag använder Mermaid.js för att skapa de dopingdiagram du ser i ett fåtal postituser Men något som gjorde mig irriterad är att det inte var reaktivt med att byta ämnen.
Detta är resultatet av några timmars grävande och försök att lista ut hur man gör det här.
Ni kan hitta källan till mdeswitcher här: mdeswitcher.js.
NOTA: Jag har laddat upp den i stor utsträckning
Diagrammet
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]
Problemet
Problemet är att du behöver initialisera Mermaid för att sätta in teman, och du kan ̈ ' ̈ inte ändra det efter det ̈ M SK2 ̈ Hursomhelst om du vill återinitialisera det på ett redan skapat diagram ̈ ; ̈ kan det ̈' ̈ inte göra om diagrammet eftersom datan inte är i DOM
Lösningen
Så efter MUCH grävande och försök att lista ut hur man gör detta, hittade jag en lösning i den här GitHub-utgåvan
Men den hade fortfarande några problem, så jag var tvungen att modifiera den lite för att få igång.
Themes
Denna webbplats är baserad på en Tailwind tema som kom med ett ganska hemskt tema-switcher.
Du kommer se att det här gör olika saker runt att byta ämnet.,, ställ ämnen för vad som lagras i den lokala dataskivan. ,, ändra ett par styler på simplemde, &, markera ., js och sedan tillämpa ämnena.
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;
}
}
};
}
Konfiguration
De viktigaste tillämpningarna för Mermaid theme 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 återinitialisera sjöjungfrudiagrammen.
OnLoad / htmx:afterSwap
I min main.js file Jag konfigurerar temaknappen. Jag importerar också mdeswitch file som innehåller koden för att byta tema.
//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
Detta är den filen som innehåller koden för att byta tema för Mermaid. ( Den hemska diagrammet ovan visar sekvensen av händelser som händer 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);
Jag går från botten till toppen här.
init- är huvudfunktionen som kallas när sidan lades
Den sparar först den ursprungliga innehållet i sjöjungfrudiagrammen.
Den lägger sedan till två händelse lyssnare för dark-theme-set och light-theme-set händelser. När dessa händelser aktiveras återställer den bearbetade data och återinitialiserar sjöjungfrudiagrammen med det nya ämnet
Den ser sedan vilken plats som är lagrad för temaet och initialiserar sjöjungfrudiagrammen med det lämpliga temat.
let isDarkMode = localStorage.theme === 'dark';
if(isDarkMode) {
loadMermaid('dark');
}
else{
loadMermaid('default')
}
spara ursprungliga data
Nyckeln till det här hela är att lagra och sedan återställa innehållet som finns i <div class="mermaid"><div> som innefattar sjöjungfrusmärket från våra poster.
Du' ser att det här bara sätter upp en Promise , som loopar genom alla element och lagrar den ursprungliga innehållet i 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 är samma förutom bakåt där det tar märket från data-original-code attribut och sätter den tillbaka till elementet.
Init
Nu har vi alla dessa data så kan vi återinitialisera sjöjungfrun för att tillämpa vårt nya tema och återinföra SVG-diagrammet till vår HTML-output
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,
});
};
I slutsats
Det var lite svårt att lista ut, men jag är glad att jag gjorde det. Jag hoppas detta hjälper någon annan där ute som försöker göra samma sak.