Keep the transcript pinned to the bottom as its content changes
This commit is contained in:
Vendored
+22
-13
@@ -112,6 +112,20 @@ export function mountChat(root, src, makeHead) {
|
||||
const head = h("header", { class: "task-header" });
|
||||
const transcript = h("div", { class: "transcript" });
|
||||
const composer = h("div", { class: "composer" });
|
||||
let stuck = true;
|
||||
const pin = () => {
|
||||
if (stuck) {
|
||||
transcript.scrollTop = transcript.scrollHeight;
|
||||
}
|
||||
};
|
||||
transcript.addEventListener("scroll", () => {
|
||||
stuck = transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight < 80;
|
||||
});
|
||||
transcript.addEventListener("load", pin, true);
|
||||
const resizes = new ResizeObserver(pin);
|
||||
resizes.observe(transcript);
|
||||
const mutations = new MutationObserver(pin);
|
||||
mutations.observe(transcript, { childList: true, subtree: true, characterData: true });
|
||||
const visibleReports = new Map();
|
||||
const acked = new Set();
|
||||
const ackVisible = () => {
|
||||
@@ -171,11 +185,8 @@ export function mountChat(root, src, makeHead) {
|
||||
if (running === !spinner.hidden) {
|
||||
return;
|
||||
}
|
||||
const pinned = transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight < 80;
|
||||
spinner.hidden = !running;
|
||||
if (pinned) {
|
||||
transcript.scrollTop = transcript.scrollHeight;
|
||||
}
|
||||
pin();
|
||||
};
|
||||
const putBefore = (el, anchor) => {
|
||||
if (anchor?.parentNode === transcript) {
|
||||
@@ -235,7 +246,8 @@ export function mountChat(root, src, makeHead) {
|
||||
pending.push(entry);
|
||||
ctx.run = undefined;
|
||||
putBefore(el, spinner);
|
||||
transcript.scrollTop = transcript.scrollHeight;
|
||||
stuck = true;
|
||||
pin();
|
||||
return () => {
|
||||
el.remove();
|
||||
pending = pending.filter((p) => p !== entry);
|
||||
@@ -299,12 +311,9 @@ export function mountChat(root, src, makeHead) {
|
||||
return;
|
||||
}
|
||||
stream.timer = 0;
|
||||
const pinned = transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight < 80;
|
||||
stream.el.hidden = quietReply.startsWith(stream.text.trim());
|
||||
replace(stream.el, markdown(stream.text, "text md", { taskId: ctx.taskId }));
|
||||
if (pinned) {
|
||||
transcript.scrollTop = transcript.scrollHeight;
|
||||
}
|
||||
pin();
|
||||
}, 100);
|
||||
};
|
||||
const openHandoff = () => {
|
||||
@@ -328,7 +337,6 @@ export function mountChat(root, src, makeHead) {
|
||||
return handoff.summary;
|
||||
};
|
||||
const appendEvents = (events) => {
|
||||
const pinned = transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight < 80;
|
||||
let contextChanged = false;
|
||||
headImpl.onEvents?.(events);
|
||||
for (const ev of events) {
|
||||
@@ -407,11 +415,10 @@ export function mountChat(root, src, makeHead) {
|
||||
renderComposer();
|
||||
}
|
||||
}
|
||||
if (pinned) {
|
||||
transcript.scrollTop = transcript.scrollHeight;
|
||||
}
|
||||
pin();
|
||||
};
|
||||
const renderAll = () => {
|
||||
stuck = true;
|
||||
observer.disconnect();
|
||||
visibleReports.clear();
|
||||
dropStream();
|
||||
@@ -450,6 +457,8 @@ export function mountChat(root, src, makeHead) {
|
||||
document.removeEventListener("visibilitychange", ackVisible);
|
||||
headImpl.dispose?.();
|
||||
observer.disconnect();
|
||||
resizes.disconnect();
|
||||
mutations.disconnect();
|
||||
dropStream();
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user