Files
2025-05-13 21:24:07 -06:00

111 lines
2.9 KiB
TypeScript

const themeToggleButton = document.getElementById('theme-toggle');
if (themeToggleButton) {
themeToggleButton.addEventListener('click', (e) => {
const root = document.documentElement;
const defaultDark =
window.matchMedia?.('(prefers-color-scheme: dark)').matches ?? true;
const themeAttr = root.getAttribute('data-theme');
const isDark = themeAttr === null ? defaultDark : themeAttr === 'dark';
root.setAttribute('data-theme', isDark ? 'light' : 'dark');
try {
localStorage.setItem('theme', isDark ? 'light' : 'dark');
} catch (e) {
console.error(e);
}
e.preventDefault();
});
}
let tooltipElem: HTMLElement | null = null;
const applyTooltip = (elem: HTMLElement) => {
const text = elem.getAttribute('data-tooltip');
if (!text) {
return;
}
let tooltip = document.getElementById('tooltip');
if (!tooltip) {
tooltip = document.createElement('div');
tooltip.id = 'tooltip';
tooltip.addEventListener('transitionend', (e) => {
if (
e.propertyName === 'opacity' &&
e.target instanceof HTMLElement &&
e.target.style.opacity === '0'
) {
e.target.remove();
}
});
document.body.appendChild(tooltip);
}
tooltip.innerText = text;
tooltip.style.opacity = '1';
const rect = elem.getBoundingClientRect();
const scrollGutter =
document.documentElement.clientWidth - document.body.clientWidth;
const scrollX = window.scrollX - scrollGutter;
let left = rect.left + scrollX + (rect.width - tooltip.offsetWidth) / 2;
const docWidth =
document.documentElement.clientWidth || document.body.clientWidth;
if (left + tooltip.offsetWidth > docWidth) {
left = docWidth - tooltip.offsetWidth;
}
if (left < 0) {
left = 0;
}
let top = rect.top + window.scrollY - tooltip.offsetHeight;
if (top < 0) {
top = rect.bottom + window.scrollY;
}
tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
const arrowLeft = rect.left + scrollX + rect.width / 2 - left;
tooltip.style.setProperty('--arrow-left', `${arrowLeft}px`);
tooltipElem = elem;
};
const removeTooltip = (elem: HTMLElement) => {
if (elem !== tooltipElem) {
return;
}
const tooltip = document.getElementById('tooltip');
if (tooltip) {
tooltip.style.opacity = '0';
}
tooltipElem = null;
};
document.addEventListener(
'mouseover',
(e) => {
if (e.target instanceof HTMLElement) {
applyTooltip(e.target);
}
},
{ passive: true },
);
document.addEventListener(
'mouseout',
(e) => {
if (e.target instanceof HTMLElement) {
removeTooltip(e.target);
}
},
{ passive: true },
);
document.addEventListener(
'touchstart',
(e) => {
if (e.target instanceof HTMLElement) {
applyTooltip(e.target);
}
},
{ passive: true },
);
document.addEventListener(
'touchend',
(e) => {
if (e.target instanceof HTMLElement) {
removeTooltip(e.target);
}
},
{ passive: true },
);