aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-04 07:30:25 -0700
committerAdam Soltys <[email protected]>2026-08-04 07:30:25 -0700
commit0871281ff921fabf24aba94656dd3c375958a973 (patch)
treeeaf2d2d692b5d2d7ca500aa41786dc02459bf8f5 /src/features
parentd04882474a98e3429d7d4b71a56213c6240c2816 (diff)
downloadcoinosv3-0871281ff921fabf24aba94656dd3c375958a973.tar.gz
coinosv3-0871281ff921fabf24aba94656dd3c375958a973.zip
The chat log follows its bottom edge through viewport resizes
The keyboard shrinks the viewport-sized chat card: the composer stayed on screen but the log kept its old scroll offset, hiding the newest messages. Re-stick on every viewport resize and on composer focus — unless the reader has deliberately scrolled up, which msgStick already remembers. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_015QwAtBSpKvECqp1rHLHjJk
Diffstat (limited to 'src/features')
-rw-r--r--src/features/messages.js16
1 files changed, 16 insertions, 0 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index ae8cb53..6d9217d 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -1251,6 +1251,13 @@ export function messagesFeature(ctx) {
});
};
+ // The chat card is sized to the viewport, so the mobile keyboard shrinks it:
+ // the composer stays on screen, but the log keeps its old scroll offset and
+ // the newest messages vanish under the fold. Follow the bottom edge through
+ // every viewport change (keyboard, rotation, browser chrome) — unless the
+ // user has deliberately scrolled up, which msgStick already remembers.
+ const onViewportResize = () => { if (ui.chatOpen) stickToBottom(); };
+
// A remote signer that a reload dropped: say so where the typing happens,
// rather than letting someone write a message and only then be told. The
// identity itself is still known — it's the ability to sign as it that's
@@ -1282,6 +1289,9 @@ export function messagesFeature(ctx) {
value: ui.msgDraft || '', maxlength: '2000',
onInput: (e) => { ui.msgDraft = e.target.value; if (onType && e.target.value) onType(); },
onKeydown: (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); onSend(); } },
+ // Focus summons the keyboard; some browsers resize only after its
+ // animation, so re-stick once now and once when it has settled.
+ onFocus: () => { stickToBottom(); setTimeout(stickToBottom, 350); },
}),
h('button', { class: 'btn-primary btn-sm', disabled: ui.msgSending, onClick: onSend },
ui.msgSending ? h('span', { class: 'spinner sm' }) : t('msgSend'))));
@@ -1782,6 +1792,12 @@ export function messagesFeature(ctx) {
loadLinkInvite(urlInvite);
setTimeout(() => { ui.chatOpen = true; ui.msgView = 'home'; render(); }, 0);
}
+ window.addEventListener('resize', onViewportResize);
+ window.visualViewport?.addEventListener('resize', onViewportResize);
+ allUnsubs.push(() => {
+ window.removeEventListener('resize', onViewportResize);
+ window.visualViewport?.removeEventListener('resize', onViewportResize);
+ });
startDMs();
// Communities subscribe up front too, not just when chat opens — the
// header's unread dot can't report a room nobody is listening to.