/* about.js : interactions propres à la page « Qui suis-je » - terminal : la commande se tape lettre par lettre, puis les lignes de la fiche apparaissent - portrait : légère inclinaison 3D qui suit la souris - parcours : la ligne de la frise se remplit selon le scroll Mode capture ?ybstatic=1 : tout est affiché d'emblée. */ (function () { const STATIC = document.documentElement.classList.contains('yb-static'); const TOUCH = matchMedia('(pointer: coarse)').matches; /* Terminal tapé */ const term = document.querySelector('[data-type]'); if (term) { const cmd = term.querySelector('[data-type-cmd]'), rows = [...term.querySelectorAll('[data-type-row]')]; const full = cmd ? cmd.textContent : ''; if (STATIC) rows.forEach(r => r.classList.add('is-typed')); else { if (cmd) cmd.textContent = ''; const io = new IntersectionObserver(es => es.forEach(en => { if (!en.isIntersecting) return; io.disconnect(); let i = 0; const type = () => { if (cmd && i <= full.length) { cmd.textContent = full.slice(0, i++); return setTimeout(type, 45 + Math.random() * 40); } rows.forEach((r, k) => setTimeout(() => r.classList.add('is-typed'), 180 + k * 160)); }; setTimeout(type, 300); }), { threshold: 0.45 }); io.observe(term); } } /* Portrait incliné à la souris */ const frame = document.querySelector('[data-tilt]'); if (frame && !STATIC && !TOUCH) { const fig = frame.parentElement; fig.addEventListener('mousemove', e => { const r = frame.getBoundingClientRect(); const x = (e.clientX - r.left) / r.width - 0.5, y = (e.clientY - r.top) / r.height - 0.5; frame.style.setProperty('--ry', (x * 10).toFixed(2) + 'deg'); frame.style.setProperty('--rx', (-y * 10).toFixed(2) + 'deg'); }); fig.addEventListener('mouseleave', () => { frame.style.setProperty('--ry', '0deg'); frame.style.setProperty('--rx', '0deg'); }); } /* Frise du parcours */ const tl = document.querySelector('[data-timeline]'); if (tl && !STATIC) { const fill = tl.querySelector('.qs-tl__fill'); const tick = () => { const r = tl.getBoundingClientRect(); const p = Math.max(0, Math.min(1, (innerHeight * 0.6 - r.top) / r.height)); fill.style.height = (p * 100).toFixed(1) + '%'; requestAnimationFrame(tick); }; requestAnimationFrame(tick); } })();