Mode clair / sombre et thèmes de saison
This commit is contained in:
parent
da05adede1
commit
17cf2c8380
19 changed files with 3563 additions and 0 deletions
57
assets/js/about.js
Normal file
57
assets/js/about.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* 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);
|
||||
}
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue