156 lines
5.5 KiB
JavaScript
156 lines
5.5 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
const FPS = 60; // Target frames per second for cursor tracking
|
|
|
|
// -------- Video fixed BG ------------------------------
|
|
const reelEl = document.getElementById('reel');
|
|
if (!reelEl) return;
|
|
|
|
const video = reelEl.tagName.toLowerCase() === 'video' ? reelEl : reelEl.querySelector('video');
|
|
if (!video) return;
|
|
|
|
function tryPlay() {
|
|
const playPromise = video.play();
|
|
if (playPromise !== undefined) {
|
|
playPromise.catch(() => {
|
|
// Autoplay bloqué : passer en muet et retenter
|
|
video.muted = true;
|
|
video.play().catch(() => {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
function handleVisibility(visible) {
|
|
console.log('Visibility changed, playing:', visible);
|
|
if (visible) {
|
|
// make visible the video element
|
|
video.style.visibility = 'visible';
|
|
tryPlay();
|
|
} else {
|
|
video.style.visibility = 'hidden';
|
|
video.pause();
|
|
}
|
|
}
|
|
|
|
if ('IntersectionObserver' in window) {
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
handleVisibility(entry.intersectionRatio >= 0.01);
|
|
});
|
|
}, {threshold: [0, 0.01, 1]});
|
|
observer.observe(reelEl);
|
|
} else {
|
|
// Fallback simple : vérification sur scroll/resize
|
|
let ticking = false;
|
|
const check = () => {
|
|
ticking = false;
|
|
const rect = reelEl.getBoundingClientRect();
|
|
const vh = window.innerHeight || document.documentElement.clientHeight;
|
|
// Visible si une partie quelconque est dans la fenêtre
|
|
const visible = rect.bottom > 0 && rect.top < vh;
|
|
handleVisibility(visible);
|
|
};
|
|
const onScroll = () => {
|
|
if (!ticking) {
|
|
ticking = true;
|
|
requestAnimationFrame(check);
|
|
}
|
|
};
|
|
onScroll();
|
|
window.addEventListener('scroll', onScroll, {passive: true});
|
|
window.addEventListener('resize', onScroll);
|
|
}
|
|
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.hidden) video.pause();
|
|
});
|
|
|
|
// Cursor tracking
|
|
//track the cursor position and set CSS variables --cursor-x and --cursor-y on the body element
|
|
let x = 0;
|
|
let y = 0;
|
|
document.addEventListener('mousemove', (e) => {
|
|
x = Math.round(((e.clientX / window.innerWidth) * 2 - 1) * 10000) / 10000;
|
|
y = Math.round(((e.clientY / window.innerHeight) * 2 - 1) * 10000) / 10000;
|
|
});
|
|
|
|
let lastUpdate = 0;
|
|
const FRAME_INTERVAL = 1000 / FPS;
|
|
const updateTwist = (timestamp) => {
|
|
if (!timestamp) timestamp = performance.now();
|
|
if (timestamp - lastUpdate >= FRAME_INTERVAL) {
|
|
document.body.style.setProperty('--cursor-x', x);
|
|
document.body.style.setProperty('--cursor-y', y);
|
|
lastUpdate = timestamp;
|
|
}
|
|
requestAnimationFrame(updateTwist);
|
|
}
|
|
updateTwist();
|
|
|
|
// --------- Init Lenis smooth scroll ------------------------
|
|
// Initialize Lenis
|
|
const lenis = new Lenis({
|
|
autoRaf: true,
|
|
});
|
|
|
|
// Gallery interactions
|
|
// On click on .photo element, toggle the 'full' class
|
|
document.querySelectorAll('.photo').forEach(photoEl => {
|
|
photoEl.addEventListener('click', () => {
|
|
console.log('Photo clicked');
|
|
// get next photo-full element inside the parent div
|
|
let fullPhoto = photoEl.parentElement.querySelector('.photo-full');
|
|
if (!fullPhoto) return;
|
|
fullPhoto.style.display = 'block';
|
|
fullPhoto.addEventListener('click', () => {
|
|
fullPhoto.style.display = 'none';
|
|
})
|
|
});
|
|
});
|
|
|
|
// Accordion functionality
|
|
// Comportement "accordion" : quand un details s'ouvre, fermer les autres
|
|
(function(){
|
|
const faqContainer = document.getElementById('faq');
|
|
if (!faqContainer) return;
|
|
const items = faqContainer.querySelectorAll('details');
|
|
|
|
items.forEach(item => {
|
|
// Mise à jour de l'attribut aria-expanded pour accessibilité
|
|
item.addEventListener('toggle', () => {
|
|
item.querySelector('summary')?.setAttribute('aria-expanded', item.open ? 'true' : 'false');
|
|
if (item.open) {
|
|
items.forEach(other => { if (other !== item) other.removeAttribute('open'); });
|
|
}
|
|
});
|
|
|
|
// Permet Enter / Espace pour déclencher l'ouverture quand summary a le focus
|
|
const summary = item.querySelector('summary');
|
|
summary.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
summary.click();
|
|
}
|
|
});
|
|
});
|
|
})();
|
|
|
|
// Link prefetching on hover
|
|
(function(){
|
|
const prefetchLinks = new Set();
|
|
document.querySelectorAll('a[href]').forEach(link => {
|
|
link.addEventListener('mouseenter', () => {
|
|
const url = link.href;
|
|
if (!prefetchLinks.has(url)) {
|
|
const linkEl = document.createElement('link');
|
|
linkEl.rel = 'prefetch';
|
|
linkEl.href = url;
|
|
document.head.appendChild(linkEl);
|
|
prefetchLinks.add(url);
|
|
}
|
|
});
|
|
});
|
|
})();
|
|
});
|