Files
lichterei-web/assets/js/index.js

155 lines
4.9 KiB
JavaScript

// Lightbox
Array.from(document.querySelectorAll("[data-lightbox]")).forEach(element => {
element.onclick = (e) => {
e.preventDefault();
basicLightbox.create(`<img src="${element.href}">`).show();
};
});
let lastPointerType = "mouse";
window.addEventListener("pointerdown", event => {
lastPointerType = event.pointerType || "mouse";
});
// Central magnetic menu
const menuContainer = document.querySelector("[data-magnetic-menu]");
if (menuContainer) {
const menuItems = Array.from(menuContainer.querySelectorAll(".magnetic-menu__item"));
const hoverRadius = 240;
const shiftStrength = 45;
const spread = 18;
const isHome = document.body.classList.contains("is-home");
const applySpreadOnly = () => {
menuItems.forEach((item, index) => {
const neighborSpread = (index - (menuItems.length - 1) / 2) * spread;
item.style.transform = `translate(${neighborSpread}px, 0px)`;
});
};
const handleMenuPointer = event => {
const pointerX = event?.clientX ?? null;
const pointerY = event?.clientY ?? null;
menuItems.forEach((item, index) => {
const rect = item.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
let offsetX = 0;
let offsetY = 0;
if (pointerX !== null) {
const dx = pointerX - centerX;
const dy = pointerY - centerY;
const distance = Math.hypot(dx, dy);
if (distance < hoverRadius && distance > 0.001) {
const force = 1 - distance / hoverRadius;
offsetX = -(dx / distance) * force * shiftStrength;
offsetY = -(dy / distance) * force * shiftStrength;
}
}
const neighborSpread = (index - (menuItems.length - 1) / 2) * spread;
item.style.transform = `translate(${offsetX + neighborSpread}px, ${offsetY}px)`;
});
};
menuContainer.addEventListener("pointermove", handleMenuPointer);
menuContainer.addEventListener("pointerleave", applySpreadOnly);
applySpreadOnly();
if (isHome) {
const pinMenu = () => {
document.body.classList.add("has-top-menu");
};
menuItems.forEach(item => {
item.addEventListener("pointerdown", pinMenu, { once: true });
item.addEventListener("click", pinMenu, { once: true });
item.addEventListener("touchstart", pinMenu, { once: true });
});
}
}
// Footer magnet hover
const footer = document.querySelector(".footer");
const footerMagnets = footer ? Array.from(footer.querySelectorAll("[data-footer-magnet]")) : [];
if (footer && footerMagnets.length) {
const radius = 240;
const maxOffset = 60;
let pointerX = null;
let pointerY = null;
let rafId = null;
const updateFooterMagnets = () => {
footerMagnets.forEach(item => {
if (pointerX === null || pointerY === null) {
item.style.transform = "";
return;
}
const rect = item.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const dx = centerX - pointerX;
const dy = centerY - pointerY;
const distance = Math.hypot(dx, dy);
if (distance < radius && distance > 0.001) {
const force = 1 - distance / radius;
const offsetX = (dx / distance) * force * maxOffset;
const offsetY = (dy / distance) * force * maxOffset;
item.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
} else {
item.style.transform = "";
}
});
rafId = null;
};
const requestFooterUpdate = () => {
if (rafId === null) {
rafId = requestAnimationFrame(updateFooterMagnets);
}
};
footer.addEventListener("pointermove", event => {
pointerX = event.clientX;
pointerY = event.clientY;
requestFooterUpdate();
});
footer.addEventListener("pointerleave", () => {
pointerX = null;
pointerY = null;
footerMagnets.forEach(item => {
item.style.transform = "";
});
});
}
// Footer image brightness cycle
const footerDimImage = document.querySelector(".footer-dim-image");
if (footerDimImage) {
const brightnessSteps = [1, 0.75, 0.5, 0.25];
let brightnessIndex = Number(footerDimImage.dataset.brightnessIndex || 0);
footerDimImage.style.filter = `brightness(${brightnessSteps[brightnessIndex]})`;
footerDimImage.addEventListener("click", () => {
brightnessIndex = (brightnessIndex + 1) % brightnessSteps.length;
footerDimImage.dataset.brightnessIndex = String(brightnessIndex);
footerDimImage.style.filter = `brightness(${brightnessSteps[brightnessIndex]})`;
if (!document.body.classList.contains("is-blackout") && Math.random() < 0.15) {
document.body.classList.add("is-blackout");
}
});
}
// Blackout toggle based on click
const blackoutOverlay = document.querySelector("[data-blackout-overlay]");
document.addEventListener("pointerdown", () => {
if (document.body.classList.contains("is-blackout")) {
document.body.classList.remove("is-blackout");
}
}, true);