89 lines
2.7 KiB
JavaScript
89 lines
2.7 KiB
JavaScript
/* ========================================
|
||
GreenLens Landing Page – Interactions
|
||
======================================== */
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
|
||
// --- Navbar scroll effect ---
|
||
const navbar = document.querySelector('.navbar');
|
||
const handleScroll = () => {
|
||
navbar.classList.toggle('scrolled', window.scrollY > 60);
|
||
};
|
||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||
handleScroll();
|
||
|
||
// --- Mobile hamburger ---
|
||
const hamburger = document.querySelector('.nav-hamburger');
|
||
const navLinks = document.querySelector('.nav-links');
|
||
|
||
if (hamburger) {
|
||
hamburger.addEventListener('click', () => {
|
||
navLinks.classList.toggle('active');
|
||
});
|
||
|
||
// close on link click
|
||
navLinks.querySelectorAll('a').forEach(link => {
|
||
link.addEventListener('click', () => {
|
||
navLinks.classList.remove('active');
|
||
});
|
||
});
|
||
}
|
||
|
||
// --- Scroll reveal ---
|
||
const revealElements = document.querySelectorAll('.reveal');
|
||
|
||
const revealObserver = new IntersectionObserver((entries) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.add('active');
|
||
revealObserver.unobserve(entry.target);
|
||
}
|
||
});
|
||
}, {
|
||
threshold: 0.15,
|
||
rootMargin: '0px 0px -50px 0px'
|
||
});
|
||
|
||
revealElements.forEach(el => revealObserver.observe(el));
|
||
|
||
// --- Counter animation ---
|
||
const counters = document.querySelectorAll('[data-count]');
|
||
const counterObserver = new IntersectionObserver((entries) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting) {
|
||
const el = entry.target;
|
||
const target = parseFloat(el.dataset.count);
|
||
const suffix = el.dataset.suffix || '';
|
||
const isDecimal = target % 1 !== 0;
|
||
const duration = 1500;
|
||
const start = performance.now();
|
||
|
||
const step = (now) => {
|
||
const progress = Math.min((now - start) / duration, 1);
|
||
const eased = 1 - Math.pow(1 - progress, 3); // ease-out cubic
|
||
const current = eased * target;
|
||
el.textContent = (isDecimal ? current.toFixed(1) : Math.floor(current)) + suffix;
|
||
if (progress < 1) requestAnimationFrame(step);
|
||
};
|
||
|
||
requestAnimationFrame(step);
|
||
counterObserver.unobserve(el);
|
||
}
|
||
});
|
||
}, { threshold: 0.5 });
|
||
|
||
counters.forEach(el => counterObserver.observe(el));
|
||
|
||
// --- Smooth scroll for anchor links ---
|
||
document.querySelectorAll('a[href^="#"]').forEach(link => {
|
||
link.addEventListener('click', (e) => {
|
||
const target = document.querySelector(link.getAttribute('href'));
|
||
if (target) {
|
||
e.preventDefault();
|
||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||
}
|
||
});
|
||
});
|
||
|
||
});
|