From f6c061859696a4045f47bf85b1d8c0732c0ab64a Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 1 Jan 2026 21:09:28 +0100 Subject: [PATCH] fix: improve web chat scroll and text --- ui/src/styles/base.css | 2 ++ ui/src/styles/components.css | 1 + ui/src/ui/app-render.ts | 1 + ui/src/ui/app.ts | 12 ++++++++++++ ui/src/ui/controllers/chat.ts | 3 ++- 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ui/src/styles/base.css b/ui/src/styles/base.css index ead5d2893..1cfa2e3ef 100644 --- a/ui/src/styles/base.css +++ b/ui/src/styles/base.css @@ -12,6 +12,7 @@ --chrome: rgba(10, 14, 20, 0.75); --chrome-strong: rgba(10, 14, 20, 0.82); --text: rgba(246, 248, 252, 0.95); + --chat-text: rgba(246, 248, 252, 0.88); --muted: rgba(210, 218, 230, 0.62); --border: rgba(255, 255, 255, 0.08); --accent: #ff7a3d; @@ -40,6 +41,7 @@ --chrome: rgba(255, 255, 255, 0.72); --chrome-strong: rgba(255, 255, 255, 0.82); --text: rgba(20, 24, 36, 0.96); + --chat-text: rgba(20, 24, 36, 0.82); --muted: rgba(50, 58, 76, 0.6); --border: rgba(16, 24, 40, 0.12); --accent: #ff7a3d; diff --git a/ui/src/styles/components.css b/ui/src/styles/components.css index a44e9a824..1c459bed3 100644 --- a/ui/src/styles/components.css +++ b/ui/src/styles/components.css @@ -504,6 +504,7 @@ white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; + color: var(--chat-text); } .chat-stamp { diff --git a/ui/src/ui/app-render.ts b/ui/src/ui/app-render.ts index 61949c540..46d229e7f 100644 --- a/ui/src/ui/app-render.ts +++ b/ui/src/ui/app-render.ts @@ -213,6 +213,7 @@ export function renderApp(state: AppViewState) { onPasswordChange: (next) => (state.password = next), onSessionKeyChange: (next) => { state.sessionKey = next; + state.chatMessage = ""; state.applySettings({ ...state.settings, sessionKey: next }); }, onRefresh: () => state.loadOverview(), diff --git a/ui/src/ui/app.ts b/ui/src/ui/app.ts index 42fb93741..6a9fffdf7 100644 --- a/ui/src/ui/app.ts +++ b/ui/src/ui/app.ts @@ -168,6 +168,7 @@ export class ClawdisApp extends LitElement { client: GatewayBrowserClient | null = null; private chatScrollFrame: number | null = null; + private chatScrollTimeout: number | null = null; private nodesPollInterval: number | null = null; basePath = ""; private popStateHandler = () => this.onPopState(); @@ -202,6 +203,7 @@ export class ClawdisApp extends LitElement { (changed.has("chatMessages") || changed.has("chatStream") || changed.has("chatLoading") || + changed.has("chatMessage") || changed.has("tab")) ) { this.scheduleChatScroll(); @@ -241,11 +243,21 @@ export class ClawdisApp extends LitElement { private scheduleChatScroll() { if (this.chatScrollFrame) cancelAnimationFrame(this.chatScrollFrame); + if (this.chatScrollTimeout != null) { + clearTimeout(this.chatScrollTimeout); + this.chatScrollTimeout = null; + } this.chatScrollFrame = requestAnimationFrame(() => { this.chatScrollFrame = null; const container = this.querySelector(".chat-thread") as HTMLElement | null; if (!container) return; container.scrollTop = container.scrollHeight; + this.chatScrollTimeout = window.setTimeout(() => { + this.chatScrollTimeout = null; + const latest = this.querySelector(".chat-thread") as HTMLElement | null; + if (!latest) return; + latest.scrollTop = latest.scrollHeight; + }, 120); }); } diff --git a/ui/src/ui/controllers/chat.ts b/ui/src/ui/controllers/chat.ts index f5ba40055..b407a3862 100644 --- a/ui/src/ui/controllers/chat.ts +++ b/ui/src/ui/controllers/chat.ts @@ -46,6 +46,7 @@ export async function sendChat(state: ChatState) { if (!msg) return; state.chatSending = true; + state.chatMessage = ""; state.lastError = null; const runId = crypto.randomUUID(); state.chatRunId = runId; @@ -57,10 +58,10 @@ export async function sendChat(state: ChatState) { deliver: false, idempotencyKey: runId, }); - state.chatMessage = ""; } catch (err) { state.chatRunId = null; state.chatStream = null; + state.chatMessage = msg; state.lastError = String(err); } finally { state.chatSending = false;