mirror of
https://github.com/imfing/hextra.git
synced 2025-08-23 16:36:44 -04:00

* fix(theme-toggle): quick flash (light/dark) * chore: simplify * chore: simplify * chore: simplify
92 lines
2.9 KiB
JavaScript
92 lines
2.9 KiB
JavaScript
// Light / Dark theme toggle
|
|
(function () {
|
|
const defaultTheme = '{{ site.Params.theme.default | default `system`}}'
|
|
const themes = ["light", "dark"];
|
|
|
|
const themeToggleButtons = document.querySelectorAll(".hextra-theme-toggle");
|
|
const themeToggleOptions = document.querySelectorAll(".hextra-theme-toggle-options p");
|
|
|
|
function applyTheme(theme) {
|
|
theme = themes.includes(theme) ? theme : "system";
|
|
|
|
themeToggleButtons.forEach((btn) => btn.parentElement.dataset.theme = theme );
|
|
|
|
localStorage.setItem("color-theme", theme);
|
|
}
|
|
|
|
function switchTheme(theme) {
|
|
setTheme(theme);
|
|
applyTheme(theme);
|
|
}
|
|
|
|
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") {
|
|
setTheme("system");
|
|
}
|
|
});
|
|
})();
|