65 lines
2.1 KiB
JavaScript
65 lines
2.1 KiB
JavaScript
const cvPortrait = document.getElementById('cv-portrait-orbit');
|
|
const siteThemeStorageKey = 'site-theme';
|
|
const legacyCvThemeStorageKey = 'cv-theme';
|
|
|
|
function normalizeSiteTheme(theme) {
|
|
return theme === 'light' || theme === 'fancy' ? 'light' : 'dark';
|
|
}
|
|
|
|
function getStoredSiteTheme() {
|
|
try {
|
|
return localStorage.getItem(siteThemeStorageKey) || localStorage.getItem(legacyCvThemeStorageKey);
|
|
} catch (_error) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function storeSiteTheme(theme) {
|
|
const nextTheme = normalizeSiteTheme(theme);
|
|
try {
|
|
localStorage.setItem(siteThemeStorageKey, nextTheme);
|
|
localStorage.removeItem(legacyCvThemeStorageKey);
|
|
} catch (_error) {
|
|
}
|
|
}
|
|
|
|
function getSiteThemeButtons() {
|
|
return [...document.querySelectorAll('[data-site-theme]')];
|
|
}
|
|
|
|
function setSiteTheme(theme) {
|
|
const nextTheme = normalizeSiteTheme(theme);
|
|
document.documentElement.classList.toggle('theme-light', nextTheme === 'light');
|
|
document.documentElement.classList.toggle('theme-dark', nextTheme === 'dark');
|
|
document.body.classList.toggle('theme-light', nextTheme === 'light');
|
|
document.body.classList.toggle('theme-dark', nextTheme === 'dark');
|
|
|
|
getSiteThemeButtons().forEach((button) => {
|
|
const active = normalizeSiteTheme(button.dataset.siteTheme) === nextTheme;
|
|
button.classList.toggle('is-active', active);
|
|
button.setAttribute('aria-pressed', active ? 'true' : 'false');
|
|
});
|
|
|
|
storeSiteTheme(nextTheme);
|
|
}
|
|
|
|
document.addEventListener('click', (event) => {
|
|
const button = event.target.closest('[data-site-theme]');
|
|
if (!button) return;
|
|
setSiteTheme(button.dataset.siteTheme);
|
|
});
|
|
|
|
document.addEventListener('pointermove', (event) => {
|
|
if (!document.body.classList.contains('theme-light') || !cvPortrait) return;
|
|
|
|
const bounds = cvPortrait.getBoundingClientRect();
|
|
const centerX = bounds.left + bounds.width / 2;
|
|
const centerY = bounds.top + bounds.height / 2;
|
|
const radians = Math.atan2(event.clientY - centerY, event.clientX - centerX);
|
|
const degrees = radians * 180 / Math.PI;
|
|
|
|
cvPortrait.style.setProperty('--portrait-rotation', `${degrees + 8}deg`);
|
|
});
|
|
|
|
setSiteTheme(getStoredSiteTheme() || 'dark');
|