update
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
/* ============================================================
|
||||
main.js — Scroll animations, counters, FAQ, BA slider
|
||||
============================================================ */
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/* --- Scroll animation (IntersectionObserver) ------------ */
|
||||
function initScrollAnimations() {
|
||||
const els = document.querySelectorAll('[data-animate]');
|
||||
if (!els.length) return;
|
||||
|
||||
const obs = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.classList.add('in-view');
|
||||
obs.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' });
|
||||
|
||||
els.forEach(el => obs.observe(el));
|
||||
}
|
||||
|
||||
/* --- Animated counters ---------------------------------- */
|
||||
function animateCounter(el) {
|
||||
const target = parseFloat(el.dataset.count);
|
||||
const suffix = el.dataset.suffix || '';
|
||||
const prefix = el.dataset.prefix || '';
|
||||
const decimals = (target % 1 !== 0) ? 1 : 0;
|
||||
const duration = 1600;
|
||||
const start = performance.now();
|
||||
|
||||
function tick(now) {
|
||||
const elapsed = now - start;
|
||||
const progress = Math.min(elapsed / duration, 1);
|
||||
const ease = 1 - Math.pow(1 - progress, 3);
|
||||
const value = target * ease;
|
||||
el.textContent = prefix + value.toFixed(decimals) + suffix;
|
||||
if (progress < 1) requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
function initCounters() {
|
||||
const counters = document.querySelectorAll('[data-count]');
|
||||
if (!counters.length) return;
|
||||
|
||||
const obs = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
animateCounter(entry.target);
|
||||
obs.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.3 });
|
||||
|
||||
counters.forEach(el => obs.observe(el));
|
||||
}
|
||||
|
||||
/* --- FAQ accordion -------------------------------------- */
|
||||
function initFAQ() {
|
||||
document.querySelectorAll('.faq-item').forEach(item => {
|
||||
const q = item.querySelector('.faq-question');
|
||||
if (!q) return;
|
||||
|
||||
q.addEventListener('click', () => {
|
||||
const isOpen = item.classList.contains('open');
|
||||
// close all
|
||||
document.querySelectorAll('.faq-item.open').forEach(i => {
|
||||
i.classList.remove('open');
|
||||
});
|
||||
if (!isOpen) item.classList.add('open');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* --- Before / After slider ------------------------------ */
|
||||
function initBASlider(slider) {
|
||||
const handle = slider.querySelector('.ba-handle');
|
||||
const beforeWrap = slider.querySelector('.ba-before-wrap');
|
||||
if (!handle || !beforeWrap) return;
|
||||
|
||||
let dragging = false;
|
||||
|
||||
function setPosition(clientX) {
|
||||
const rect = slider.getBoundingClientRect();
|
||||
const rawPct = (clientX - rect.left) / rect.width;
|
||||
const pct = Math.min(Math.max(rawPct, 0.02), 0.98);
|
||||
beforeWrap.style.width = (pct * 100) + '%';
|
||||
handle.style.left = (pct * 100) + '%';
|
||||
}
|
||||
|
||||
handle.addEventListener('mousedown', () => { dragging = true; });
|
||||
handle.addEventListener('touchstart', () => { dragging = true; }, { passive: true });
|
||||
|
||||
window.addEventListener('mousemove', e => { if (dragging) setPosition(e.clientX); });
|
||||
window.addEventListener('touchmove', e => { if (dragging) setPosition(e.touches[0].clientX); }, { passive: true });
|
||||
|
||||
window.addEventListener('mouseup', () => { dragging = false; });
|
||||
window.addEventListener('touchend', () => { dragging = false; });
|
||||
|
||||
slider.addEventListener('click', e => setPosition(e.clientX));
|
||||
}
|
||||
|
||||
function initBASliders() {
|
||||
document.querySelectorAll('.ba-slider').forEach(initBASlider);
|
||||
}
|
||||
|
||||
/* --- Smooth scroll for anchor links --------------------- */
|
||||
function initSmoothScroll() {
|
||||
document.querySelectorAll('a[href^="#"]').forEach(a => {
|
||||
a.addEventListener('click', e => {
|
||||
const id = a.getAttribute('href').slice(1);
|
||||
const target = document.getElementById(id);
|
||||
if (!target) return;
|
||||
e.preventDefault();
|
||||
const headerH = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-h')) || 72;
|
||||
const top = target.getBoundingClientRect().top + window.scrollY - headerH - 16;
|
||||
window.scrollTo({ top, behavior: 'smooth' });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* --- Video hero fallback -------------------------------- */
|
||||
function initHeroVideo() {
|
||||
const video = document.querySelector('.hero-video-wrap video');
|
||||
if (!video) return;
|
||||
video.play().catch(() => {
|
||||
// autoplay blocked — poster image is visible; nothing to do
|
||||
});
|
||||
}
|
||||
|
||||
/* --- Testimonial auto-scroll (on mobile) ---------------- */
|
||||
function initTestimonialScroll() {
|
||||
const track = document.querySelector('.testimonial-track');
|
||||
if (!track) return;
|
||||
|
||||
let isPaused = false;
|
||||
track.addEventListener('mouseenter', () => { isPaused = true; });
|
||||
track.addEventListener('mouseleave', () => { isPaused = false; });
|
||||
|
||||
// keyboard scroll within track
|
||||
track.setAttribute('tabindex', '0');
|
||||
}
|
||||
|
||||
/* --- Boot ---------------------------------------------- */
|
||||
function boot() {
|
||||
initScrollAnimations();
|
||||
initCounters();
|
||||
initFAQ();
|
||||
initBASliders();
|
||||
initSmoothScroll();
|
||||
initHeroVideo();
|
||||
initTestimonialScroll();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', boot);
|
||||
} else {
|
||||
boot();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user