155 lines
4.9 KiB
JavaScript
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);
|