mirror of
https://github.com/imfing/hextra.git
synced 2025-08-23 07:07:06 -04:00

* feat: add 'system' inside the theme toggle * chore: generate hugo_stats.json * fix: missing css * chore: reorganize code * feat: menu * chore: simplify * chore: some i18n * review * fix: remove replace
119 lines
3.7 KiB
JavaScript
119 lines
3.7 KiB
JavaScript
// Light / Dark theme toggle
|
|
(function () {
|
|
const defaultTheme = '{{ site.Params.theme.default | default `system`}}'
|
|
|
|
const themeToggleButtons = document.querySelectorAll(".hextra-theme-toggle");
|
|
const themeToggleOptions = document.querySelectorAll(".hextra-theme-toggle-options p");
|
|
|
|
function setSystemTheme() {
|
|
const prefersColorScheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
|
|
document.documentElement.classList.remove("dark", "light");
|
|
document.documentElement.classList.add(prefersColorScheme);
|
|
|
|
document.documentElement.style.colorScheme = prefersColorScheme;
|
|
}
|
|
|
|
function applyTheme(theme) {
|
|
themeToggleButtons.forEach((btn) => btn.parentElement.dataset.theme = theme );
|
|
|
|
localStorage.setItem("color-theme", theme);
|
|
}
|
|
|
|
function switchTheme(theme) {
|
|
switch (theme) {
|
|
case "light":
|
|
document.documentElement.classList.remove("dark");
|
|
document.documentElement.classList.add(theme);
|
|
document.documentElement.style.colorScheme = theme;
|
|
|
|
applyTheme(theme);
|
|
|
|
break;
|
|
case "dark":
|
|
document.documentElement.classList.remove("light");
|
|
document.documentElement.classList.add(theme);
|
|
document.documentElement.style.colorScheme = theme;
|
|
|
|
applyTheme(theme);
|
|
|
|
break;
|
|
default:
|
|
setSystemTheme();
|
|
applyTheme("system");
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
const colorTheme = "color-theme" in localStorage ? localStorage.getItem("color-theme") : defaultTheme;
|
|
switchTheme(colorTheme);
|
|
|
|
// Add click event handler to the menu items.
|
|
themeToggleOptions.forEach((option) => {
|
|
option.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
|
|
switchTheme(option.dataset.item);
|
|
})
|
|
})
|
|
|
|
// Add click event handler to the buttons
|
|
themeToggleButtons.forEach((toggler) => {
|
|
toggler.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
|
|
const optionsElement = toggler.nextElementSibling;
|
|
|
|
optionsElement.classList.toggle('hx:hidden');
|
|
|
|
// Calculate the position of a language options element.
|
|
const switcherRect = toggler.getBoundingClientRect();
|
|
|
|
// Must be called before optionsElement.clientWidth.
|
|
optionsElement.style.minWidth = `${Math.max(switcherRect.width, 50)}px`;
|
|
|
|
const isOnTop = toggler.dataset.location === 'top';
|
|
const isOnBottom = toggler.dataset.location === 'bottom';
|
|
const isOnBottomRight = toggler.dataset.location === 'bottom-right';
|
|
const isRTL = document.body.dir === 'rtl'
|
|
|
|
// Stuck on the left side of the switcher.
|
|
let translateX = switcherRect.left;
|
|
|
|
if (isOnTop && !isRTL || isOnBottom && isRTL || isOnBottomRight && !isRTL) {
|
|
// Stuck on the right side of the switcher.
|
|
translateX = switcherRect.right - optionsElement.clientWidth;
|
|
}
|
|
|
|
// Stuck on the top of the switcher.
|
|
let translateY = switcherRect.top - window.innerHeight - 15;
|
|
|
|
if (isOnTop) {
|
|
// Stuck on the bottom of the switcher.
|
|
translateY = switcherRect.top - window.innerHeight + 150;
|
|
}
|
|
|
|
optionsElement.style.transform = `translate3d(${translateX}px, ${translateY}px, 0)`;
|
|
});
|
|
});
|
|
|
|
|
|
// Dismiss the menu when clicking outside
|
|
document.addEventListener('click', (e) => {
|
|
if (e.target.closest('.hextra-theme-toggle') === null) {
|
|
themeToggleButtons.forEach((toggler) => {
|
|
toggler.dataset.state = 'closed';
|
|
toggler.nextElementSibling.classList.add('hx:hidden');
|
|
});
|
|
}
|
|
});
|
|
|
|
// Listen for system theme changes
|
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
|
|
if (localStorage.getItem("color-theme") === "system") {
|
|
setSystemTheme();
|
|
}
|
|
});
|
|
})();
|