Files
2026-05-18 23:07:31 +02:00

243 lines
8.7 KiB
JavaScript

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