Files
Linus-Torvalds-Homepage/script.js
T
2026-03-01 00:08:33 +01:00

84 lines
3.0 KiB
JavaScript

(() => {
// wrap content into .inner for independent inner animation
document.querySelectorAll('.timeline .content').forEach((c) => {
if (!c.querySelector('.inner')) {
const wrap = document.createElement('div');
wrap.className = 'inner';
wrap.innerHTML = c.innerHTML;
c.innerHTML = '';
c.appendChild(wrap);
}
});
// delegate clicks for toggles
document.addEventListener('click', (e) => {
const btn = e.target.closest('.toggle');
if (!btn) return;
const content = btn.nextElementSibling;
if (!content) return;
toggle(content, btn);
});
function toggle(content, button) {
const isOpen = content.classList.contains('open');
// ensure we have an inner element
const inner = content.querySelector('.inner') || content;
// measure current height
const computed = getComputedStyle(content);
const startHeight = parseFloat(computed.height) || 0;
// freeze current height so transition starts from visual state
content.style.height = startHeight + 'px';
if (isOpen) {
// close: remove open class to start inner exit animation, then collapse height
content.classList.remove('open');
button.setAttribute('aria-expanded', 'false');
content.setAttribute('aria-hidden', 'true');
// after paint, animate height to 0
requestAnimationFrame(() => {
// start from the frozen pixel height
content.style.height = startHeight + 'px';
requestAnimationFrame(() => {
content.style.height = '0px';
});
});
const onEnd = (ev) => {
if (ev.propertyName !== 'height') return;
content.style.height = '';
content.removeEventListener('transitionend', onEnd);
};
content.addEventListener('transitionend', onEnd);
} else {
// open: add class first so computed scrollHeight includes padding/margins
button.setAttribute('aria-expanded', 'true');
content.setAttribute('aria-hidden', 'false');
// ensure starting height (likely 0)
content.style.height = startHeight + 'px';
// paint, add class, then measure target height
requestAnimationFrame(() => {
content.classList.add('open');
requestAnimationFrame(() => {
const target = content.scrollHeight;
content.style.height = target + 'px';
const onEnd = (ev) => {
if (ev.propertyName !== 'height') return;
content.style.height = '';
content.removeEventListener('transitionend', onEnd);
};
content.addEventListener('transitionend', onEnd);
});
});
}
}
})();