90 lines
2.4 KiB
JavaScript
90 lines
2.4 KiB
JavaScript
/**
|
|
* Godspark Refined — Zensical Light JS
|
|
* - Scroll reveal for `.gp-reveal`
|
|
* - Cursor glow via `[gp-glow]` attribute
|
|
* - Reduced-motion safe
|
|
*/
|
|
;(function () {
|
|
"use strict";
|
|
|
|
const prefersReducedMotion = window.matchMedia(
|
|
"(prefers-reduced-motion: reduce)"
|
|
).matches;
|
|
|
|
function initScrollReveal() {
|
|
if (prefersReducedMotion) return;
|
|
|
|
const nodes = document.querySelectorAll(".gp-reveal");
|
|
if (!nodes.length) return;
|
|
|
|
const thresholdRaw = getComputedStyle(document.documentElement)
|
|
.getPropertyValue("--gp-reveal-threshold")
|
|
.trim();
|
|
|
|
const threshold = Number.isFinite(parseFloat(thresholdRaw))
|
|
? parseFloat(thresholdRaw)
|
|
: 0.12;
|
|
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add("is-visible");
|
|
observer.unobserve(entry.target);
|
|
}
|
|
});
|
|
},
|
|
{ threshold, rootMargin: "0px 0px -16px 0px" }
|
|
);
|
|
|
|
nodes.forEach((el) => observer.observe(el));
|
|
}
|
|
|
|
function initCursorGlow() {
|
|
const el = document.documentElement;
|
|
const enabled =
|
|
el.hasAttribute("gp-glow") || el.classList.contains("gp-glow-active");
|
|
|
|
if (!enabled) return;
|
|
if (prefersReducedMotion) return;
|
|
|
|
el.classList.add("gp-glow-active");
|
|
|
|
let raf = false;
|
|
function setGlow(x, y) {
|
|
el.style.setProperty("--gp-cursor-x", x + "px");
|
|
el.style.setProperty("--gp-cursor-y", y + "px");
|
|
}
|
|
|
|
function onMove(e) {
|
|
if (raf) return;
|
|
raf = true;
|
|
requestAnimationFrame(() => {
|
|
const cx = e.touches ? e.touches[0].clientX : e.clientX;
|
|
const cy = e.touches ? e.touches[0].clientY : e.clientY;
|
|
setGlow(cx, cy);
|
|
raf = false;
|
|
});
|
|
}
|
|
|
|
function onHide() { el.style.setProperty("--gp-glow-opacity", "0"); }
|
|
function onShow() { el.style.setProperty("--gp-glow-opacity", "1"); }
|
|
|
|
const passive = { passive: true };
|
|
document.addEventListener("mousemove", onMove, passive);
|
|
document.addEventListener("touchmove", onMove, passive);
|
|
document.addEventListener("mouseleave", onHide);
|
|
document.addEventListener("mouseenter", onShow);
|
|
}
|
|
|
|
function boot() {
|
|
initScrollReveal();
|
|
initCursorGlow();
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", boot);
|
|
} else {
|
|
boot();
|
|
}
|
|
})();
|