/** * AKSRT Theme Toggle — dark/light mode switching with transitions */ (function () { "use strict"; var THEME_KEY = "aksrt-theme"; var THEME_COOKIE_KEY = "theme_mode"; function normalizeStoredTheme(value) { if (value === "dark" || value === "dark-theme") return "dark"; if (value === "light" || value === "white-theme") return "light"; return null; } function toCookieTheme(value) { return value === "dark" ? "dark-theme" : "white-theme"; } function getCookie(name) { var parts = document.cookie ? document.cookie.split("; ") : []; for (var i = 0; i < parts.length; i++) { var pair = parts[i].split("="); if (decodeURIComponent(pair[0]) === name) { return decodeURIComponent(pair.slice(1).join("=")); } } return ""; } function setCookie(name, value, days) { var maxAge = days ? "; max-age=" + (days * 24 * 60 * 60) : ""; var secure = window.location && window.location.protocol === "https:" ? "; Secure" : ""; document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + maxAge + "; path=/; SameSite=Lax" + secure; } function getStoredTheme() { var localTheme = null; try { localTheme = normalizeStoredTheme(localStorage.getItem(THEME_KEY)); } catch (e) { localTheme = null; } var theme = normalizeStoredTheme(getCookie(THEME_COOKIE_KEY)) || localTheme; if (theme) { setStoredTheme(theme); } return theme; } function setStoredTheme(value) { var theme = normalizeStoredTheme(value); if (!theme) return; try { localStorage.setItem(THEME_KEY, theme); } catch (e) {} setCookie(THEME_COOKIE_KEY, toCookieTheme(theme), 365); } function getTimeAutoTheme() { var hour = (new Date()).getHours(); return hour >= 20 || hour < 8 ? "dark" : "light"; } function resolveConfiguredTheme(mode) { var normalized = normalizeStoredTheme(mode); if (normalized) return normalized; if (mode === "time-auto" || mode === "auto") { return getTimeAutoTheme(); } return "light"; } function syncBrandLogos(isDark) { document.querySelectorAll("[data-logo-light]").forEach(function (img) { var lightSrc = img.getAttribute("data-logo-light") || ""; var darkSrc = img.getAttribute("data-logo-dark") || ""; if (!lightSrc) return; img.setAttribute("src", isDark && darkSrc ? darkSrc : lightSrc); }); } function syncThemeColorMeta(isDark) { var meta = document.querySelector('meta[name="theme-color"]'); if (!meta) { meta = document.createElement("meta"); meta.setAttribute("name", "theme-color"); document.head.appendChild(meta); } meta.setAttribute("content", isDark ? "#2F3135" : "#FDFCFE"); } function getThemeImageAttr(img, name) { return img.getAttribute(name) || img.getAttribute("data-" + name) || ""; } function setThemeImageSource(img, src) { if (!src || img.getAttribute("src") === src) return; img.setAttribute("src", src); } function syncThemeImages(isDark) { document.querySelectorAll("img[switch-src], img[data-switch-src]").forEach(function (img) { var darkSrc = getThemeImageAttr(img, "switch-src"); if (!img.dataset.aksrtThemeLightSrc) { img.dataset.aksrtThemeLightSrc = img.getAttribute("src") || ""; } setThemeImageSource(img, isDark && darkSrc ? darkSrc : img.dataset.aksrtThemeLightSrc); }); document.querySelectorAll("img[white-src], img[dark-src], img[data-white-src], img[data-dark-src]").forEach(function (img) { var lightSrc = getThemeImageAttr(img, "white-src") || img.dataset.aksrtThemeLightSrc || img.getAttribute("src") || ""; var darkSrc = getThemeImageAttr(img, "dark-src"); if (!img.dataset.aksrtThemeLightSrc && lightSrc) { img.dataset.aksrtThemeLightSrc = lightSrc; } setThemeImageSource(img, isDark && darkSrc ? darkSrc : lightSrc); }); } function syncCodeHighlightTheme(isDark) { if (typeof window.AksrtPrecodeApplyTheme === "function") { window.AksrtPrecodeApplyTheme(isDark); return; } var settings = (window.aksrtData && window.aksrtData.codeHighlight) || {}; var theme = isDark ? (settings.darkTheme || "monokai") : (settings.lightTheme || "enlighter"); document.querySelectorAll(".enlighter-default").forEach(function (el) { el.className = el.className.replace(/\benlighter-t-[\w-]+\b/g, "").replace(/\s+/g, " ").trim(); el.classList.add("enlighter-t-" + theme); }); } function dispatchThemeChange(isDark) { try { document.dispatchEvent(new CustomEvent("aksrt:theme-change", { detail: { theme: isDark ? "dark" : "light", isDark: isDark } })); } catch (e) {} } function applyTheme(mode) { var isDark = mode === "dark"; document.documentElement.classList.toggle("dark", isDark); document.documentElement.setAttribute("data-theme", isDark ? "dark" : "light"); document.body.classList.toggle("theme-dark", isDark); document.body.classList.toggle("dark-theme", isDark); document.body.classList.toggle("white-theme", !isDark); document.body.setAttribute("data-theme", isDark ? "dark" : "light"); syncBrandLogos(isDark); syncThemeColorMeta(isDark); syncThemeImages(isDark); syncCodeHighlightTheme(isDark); dispatchThemeChange(isDark); var btn = document.getElementById("theme-toggle"); if (btn) { btn.setAttribute("aria-pressed", isDark ? "true" : "false"); btn.classList.toggle("is-dark", isDark); var moon = btn.querySelector(".theme-icon-moon"); var sun = btn.querySelector(".theme-icon-sun"); if (moon && sun) { moon.style.display = isDark ? "none" : ""; sun.style.display = isDark ? "" : "none"; } } var floatBtn = document.getElementById("float-theme-toggle"); if (floatBtn) { floatBtn.setAttribute("aria-pressed", isDark ? "true" : "false"); var moonIcon = floatBtn.querySelector(".float-btn__icon-moon"); var sunIcon = floatBtn.querySelector(".float-btn__icon-sun"); if (moonIcon && sunIcon) { moonIcon.style.display = isDark ? "" : "none"; sunIcon.style.display = isDark ? "none" : ""; } } var ddBtn = document.getElementById("dropdown-theme-toggle"); if (ddBtn) ddBtn.setAttribute("aria-pressed", isDark ? "true" : "false"); } function initTheme() { var stored = getStoredTheme(); var configuredMode = (window.aksrtData && aksrtData.themeMode) || "light"; if (stored === "dark" || stored === "light") { applyTheme(stored); } else { applyTheme(resolveConfiguredTheme(configuredMode)); } function prefersReducedMotion() { return window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; } function getThemeTransitionPoint(event) { if (event && typeof event.clientX === "number" && typeof event.clientY === "number") { return { x: event.clientX, y: event.clientY }; } return { x: window.innerWidth / 2, y: window.innerHeight / 2 }; } function runThemeTransition(next, event) { if (!document.startViewTransition || prefersReducedMotion()) { applyTheme(next); return; } var point = getThemeTransitionPoint(event); var endRadius = Math.hypot( Math.max(point.x, window.innerWidth - point.x), Math.max(point.y, window.innerHeight - point.y) ); var clipPath = [ "circle(0px at " + point.x + "px " + point.y + "px)", "circle(" + endRadius + "px at " + point.x + "px " + point.y + "px)" ]; var enteringDark = next === "dark"; try { var transition = document.startViewTransition(function () { applyTheme(next); }); transition.ready.then(function () { try { document.documentElement.animate( { clipPath: enteringDark ? clipPath : clipPath.slice().reverse() }, { duration: 500, easing: enteringDark ? "ease-in" : "ease-out", fill: "both", pseudoElement: enteringDark ? "::view-transition-new(root)" : "::view-transition-old(root)" } ); } catch (e) {} }).catch(function () {}); } catch (e) { applyTheme(next); } } function bindToggle(id) { var el = document.getElementById(id); if (!el) return; el.addEventListener("click", function (event) { var next = document.body.classList.contains("theme-dark") ? "light" : "dark"; setStoredTheme(next); runThemeTransition(next, event); }); } bindToggle("theme-toggle"); bindToggle("theme-toggle-desktop"); bindToggle("dropdown-theme-toggle"); bindToggle("float-theme-toggle"); bindToggle("theme-toggle-mobile"); aksrt.toggleTheme = function (event) { var next = document.body.classList.contains("theme-dark") ? "light" : "dark"; setStoredTheme(next); runThemeTransition(next, event); }; } window.AksrtFrontend.register("aksrt-theme", function () { initTheme(); }); })();