From c61a674289a51c63fd6001880470ea96fafba2ef Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Thu, 21 May 2026 14:42:50 +0200 Subject: [PATCH] improve chat pane styling and layout --- src/app.tsx | 4 ++-- src/components/ChatPane.tsx | 16 +++++++++++++++- src/style.css | 27 +++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/app.tsx b/src/app.tsx index d85d47d..253690f 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -66,7 +66,7 @@ export function App() { let alive = true const poll = () => listSessions().then(s => { if (alive) setSessions(s) }).catch(() => {}) poll() - const id = setInterval(poll, 5000) + const id = setInterval(poll, 250) return () => { alive = false; clearInterval(id) } }, []) @@ -90,7 +90,7 @@ export function App() { } poll() - const id = setInterval(poll, 2000) + const id = setInterval(poll, 250) return () => { alive = false; clearInterval(id) } }, [selectedId]) diff --git a/src/components/ChatPane.tsx b/src/components/ChatPane.tsx index 0675158..499a30d 100644 --- a/src/components/ChatPane.tsx +++ b/src/components/ChatPane.tsx @@ -120,12 +120,20 @@ export function ChatPane({ session, cfg, messages, onSend, onStop, browsePath, b const [atBottom, setAtBottom] = useState(true) const isRunning = !!cfg?.state && cfg.state !== 'idle' && cfg.state !== 'stopped' + const lastLen = messages.length > 0 ? messages[messages.length - 1].content.length : 0 useEffect(() => { if (atBottom && listRef.current) { listRef.current.scrollTop = listRef.current.scrollHeight } - }, [messages.length, isRunning, atBottom]) + }, [messages.length, lastLen, isRunning, atBottom]) + + const scrollToBottom = () => { + if (listRef.current) { + listRef.current.scrollTop = listRef.current.scrollHeight + setAtBottom(true) + } + } useEffect(() => { if (!listRef.current) return @@ -264,6 +272,12 @@ export function ChatPane({ session, cfg, messages, onSend, onStop, browsePath, b )} + {!atBottom && ( + + )} + ) diff --git a/src/style.css b/src/style.css index a7f0046..ab5693c 100644 --- a/src/style.css +++ b/src/style.css @@ -317,6 +317,7 @@ input, select, textarea { font-family: inherit; } overflow: hidden; height: 100%; background: var(--bg); + position: relative; } /* ---- Welcome ---- */ @@ -1075,3 +1076,29 @@ details[open] > .tool-header::before { font-style: italic; color: var(--text-faint); } + +/* ---- Scroll to bottom ---- */ +.scroll-to-bottom { + position: absolute; + bottom: 80px; + left: 50%; + transform: translateX(-50%); + width: 36px; + height: 36px; + border-radius: 50%; + border: 1px solid var(--border); + background: var(--bg-elevated); + color: var(--text-dim); + font-size: 18px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + z-index: 10; + transition: opacity 0.15s, border-color 0.15s; +} +.scroll-to-bottom:hover { + border-color: var(--accent); + color: var(--accent); +}