diff --git a/public/s/css/f0ckm.css b/public/s/css/f0ckm.css index 81ddda9..24f08b1 100644 --- a/public/s/css/f0ckm.css +++ b/public/s/css/f0ckm.css @@ -10463,7 +10463,7 @@ body.layout-modern>.pagewrapper:not(:has(.index-layout-wrapper)):not(:has(.item- max-width: none !important; max-height: none !important; width: auto !important; - height: 100% !important; + height: auto !important; border-radius: 2px; animation: modalZoomIn 0.3s cubic-bezier(0.165, 0.84, 0.44, 1); cursor: move !important; @@ -10888,8 +10888,15 @@ body.layout-modern .tag-controls { } @keyframes dm-presence-pulse { - 0%, 100% { box-shadow: 0 0 0 2px rgba(61, 220, 132, 0.25); } - 50% { box-shadow: 0 0 0 4px rgba(61, 220, 132, 0.1); } + + 0%, + 100% { + box-shadow: 0 0 0 2px rgba(61, 220, 132, 0.25); + } + + 50% { + box-shadow: 0 0 0 4px rgba(61, 220, 132, 0.1); + } } /* ── Key notice banner ───────────────────────────────────── */ diff --git a/public/s/js/globalchat.js b/public/s/js/globalchat.js index fce4b31..ac55bd9 100644 --- a/public/s/js/globalchat.js +++ b/public/s/js/globalchat.js @@ -497,14 +497,17 @@ // Embedded images: register with lazy observer; scroll on load only for new messages (not history) node.querySelectorAll('.gchat-embed-img img[data-lazy-src]').forEach(img => { - img.addEventListener('load', () => scrollToBottom(scrollForce)); + // Only snap to bottom on image load for NEW incoming messages, not history. + // History already scrolls once at the end of loadHistory; an extra scroll + // here is what causes the double jump. + if (scrollForce) img.addEventListener('load', () => scrollToBottom(true)); img.addEventListener('click', () => openImgModal(img.src)); img.style.cursor = 'zoom-in'; lazyImgObserver.observe(img); }); - // Also handle already-src'd images (avatars etc.) + // Already-src'd images (avatars etc.) — same rule node.querySelectorAll('.gchat-embed-img img:not([data-lazy-src])').forEach(img => { - img.addEventListener('load', () => scrollToBottom(scrollForce)); + if (scrollForce) img.addEventListener('load', () => scrollToBottom(true)); img.addEventListener('click', () => openImgModal(img.src)); img.style.cursor = 'zoom-in'; }); @@ -529,10 +532,14 @@ const data = await res.json(); if (!data.success) return; const container = document.getElementById('gchat-messages'); - if (container) container.innerHTML = ''; + if (!container) return; + container.innerHTML = ''; (data.messages || []).forEach(m => appendMsg(m, false)); - // One instant snap — images above viewport won't load (lazy) so no layout shift - container.scrollTop = container.scrollHeight; + // Double rAF: wait for the browser to commit the layout (panel just became + // visible from display:none) before reading scrollHeight. + requestAnimationFrame(() => requestAnimationFrame(() => { + container.scrollTop = container.scrollHeight; + })); } catch (e) { console.error('[Chat] Failed to load history:', e); } @@ -636,7 +643,9 @@ if (icon) icon.className = `fa-solid ${isMinimized ? 'fa-chevron-up' : 'fa-chevron-down'}`; if (!isMinimized) { clearUnread(); - loadHistory(); + // Wait one rAF so the panel transitions from display:none to its full + // height before loadHistory measures scrollHeight. + requestAnimationFrame(() => loadHistory()); if (!window.matchMedia('(pointer: coarse)').matches) setTimeout(() => document.getElementById('gchat-input')?.focus(), 150); }