This commit is contained in:
2026-09-29 19:48:29 +02:00
parent 92609a00af
commit ed42b1595c
9 changed files with 760 additions and 227 deletions
+33 -12
View File
@@ -4223,17 +4223,20 @@ class CommentSystem {
if (startH === null) startH = el.getBoundingClientRect().height;
}
el.style.height = 'auto';
const fullH = el.scrollHeight;
const endH = hide ? 0 : fullH;
el.style.overflow = 'hidden';
el.style.height = endH + 'px';
// Height + clipping go through a class and a registered custom property (see f0ckm.css): layouts
// like the Onara modal pin the container with `height: auto !important; overflow: visible
// !important`, which beats both an animated height and an inline overflow. The class rule is
// more specific and !important, and its height reads the variable the animation drives.
el.style.setProperty('--comments-slide-h', endH + 'px');
el.classList.add('is-comments-sliding');
const frames = (h0, h1) => [{ transform: 'translateY(' + (h0 - fullH) + 'px)' }, { transform: 'translateY(' + (h1 - fullH) + 'px)' }];
// A turnaround covers only part of the distance, so it takes proportionally less time (same speed)
const share = fullH > 0 ? Math.abs(endH - startH) / fullH : 1;
const opts = { duration: Math.round(DURATION * Math.max(0.3, Math.min(1, share))), easing: EASING };
const anims = [el.animate([{ height: startH + 'px' }, { height: endH + 'px' }], opts)];
const anims = [el.animate([{ '--comments-slide-h': startH + 'px' }, { '--comments-slide-h': endH + 'px' }], opts)];
kids.forEach(k => anims.push(k.animate(frames(startH, endH), opts)));
const slide = { dir: hide ? 'hide' : 'show', anims, el };
@@ -4241,8 +4244,8 @@ class CommentSystem {
anims[0].onfinish = () => {
if (this._legacySlide !== slide) return;
this._legacySlide = null;
el.style.removeProperty('overflow');
el.style.removeProperty('height');
el.classList.remove('is-comments-sliding');
el.style.removeProperty('--comments-slide-h');
if (!hide) {
document.body.classList.remove('comments-sliding');
return;
@@ -5005,6 +5008,28 @@ class CommentSystem {
}, { once: true });
};
// Bring the whole picker into view with some room below it. Measured once the enter animation has
// finished (mid-animation it is shifted up and slightly squashed, so it would look smaller than it
// is) and scrolled on whatever actually scrolls here (Onara modal, index container or the window).
const revealPicker = () => {
if (!picker || picker.style.display === 'none') return;
let done = false;
const run = () => {
if (done || !picker || picker.style.display === 'none') return;
done = true;
const MARGIN = 24;
const sc = window._f0ckScrollerFor ? window._f0ckScrollerFor(picker) : null;
const view = sc ? sc.getBoundingClientRect() : { top: 0, bottom: window.innerHeight };
const r = picker.getBoundingClientRect();
let delta = r.bottom + MARGIN - view.bottom;
// Never push the picker's own top out of view (very short viewports)
delta = Math.min(delta, r.top - view.top - 8);
if (delta > 0) (sc || window).scrollBy({ top: delta, behavior: 'smooth' });
};
picker.addEventListener('animationend', run, { once: true });
setTimeout(run, 300);
};
trigger.addEventListener('click', (e) => {
e.preventDefault();
@@ -5028,9 +5053,7 @@ class CommentSystem {
picker.offsetHeight; // reflow
picker.style.animation = '';
trigger.classList.add('is-active');
requestAnimationFrame(() => requestAnimationFrame(() =>
picker.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
));
revealPicker();
}
return;
}
@@ -5093,9 +5116,7 @@ class CommentSystem {
}
container.appendChild(picker);
requestAnimationFrame(() => requestAnimationFrame(() =>
picker.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
));
revealPicker();
});
}