Merge pull request #274 from kiranjd/fix/chat-scroll-to-bottom
fix(ui): scroll chat to bottom on initial load
This commit is contained in:
@@ -54,6 +54,7 @@
|
|||||||
- Control UI: animate reading indicator dots (honors reduced-motion).
|
- Control UI: animate reading indicator dots (honors reduced-motion).
|
||||||
- Control UI: stabilize chat streaming during tool runs (no flicker/vanishing text; correct run scoping).
|
- Control UI: stabilize chat streaming during tool runs (no flicker/vanishing text; correct run scoping).
|
||||||
- Control UI: let config-form enums select empty-string values. Thanks @sreekaransrinath for PR #268.
|
- Control UI: let config-form enums select empty-string values. Thanks @sreekaransrinath for PR #268.
|
||||||
|
- Control UI: scroll chat to bottom on initial load. Thanks @kiranjd for PR #274.
|
||||||
- Status: show runtime (docker/direct) and move shortcuts to `/help`.
|
- Status: show runtime (docker/direct) and move shortcuts to `/help`.
|
||||||
- Status: show model auth source (api-key/oauth).
|
- Status: show model auth source (api-key/oauth).
|
||||||
- Block streaming: avoid splitting Markdown fenced blocks and reopen fences when forced to split.
|
- Block streaming: avoid splitting Markdown fenced blocks and reopen fences when forced to split.
|
||||||
|
|||||||
@@ -437,25 +437,41 @@ export class ClawdbotApp extends LitElement {
|
|||||||
clearTimeout(this.chatScrollTimeout);
|
clearTimeout(this.chatScrollTimeout);
|
||||||
this.chatScrollTimeout = null;
|
this.chatScrollTimeout = null;
|
||||||
}
|
}
|
||||||
this.chatScrollFrame = requestAnimationFrame(() => {
|
const pickScrollTarget = () => {
|
||||||
this.chatScrollFrame = null;
|
|
||||||
const container = this.querySelector(".chat-thread") as HTMLElement | null;
|
const container = this.querySelector(".chat-thread") as HTMLElement | null;
|
||||||
if (!container) return;
|
if (container) {
|
||||||
const distanceFromBottom =
|
const overflowY = getComputedStyle(container).overflowY;
|
||||||
container.scrollHeight - container.scrollTop - container.clientHeight;
|
const canScroll =
|
||||||
const shouldStick = force || distanceFromBottom < 140;
|
overflowY === "auto" ||
|
||||||
if (!shouldStick) return;
|
overflowY === "scroll" ||
|
||||||
if (force) this.chatHasAutoScrolled = true;
|
container.scrollHeight - container.clientHeight > 1;
|
||||||
container.scrollTop = container.scrollHeight;
|
if (canScroll) return container;
|
||||||
this.chatScrollTimeout = window.setTimeout(() => {
|
}
|
||||||
this.chatScrollTimeout = null;
|
return (document.scrollingElement ?? document.documentElement) as HTMLElement | null;
|
||||||
const latest = this.querySelector(".chat-thread") as HTMLElement | null;
|
};
|
||||||
if (!latest) return;
|
// Wait for Lit render to complete, then scroll
|
||||||
const latestDistanceFromBottom =
|
void this.updateComplete.then(() => {
|
||||||
latest.scrollHeight - latest.scrollTop - latest.clientHeight;
|
this.chatScrollFrame = requestAnimationFrame(() => {
|
||||||
if (!force && latestDistanceFromBottom >= 180) return;
|
this.chatScrollFrame = null;
|
||||||
latest.scrollTop = latest.scrollHeight;
|
const target = pickScrollTarget();
|
||||||
}, 120);
|
if (!target) return;
|
||||||
|
const distanceFromBottom =
|
||||||
|
target.scrollHeight - target.scrollTop - target.clientHeight;
|
||||||
|
const shouldStick = force || distanceFromBottom < 200;
|
||||||
|
if (!shouldStick) return;
|
||||||
|
if (force) this.chatHasAutoScrolled = true;
|
||||||
|
target.scrollTop = target.scrollHeight;
|
||||||
|
const retryDelay = force ? 150 : 120;
|
||||||
|
this.chatScrollTimeout = window.setTimeout(() => {
|
||||||
|
this.chatScrollTimeout = null;
|
||||||
|
const latest = pickScrollTarget();
|
||||||
|
if (!latest) return;
|
||||||
|
const latestDistanceFromBottom =
|
||||||
|
latest.scrollHeight - latest.scrollTop - latest.clientHeight;
|
||||||
|
if (!force && latestDistanceFromBottom >= 250) return;
|
||||||
|
latest.scrollTop = latest.scrollHeight;
|
||||||
|
}, retryDelay);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,7 +705,7 @@ export class ClawdbotApp extends LitElement {
|
|||||||
if (this.tab === "nodes") await loadNodes(this);
|
if (this.tab === "nodes") await loadNodes(this);
|
||||||
if (this.tab === "chat") {
|
if (this.tab === "chat") {
|
||||||
await Promise.all([loadChatHistory(this), loadSessions(this)]);
|
await Promise.all([loadChatHistory(this), loadSessions(this)]);
|
||||||
this.scheduleChatScroll();
|
this.scheduleChatScroll(!this.chatHasAutoScrolled);
|
||||||
}
|
}
|
||||||
if (this.tab === "config") {
|
if (this.tab === "config") {
|
||||||
await loadConfigSchema(this);
|
await loadConfigSchema(this);
|
||||||
|
|||||||
Reference in New Issue
Block a user