CarDentIQ / static /js /ui.js
parthmax24's picture
added the latest updates
81b4246
Raw
History Blame Contribute Delete
3.35 kB
// Developer: Saksham Pathak (github.com/parthmax2)
// Shared UI behaviors: nav scroll state, cursor glow, magnetic buttons,
// staggered scroll-reveal, animated stat counters.
function initNavScroll() {
const navbar = document.querySelector(".navbar");
if (!navbar) return;
const update = () => navbar.classList.toggle("navbar-scrolled", window.scrollY > 10);
update();
window.addEventListener("scroll", update, { passive: true });
}
function initCursorGlow() {
if (!window.matchMedia("(hover: hover) and (pointer: fine)").matches) return;
const glow = document.createElement("div");
glow.className = "cursor-glow";
document.body.appendChild(glow);
window.addEventListener("mousemove", (e) => {
glow.style.setProperty("--x", `${e.clientX}px`);
glow.style.setProperty("--y", `${e.clientY}px`);
});
}
function initMagneticButtons() {
const strength = 0.25;
document.querySelectorAll(".btn-primary, .btn-secondary").forEach((btn) => {
btn.addEventListener("mousemove", (e) => {
const rect = btn.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
btn.style.transform = `translate(${x * strength}px, ${y * strength}px)`;
});
btn.addEventListener("mouseleave", () => { btn.style.transform = ""; });
});
}
// Assigns a stagger index (--i) to each .reveal within a group, then reveals
// elements as they cross the viewport.
function initStaggerReveal() {
document.querySelectorAll(".reveal-group").forEach((group) => {
Array.from(group.children).forEach((child, i) => {
if (child.classList.contains("reveal")) child.style.setProperty("--i", i);
});
});
const items = document.querySelectorAll(".reveal:not(.reveal-visible)");
if (!("IntersectionObserver" in window)) {
items.forEach((el) => el.classList.add("reveal-visible"));
return;
}
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("reveal-visible");
observer.unobserve(entry.target);
}
});
}, { threshold: 0.15 });
items.forEach((el) => observer.observe(el));
}
function initCounters() {
const counters = document.querySelectorAll("[data-count-to]");
if (counters.length === 0) return;
const animate = (el) => {
const target = parseFloat(el.dataset.countTo);
const decimals = el.dataset.countTo.includes(".") ? el.dataset.countTo.split(".")[1].length : 0;
const suffix = el.dataset.countSuffix || "";
const duration = 1400;
const start = performance.now();
function tick(now) {
const progress = Math.min((now - start) / duration, 1);
const eased = 1 - Math.pow(1 - progress, 3);
el.textContent = (target * eased).toFixed(decimals) + suffix;
if (progress < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
};
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
animate(entry.target);
observer.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
counters.forEach((el) => observer.observe(el));
}
initNavScroll();
initCursorGlow();
initMagneticButtons();
initStaggerReveal();
initCounters();