Files
floorithardwoodfloors.com/assets/js/main.js
T
Concept Agent 9907a2ab7d update
2026-05-07 11:45:16 +02:00

165 lines
5.4 KiB
JavaScript

/* ============================================================
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();
}
})();