/* ---------------------------------------------------------------- Le Shed — Initialisation 1. Injection des motifs décoratifs (formes vectorielles colorées) 2. Initialisation de Rellax sur les objets décoratifs 3. Parallax custom de la colonne droite : - Les deux colonnes démarrent à la même hauteur (top aligné) - Les deux colonnes finissent à la même hauteur (bottom aligné) - Le translateY est appliqué sur .col__cards (wrapper interne) pour ne pas casser le position:sticky du heading. ---------------------------------------------------------------- */ document.addEventListener('DOMContentLoaded', function () { /* ---- Header compact au scroll + padding-top dynamique ---- */ var masthead = document.querySelector('.masthead'); var layout = document.querySelector('.layout'); var headerSyncing = false; function syncHeaderHeight() { if (!masthead || !layout) return; var h = masthead.offsetHeight; layout.style.paddingTop = h + 'px'; document.documentElement.style.setProperty('--header-h', h + 'px'); } function syncHeaderLoop() { syncHeaderHeight(); syncColHeadingH(); if (headerSyncing) requestAnimationFrame(syncHeaderLoop); } function startHeaderSync() { if (headerSyncing) return; headerSyncing = true; syncHeaderLoop(); setTimeout(function () { headerSyncing = false; syncHeaderHeight(); }, 350); } function syncColHeadingH() { var headingLeft = document.querySelector('.col--left .col__heading'); if (headingLeft) { document.documentElement.style.setProperty('--col-heading-h', headingLeft.offsetHeight + 'px'); } } function onHeaderScroll() { if (!masthead) return; var scrolled = window.scrollY > 20; if (scrolled !== masthead.classList.contains('is-compact')) { masthead.classList.toggle('is-compact', scrolled); startHeaderSync(); } } syncHeaderHeight(); syncColHeadingH(); window.addEventListener('resize', function () { syncHeaderHeight(); syncColHeadingH(); }); window.addEventListener('scroll', onHeaderScroll, { passive: true }); onHeaderScroll(); /* ---- Rellax pour les objets décoratifs uniquement ---- */ function initRellax() { var rellax = new Rellax('[data-rellax-speed]', { center: false, wrapper: null, round: true, vertical: true, horizontal: false }); window.addEventListener('resize', function () { rellax.refresh(); }); } /* ---- Parallax custom colonne droite ---- */ function initColumnParallax() { var colLeft = document.querySelector('.col--left'); var colRight = document.querySelector('.col--right'); var cardsRight = document.querySelector('.col--right .col__cards'); if (!colLeft || !colRight || !cardsRight) return; var titlesRight = Array.from(colRight.querySelectorAll('.col__cards .card__title')); var ticking = false; var dims = {}; var maxScroll = 0; var currentOffset = 0; // top de base des titres sticky (sans parallax) var baseStickyTop = 0; function readBaseStickyTop() { var headerH = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--header-h')) || 80; var headingRight = colRight.querySelector('.col__heading'); var colHeadingH = headingRight ? headingRight.offsetHeight : 35; baseStickyTop = headerH + colHeadingH - 2; } function recalc() { cardsRight.style.transform = ''; titlesRight.forEach(function (t) { t.style.top = ''; }); layout.style.height = ''; dims.leftH = colLeft.offsetHeight; dims.rightH = colRight.offsetHeight; var cs = getComputedStyle(layout); var padTop = parseFloat(cs.paddingTop) || 0; var padBot = parseFloat(cs.paddingBottom) || 0; var minColH = Math.min(dims.leftH, dims.rightH); layout.style.height = (padTop + minColH + padBot) + 'px'; maxScroll = Math.max(1, document.documentElement.scrollHeight - window.innerHeight); readBaseStickyTop(); } function onScroll() { if (!ticking) { ticking = true; requestAnimationFrame(function () { readBaseStickyTop(); var progress = Math.min(1, Math.max(0, window.scrollY / maxScroll)); var delta = dims.leftH - dims.rightH; currentOffset = Math.round(delta * progress); cardsRight.style.transform = 'translateY(' + currentOffset + 'px)'; // Compenser le translateY sur le top des titres sticky // pour qu'ils se collent toujours juste sous "Actions publiques" var correctedTop = baseStickyTop - currentOffset; titlesRight.forEach(function (t) { t.style.top = correctedTop + 'px'; }); ticking = false; }); } } recalc(); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', function () { recalc(); onScroll(); }); onScroll(); } /* ---- Settings panel toggle ---- */ var settingsBtn = document.getElementById('settings-toggle'); var settingsPanel = document.getElementById('settings-panel'); if (settingsBtn && settingsPanel) { settingsBtn.addEventListener('click', function () { settingsPanel.hidden = !settingsPanel.hidden; }); document.addEventListener('click', function (e) { if (!document.getElementById('settings').contains(e.target)) { settingsPanel.hidden = true; } }); } /* ---- Switch motifs ---- */ var rellaxInstance = null; function clearMotifs() { document.querySelectorAll('.objets-layer, .objets2-layer, .paysage-layer').forEach(function (el) { el.remove(); }); if (rellaxInstance) { try { rellaxInstance.destroy(); } catch (e) {} rellaxInstance = null; } } function activateMotif(mode) { clearMotifs(); if (mode === 'paysage' && window.LeShedPaysage) { window.LeShedPaysage.inject().then(function () { rellaxInstance = new Rellax('[data-rellax-speed]', { center: false, round: true, vertical: true, horizontal: false }); }); } else if (mode === 'objets' && window.LeShedObjets) { window.LeShedObjets.inject().then(function () { rellaxInstance = new Rellax('[data-rellax-speed]', { center: false, round: true, vertical: true, horizontal: false }); }); } else if (mode === 'objets2' && window.LeShedObjets2) { window.LeShedObjets2.inject().then(function () { rellaxInstance = new Rellax('[data-rellax-speed]', { center: false, round: true, vertical: true, horizontal: false }); }); } } document.querySelectorAll('input[name="motifs"]').forEach(function (radio) { radio.addEventListener('change', function () { if (radio.checked) activateMotif(radio.value); }); }); /* ---- Couleur motifs ---- */ var couleurCustomInput = document.getElementById('couleur-custom'); function applyMotifColor(value) { var color = value === 'custom' ? couleurCustomInput.value : value; document.documentElement.style.setProperty('--motif-color', color); } document.querySelectorAll('input[name="couleur"]').forEach(function (radio) { radio.addEventListener('change', function () { if (radio.checked) applyMotifColor(radio.value); }); }); if (couleurCustomInput) { couleurCustomInput.addEventListener('input', function () { var customRadio = document.querySelector('input[name="couleur"][value="custom"]'); if (customRadio) customRadio.checked = true; applyMotifColor('custom'); }); } /* ---- Boot ---- */ document.querySelectorAll('input[name="motifs"]').forEach(function (r) { r.checked = r.value === 'objets2'; }); document.querySelectorAll('input[name="couleur"]').forEach(function (r) { r.checked = r.value === '#1a1a1a'; }); applyMotifColor('#1a1a1a'); activateMotif('objets2'); initColumnParallax(); });