décors mid-left au pied des colonnes avec parallax custom
This commit is contained in:
@@ -391,13 +391,19 @@
|
||||
|
||||
const asideProjectMenu = document.querySelector('#block-erabletheme-views-block-projets-block-1 .projets_list');
|
||||
if (asideProjectMenu) {
|
||||
for (let item of asideProjectMenu.children) {
|
||||
const itemTitle = item.innerText;
|
||||
const contentPage = document.querySelector('.projet_full');
|
||||
const contentPageTitle = contentPage.querySelector('h2')?.innerText;
|
||||
|
||||
if (itemTitle.toLowerCase() === contentPageTitle.toLowerCase()) {
|
||||
item.querySelector('a').classList.add('is-active');
|
||||
// Le titre du projet n'est plus rendu dans .projet_full depuis la
|
||||
// refonte (il a été remonté dans .page-header-outside, hors colonne
|
||||
// blanche). On va chercher le titre courant à sa nouvelle place.
|
||||
// Garde sur null + chaîne vide pour éviter l'exception qui plantait
|
||||
// tout le behavior attach (et donc Rellax) sur /projets/<slug>.
|
||||
const headerOutside = document.querySelector('.layout-content .page-header-outside h2');
|
||||
const contentPageTitle = (headerOutside?.innerText || '').trim().toLowerCase();
|
||||
if (contentPageTitle) {
|
||||
for (let item of asideProjectMenu.children) {
|
||||
const itemTitle = (item.innerText || '').trim().toLowerCase();
|
||||
if (itemTitle === contentPageTitle) {
|
||||
item.querySelector('a')?.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,6 +439,133 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Décors mid-left : 0, 1 ou 2 PNG empilés au pied gauche extérieur
|
||||
// de chaque .fullpage interne (pages non-index). Tailles et gaps
|
||||
// proportionnels à colH, bornés min/max. On n'affiche un motif
|
||||
// que si la pile tient sous 50% colH (les deux) ou 30% (un seul),
|
||||
// sinon la forme déborderait dans le contenu en haut.
|
||||
// Position absolue calculée en px dans .layout-container ;
|
||||
// bord droit du PNG calé sur bord gauche colonne via
|
||||
// translateX(-100%). Parallax custom plus bas (sans Rellax).
|
||||
// Visibilité responsive : _background.scss.
|
||||
//
|
||||
const layoutContainer = document.querySelector('.layout-container');
|
||||
const colDecorState = []; // { img1, img2, col }
|
||||
|
||||
function clamp(min, val, max) { return Math.max(min, Math.min(val, max)); }
|
||||
|
||||
function colDecorMetrics(colH) {
|
||||
return {
|
||||
gapBottom: clamp(120, 0.08 * colH, 320),
|
||||
gapBetween: clamp(60, 0.03 * colH, 180),
|
||||
h2: clamp(180, 0.14 * colH, 480),
|
||||
h1: clamp(220, 0.17 * colH, 580),
|
||||
};
|
||||
}
|
||||
|
||||
function createColDecorImg(idx) {
|
||||
const img = document.createElement('img');
|
||||
img.className = `col-decor col-decor-${idx}`;
|
||||
img.setAttribute('aria-hidden', 'true');
|
||||
img.setAttribute('alt', '');
|
||||
img.src = `/themes/erabletheme/assets/new-bg-shapes/mid-left-${idx}.png`;
|
||||
img.style.cssText = 'position:absolute;width:auto;pointer-events:none;z-index:0;transform:translateX(-100%);';
|
||||
return img;
|
||||
}
|
||||
|
||||
function setupColDecor() {
|
||||
if (!layoutContainer) return;
|
||||
layoutContainer.querySelectorAll('.col-decor').forEach(n => n.remove());
|
||||
colDecorState.length = 0;
|
||||
document.querySelectorAll('.fullpage:not(.large-container)').forEach(col => {
|
||||
const img1 = createColDecorImg(1);
|
||||
const img2 = createColDecorImg(2);
|
||||
layoutContainer.appendChild(img1);
|
||||
layoutContainer.appendChild(img2);
|
||||
colDecorState.push({ img1, img2, col });
|
||||
});
|
||||
positionColDecor();
|
||||
}
|
||||
|
||||
function positionColDecor() {
|
||||
if (!colDecorState.length) return;
|
||||
const lcRect = layoutContainer.getBoundingClientRect();
|
||||
const lcTopAbs = lcRect.top + window.scrollY;
|
||||
const lcLeftAbs = lcRect.left + window.scrollX;
|
||||
for (const entry of colDecorState) {
|
||||
const { img1, img2, col } = entry;
|
||||
const r = col.getBoundingClientRect();
|
||||
const colH = r.height;
|
||||
const m = colDecorMetrics(colH);
|
||||
const stack2H = m.gapBottom + m.h2;
|
||||
const stack1H = stack2H + m.gapBetween + m.h1;
|
||||
const showBoth = stack1H <= colH * 0.5;
|
||||
const showOne = !showBoth && stack2H <= colH * 0.3;
|
||||
img1.style.display = showBoth ? 'block' : 'none';
|
||||
img2.style.display = (showBoth || showOne) ? 'block' : 'none';
|
||||
entry.visible1 = showBoth;
|
||||
entry.visible2 = showBoth || showOne;
|
||||
if (!showBoth && !showOne) continue;
|
||||
const colBottomAbs = r.bottom + window.scrollY;
|
||||
const leftRel = (r.left + window.scrollX) - lcLeftAbs;
|
||||
const top2 = colBottomAbs - m.gapBottom - m.h2;
|
||||
img2.style.top = (top2 - lcTopAbs) + 'px';
|
||||
img2.style.left = leftRel + 'px';
|
||||
img2.style.height = m.h2 + 'px';
|
||||
// Référence scroll : motif centré dans le viewport.
|
||||
entry.scrollRef2 = top2 + m.h2 / 2 - window.innerHeight / 2;
|
||||
if (showBoth) {
|
||||
const top1 = top2 - m.gapBetween - m.h1;
|
||||
img1.style.top = (top1 - lcTopAbs) + 'px';
|
||||
img1.style.left = leftRel + 'px';
|
||||
img1.style.height = m.h1 + 'px';
|
||||
entry.scrollRef1 = top1 + m.h1 / 2 - window.innerHeight / 2;
|
||||
}
|
||||
}
|
||||
// Premier rendu du parallax après (re)position.
|
||||
applyColDecorParallax();
|
||||
}
|
||||
|
||||
// Parallax custom (sans Rellax) : remontée subtile, amplitude bornée,
|
||||
// proportionnelle au scroll relatif à la position d'ancrage. À 0.15
|
||||
// de vitesse, pour 100px de scroll au-delà de la référence, le motif
|
||||
// monte de 15px ; clamp à ±30px évite tout débordement.
|
||||
const COL_DECOR_PARALLAX_SPEED = 0.15;
|
||||
const COL_DECOR_PARALLAX_AMP = 30;
|
||||
let colDecorRafPending = false;
|
||||
|
||||
function applyColDecorParallax() {
|
||||
const scrollY = window.scrollY || document.body.scrollTop || 0;
|
||||
for (const { img1, img2, visible1, visible2, scrollRef1, scrollRef2 } of colDecorState) {
|
||||
if (visible2 && scrollRef2 != null) {
|
||||
const dY = clamp(-COL_DECOR_PARALLAX_AMP,
|
||||
-(scrollY - scrollRef2) * COL_DECOR_PARALLAX_SPEED,
|
||||
COL_DECOR_PARALLAX_AMP);
|
||||
img2.style.transform = `translate3d(0, ${dY}px, 0) translateX(-100%)`;
|
||||
}
|
||||
if (visible1 && scrollRef1 != null) {
|
||||
const dY = clamp(-COL_DECOR_PARALLAX_AMP,
|
||||
-(scrollY - scrollRef1) * COL_DECOR_PARALLAX_SPEED,
|
||||
COL_DECOR_PARALLAX_AMP);
|
||||
img1.style.transform = `translate3d(0, ${dY}px, 0) translateX(-100%)`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onColDecorScroll() {
|
||||
if (colDecorRafPending) return;
|
||||
colDecorRafPending = true;
|
||||
requestAnimationFrame(() => {
|
||||
colDecorRafPending = false;
|
||||
applyColDecorParallax();
|
||||
});
|
||||
}
|
||||
if (!document.body.dataset.colDecorScrollWired) {
|
||||
document.body.addEventListener('scroll', onColDecorScroll, { passive: true });
|
||||
document.body.dataset.colDecorScrollWired = 'true';
|
||||
}
|
||||
|
||||
//
|
||||
// Décors latéraux parallax v2.
|
||||
// Cloner le .decor-tile autant de fois que nécessaire pour couvrir
|
||||
@@ -472,15 +605,30 @@
|
||||
rellax = new Rellax('.bgImg', { wrapper: 'body' });
|
||||
}
|
||||
|
||||
// Init initial : frises latérales (basées sur layout-container,
|
||||
// mesure stable même sans images chargées) + Rellax. Les col-decor
|
||||
// sont injectés et positionnés UNIQUEMENT au window.load — leur
|
||||
// position dépend de getBoundingClientRect() de .fullpage qui n'est
|
||||
// fiable qu'une fois toutes les images du contenu chargées (sinon
|
||||
// Rellax cache un blockTop périmé et le motif dérive vers le bas
|
||||
// sur les pages longues).
|
||||
setupBackgroundTiles();
|
||||
initRellax();
|
||||
|
||||
// Resize debouncé : recalcule le nombre de tiles, repart Rellax propre.
|
||||
window.addEventListener('load', () => {
|
||||
setupBackgroundTiles();
|
||||
setupColDecor();
|
||||
initRellax();
|
||||
});
|
||||
|
||||
// Resize debouncé : recalcule le nombre de tiles + col-decor,
|
||||
// repart Rellax propre.
|
||||
let bgResizeTimer = null;
|
||||
window.addEventListener('resize', () => {
|
||||
clearTimeout(bgResizeTimer);
|
||||
bgResizeTimer = setTimeout(() => {
|
||||
setupBackgroundTiles();
|
||||
setupColDecor();
|
||||
initRellax();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user