From 3d5d9a05eaf861d7f1711ed34937159b83d3f67b Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Sun, 17 May 2026 12:58:26 +0200 Subject: [PATCH] feat(17): cap discussion height at 32rem with auto-scroll to latest message - #discussion-messages: max-height 32rem, overflow-y auto, smooth scroll - Auto-scroll to bottom on initial load, on own message sent (htmx:afterRequest), and on SSE message received from other users Co-Authored-By: Claude Sonnet 4.6 (1M context) --- backend/internal/web/ui/app.css | 6 ++++++ backend/static/discussion-sse.js | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/backend/internal/web/ui/app.css b/backend/internal/web/ui/app.css index 518de05..bd3c3b3 100644 --- a/backend/internal/web/ui/app.css +++ b/backend/internal/web/ui/app.css @@ -706,6 +706,12 @@ Section 26 — Discussion message bubbles (Phase 17) ============================================================ */ +#discussion-messages { + max-height: 32rem; + overflow-y: auto; + scroll-behavior: smooth; +} + .message-row { display: flex; flex-direction: column; diff --git a/backend/static/discussion-sse.js b/backend/static/discussion-sse.js index 7834be2..56a6e91 100644 --- a/backend/static/discussion-sse.js +++ b/backend/static/discussion-sse.js @@ -38,6 +38,11 @@ return list; } + function scrollToBottom(container) { + var messages = container.querySelector("#discussion-messages"); + if (messages) messages.scrollTop = messages.scrollHeight; + } + function appendMessage(container, event) { if (!event || !event.messageId || !event.messageHtml || messageExists(event.messageId)) { return; @@ -54,6 +59,7 @@ var template = document.createElement("template"); template.innerHTML = event.messageHtml.trim(); list.appendChild(template.content); + scrollToBottom(container); } function connectDiscussion(container) { @@ -62,6 +68,7 @@ var streamURL = container.dataset.discussionStreamUrl; if (!streamURL || !window.EventSource) return; + scrollToBottom(container); container.dataset.discussionStreamConnected = "true"; var source = new EventSource(streamURL); source.addEventListener("discussion-message", function (message) { @@ -95,5 +102,8 @@ form.reset(); var textarea = form.querySelector("#discussion-message-body"); if (textarea) textarea.value = ""; + + var tab = form.closest("[data-discussion-stream-url]"); + if (tab) scrollToBottom(tab); }); })();