From 85ed078058ff6c42875405b8ea1d30e2966ca6f1 Mon Sep 17 00:00:00 2001 From: Laura Date: Mon, 3 Nov 2025 00:56:45 +0100 Subject: [PATCH] scroll into view button --- static/css/chat.css | 16 ++++++++++++++++ static/js/chat.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/static/css/chat.css b/static/css/chat.css index f8e9869..ed95e49 100644 --- a/static/css/chat.css +++ b/static/css/chat.css @@ -777,6 +777,21 @@ body:not(.loading) #loading { display: none; } +#messages .message.in-view .scroll-view { + opacity: 0; + pointer-events: none; +} + +#messages .message .scroll-view { + position: absolute; + bottom: 5px; + right: 2px; + background-image: url(icons/up.svg); + width: 14px; + height: 14px; + transition: 150ms; +} + #chat { display: flex; position: relative; @@ -1011,6 +1026,7 @@ body.loading #version, .message .statistics .tps::before, .message .statistics .tokens::before, .message .statistics .cost::before, +.message .scroll-view, #json, #search, #scrolling, diff --git a/static/js/chat.js b/static/js/chat.js index f21ae07..3fbfb08 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -145,6 +145,18 @@ } } + const observer = new IntersectionObserver( + entries => { + for (const entry of entries) { + entry.target.parentElement.classList.toggle("in-view", entry.isIntersecting); + } + }, + { + root: $messages, + threshold: 1.0, + } + ); + class Message { #destroyed = false; @@ -219,6 +231,8 @@ this.#_message.appendChild(_wrapper); + observer.observe(_wrapper); + // message role const _role = make("div"); @@ -231,6 +245,7 @@ _wrapper.appendChild(this.#_tags); + // message body const _body = make("div", "body"); this.#_message.appendChild(_body); @@ -478,6 +493,20 @@ this.#_message.appendChild(this.#_statistics); + // scroll into view + const _scroll = make("button", "scroll-view"); + + _scroll.title = "Scroll message into view"; + + this.#_message.appendChild(_scroll); + + _scroll.addEventListener("click", () => { + this.#_message.scrollIntoView({ + behavior: "smooth", + block: "start", + }); + }); + // add to dom $messages.appendChild(this.#_message);