102 lines
2.8 KiB
JavaScript
102 lines
2.8 KiB
JavaScript
(function () {
|
|
var STORAGE_KEY = "theme";
|
|
var root = document.documentElement;
|
|
var mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
var isAuthenticated = window.__TC_IS_AUTHENTICATED === true || window.__TC_IS_AUTHENTICATED === "true";
|
|
var serverTheme = normalizeTheme(window.__TC_SERVER_THEME);
|
|
|
|
function normalizeTheme(theme) {
|
|
if (!theme) return "";
|
|
return String(theme).trim().toLowerCase();
|
|
}
|
|
|
|
function getStoredTheme() {
|
|
var value = null;
|
|
try {
|
|
value = localStorage.getItem(STORAGE_KEY);
|
|
} catch (e) {
|
|
value = null;
|
|
}
|
|
return value === "dark" || value === "light" ? value : null;
|
|
}
|
|
|
|
function getPreferredTheme() {
|
|
return mediaQuery.matches ? "dark" : "light";
|
|
}
|
|
|
|
function applyTheme(theme) {
|
|
root.classList.toggle("dark", theme === "dark");
|
|
}
|
|
|
|
function currentTheme() {
|
|
return root.classList.contains("dark") ? "dark" : "light";
|
|
}
|
|
|
|
function setStoredTheme(theme) {
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, theme);
|
|
} catch (e) {
|
|
// localStorage may be unavailable in private mode or blocked contexts.
|
|
}
|
|
}
|
|
|
|
function persistThemePreference(theme) {
|
|
if (!isAuthenticated) return;
|
|
fetch("/preferences/theme", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
credentials: "same-origin",
|
|
body: JSON.stringify({ theme: theme }),
|
|
}).catch(function () {});
|
|
}
|
|
|
|
function updateToggleState(theme) {
|
|
var button = document.getElementById("themeToggle");
|
|
if (!button) return;
|
|
|
|
var isDark = theme === "dark";
|
|
button.setAttribute("aria-pressed", isDark ? "true" : "false");
|
|
button.textContent = isDark ? "Light mode" : "Dark mode";
|
|
}
|
|
|
|
function applyInitialTheme() {
|
|
if (isAuthenticated && (serverTheme === "dark" || serverTheme === "light")) {
|
|
setStoredTheme(serverTheme);
|
|
applyTheme(serverTheme);
|
|
return;
|
|
}
|
|
var stored = getStoredTheme();
|
|
applyTheme(stored || getPreferredTheme());
|
|
}
|
|
|
|
window.toggleTheme = function toggleTheme() {
|
|
var next = currentTheme() === "dark" ? "light" : "dark";
|
|
applyTheme(next);
|
|
setStoredTheme(next);
|
|
persistThemePreference(next);
|
|
updateToggleState(next);
|
|
};
|
|
|
|
window.initThemeToggle = function initThemeToggle() {
|
|
updateToggleState(currentTheme());
|
|
};
|
|
|
|
if (typeof mediaQuery.addEventListener === "function") {
|
|
mediaQuery.addEventListener("change", function (event) {
|
|
if (getStoredTheme()) return;
|
|
var theme = event.matches ? "dark" : "light";
|
|
applyTheme(theme);
|
|
updateToggleState(theme);
|
|
});
|
|
} else if (typeof mediaQuery.addListener === "function") {
|
|
mediaQuery.addListener(function (event) {
|
|
if (getStoredTheme()) return;
|
|
var theme = event.matches ? "dark" : "light";
|
|
applyTheme(theme);
|
|
updateToggleState(theme);
|
|
});
|
|
}
|
|
|
|
applyInitialTheme();
|
|
})();
|