type Theme = "light" | "dark";
const STORAGE_KEY = "theme";
const getSavedTheme = (): Theme => {
const raw = localStorage.getItem(STORAGE_KEY);
if (raw === "light" || raw === "dark") return raw;
return "dark";
};
const applyTheme = (theme: Theme): void => {
const html = document.documentElement;
html.setAttribute("data-theme", theme);
localStorage.setItem(STORAGE_KEY, theme);
updateToggleButtons(theme);
};
const cycleTheme = (): void => {
const current = getSavedTheme();
const next: Theme = current === "light" ? "dark" : "light";
applyTheme(next);
};
const updateToggleButtons = (theme: Theme): void => {
const headerBtn = document.getElementById(
"theme-toggle",
) as HTMLButtonElement | null;
const footerBtn = document.getElementById(
"footer-theme-toggle",
) as HTMLButtonElement | null;
const updateButton = (btn: HTMLButtonElement | null): void => {
if (!btn) return;
const label = btn.querySelector("[data-theme-label]") as HTMLElement | null;
if (label) {
label.textContent = theme;
}
const svg = btn.querySelector("svg");
if (!svg) return;
if (theme === "light") {
svg.innerHTML =
'';
svg.setAttribute("stroke", "currentColor");
svg.setAttribute("fill", "none");
} else {
svg.innerHTML =
'';
svg.setAttribute("stroke", "currentColor");
svg.setAttribute("fill", "none");
}
};
updateButton(headerBtn);
updateButton(footerBtn);
};
const initTheme = (): void => {
const saved = getSavedTheme();
applyTheme(saved);
// Use event delegation to handle theme toggles
document.addEventListener("click", (e) => {
const target = e.target as HTMLElement;
const btn = target.closest("#theme-toggle, #footer-theme-toggle") as HTMLButtonElement | null;
if (btn) {
cycleTheme();
}
});
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initTheme);
} else {
initTheme();
}