UNPKG

@h0rn0chse/dark-mode-toggle

Version:
80 lines (65 loc) 2.19 kB
import { EventBus } from "./EventBus.js"; class _ThemeHandler extends EventBus { constructor () { super("ThemeBus"); this.themes = { light: document.querySelector("#light"), dark: document.querySelector("#dark"), }; this.initialized = false; } init () { if (this.initialized) { return } this.initialized = true; const savedTheme = localStorage.getItem("theme"); const systemTheme = this._initWatcher(); this._initThemes(savedTheme || systemTheme); } _getInverseTheme (theme) { switch (theme) { case "light": return this.themes.dark; case "dark": return this.themes.light; default: } } _initWatcher () { const colorSchemeQueryList = globalThis.matchMedia("(prefers-color-scheme: dark)"); colorSchemeQueryList.addEventListener("change", (evt) => { const preferDark = colorSchemeQueryList.matches; this.setTheme(preferDark ? "dark" : "light"); }); const preferDark = colorSchemeQueryList.matches; return preferDark ? "dark" : "light"; } _initThemes (theme) { this.currentTheme = theme; const inverseTheme = this._getInverseTheme(theme); inverseTheme.remove(); } setTheme (theme) { if (this.currentTheme === theme) { return; } const activeTheme = this._getInverseTheme(theme); const targetTheme = this.themes[theme].cloneNode(); targetTheme.addEventListener("load", (evt) => { activeTheme.remove(); // theme is ready this.emit("themeLoaded", { theme }); }, { once: true }); document.head.appendChild(targetTheme); // save new theme and it's node this.themes[theme] = targetTheme; this.currentTheme = theme; localStorage.setItem("theme", theme); this.emit("themeChanged", { theme }); } getTheme () { return this.currentTheme; } } export const ThemeHandler = new _ThemeHandler();