This commit is contained in:
2026-09-29 18:34:51 +02:00
parent 6c813143eb
commit 40ba687970
5 changed files with 260 additions and 63 deletions
+90
View File
@@ -47,6 +47,9 @@ class CommentSystem {
// inline script in header.html (prevents flash). Here we sync the
// container-level class and display state to match.
if (this.container) {
// A slide cut short by navigating away must not leave its border behind
this._legacySlide = null;
document.body.classList.remove('comments-sliding');
const isHidden = localStorage.getItem('comments_hidden') === 'true';
// Force show if hash is present
if (window.location.hash && window.location.hash.startsWith('#c')) {
@@ -4135,6 +4138,16 @@ class CommentSystem {
document.body.classList.contains('comments-hidden') ||
localStorage.getItem('comments_hidden') === 'true';
// Legacy layout: comments slide up behind the info box (and back down out of it)
const reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (document.body.classList.contains('layout-legacy') && typeof this.container.animate === 'function' && !reduceMotion) {
// A slide still running decides the direction, since the classes only flip when it ends
const running = this._legacySlide && this._legacySlide.el === this.container ? this._legacySlide : null;
const hiddenNow = running ? running.dir === 'hide' : isHidden;
this.slideLegacyComments(!hiddenNow, layout, sidebar, siblings);
return;
}
if (isHidden) {
// SHOW: expand grid first, then slide content in
if (layout) layout.classList.remove('sidebar-hidden');
@@ -4170,6 +4183,83 @@ class CommentSystem {
}
}
// Legacy layout slide: the container shrinks from the bottom up while its content moves up by the same
// amount, so the comments look like they retract behind the box above them (reverse on show).
// Pressing again mid-slide turns it around from where it is.
slideLegacyComments(hide, layout, sidebar, siblings) {
const el = this.container;
const kids = Array.from(el.children);
// Curtain feel: slow, soft start, gentle settle at the end
const DURATION = 900;
const EASING = 'cubic-bezier(0.45, 0, 0.2, 1)';
let startH = null;
if (this._legacySlide) {
// Only turn around from mid-slide on the same item; a slide left over from a previous item is dropped
if (this._legacySlide.el === el) startH = el.getBoundingClientRect().height;
this._legacySlide.anims.forEach(a => a.cancel());
this._legacySlide = null;
}
if (!hide) {
// Put it back in the flow first (collapsed), so its full height can be measured
if (layout) layout.classList.remove('sidebar-hidden');
document.body.classList.remove('sidebar-left-hidden', 'comments-hidden');
// Border stays until the comments are fully down again
document.body.classList.add('comments-sliding');
el.classList.remove('is-hidden', 'faded-out');
el.style.removeProperty('display');
if (sidebar) {
sidebar.classList.remove('is-hidden');
sidebar.style.removeProperty('display');
}
siblings.forEach(s => s.classList.remove('faded-out'));
localStorage.setItem('comments_hidden', 'false');
if (startH === null) startH = 0;
} else {
// Mark state immediately so quick navigations stay hidden
localStorage.setItem('comments_hidden', 'true');
document.body.classList.add('comments-sliding');
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';
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)];
kids.forEach(k => anims.push(k.animate(frames(startH, endH), opts)));
const slide = { dir: hide ? 'hide' : 'show', anims, el };
this._legacySlide = slide;
anims[0].onfinish = () => {
if (this._legacySlide !== slide) return;
this._legacySlide = null;
el.style.removeProperty('overflow');
el.style.removeProperty('height');
if (!hide) {
document.body.classList.remove('comments-sliding');
return;
}
el.classList.add('faded-out', 'is-hidden');
el.style.setProperty('display', 'none', 'important');
siblings.forEach(s => s.classList.add('faded-out'));
if (sidebar) {
sidebar.classList.add('is-hidden');
sidebar.style.setProperty('display', 'none', 'important');
}
if (layout) layout.classList.add('sidebar-hidden');
document.body.classList.add('sidebar-left-hidden', 'comments-hidden');
document.body.classList.remove('comments-sliding');
};
}
escapeHtml(unsafe) {