mirror of
https://github.com/ohwgiles/laminar.git
synced 2026-10-06 19:09:03 +00:00
Add sticky auto-scroll for build output
Implements #220 - if the page is scrolled to the very bottom while a build log is streaming, the scroll position "sticks" there and follows new output as it is rendered, like tail -f. Any upward scroll disengages this behaviour, and scrolling back to the bottom re-engages it, so no toggle button is needed. The sticky state is tracked with wheel/scroll event listeners rather than sampled from window.scrollY at render time, because scrolling is handled outside the main thread: while the main thread is busy rendering a large log chunk, window.scrollY may still report the old (bottom) position, which would wrongly yank the page back down and swallow the user's upward scroll. AI-assisted implementation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -669,6 +669,23 @@ const Run = templateId => {
|
|||||||
latestNum: null,
|
latestNum: null,
|
||||||
logComplete: false,
|
logComplete: false,
|
||||||
};
|
};
|
||||||
|
// if the page is scrolled to the bottom, the scroll position "sticks"
|
||||||
|
// there and follows new log output as it is rendered, like tail -f.
|
||||||
|
// Any upward scroll disengages this, scrolling back to the bottom
|
||||||
|
// re-engages it. This must be tracked with event listeners rather than
|
||||||
|
// sampled when rendering, because scrolling is handled outside the main
|
||||||
|
// thread: while the main thread is busy rendering a large log chunk,
|
||||||
|
// window.scrollY may still report the old (bottom) position, which
|
||||||
|
// would wrongly yank the page back down and swallow the user's scroll.
|
||||||
|
let stickToBottom = true;
|
||||||
|
window.addEventListener('wheel', evt => {
|
||||||
|
if (evt.deltaY < 0)
|
||||||
|
stickToBottom = false;
|
||||||
|
});
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
stickToBottom = window.innerHeight + window.scrollY >=
|
||||||
|
document.documentElement.scrollHeight - 1;
|
||||||
|
});
|
||||||
const logFetcher = (vm, name, num) => {
|
const logFetcher = (vm, name, num) => {
|
||||||
const abort = new AbortController();
|
const abort = new AbortController();
|
||||||
fetch('log/'+name+'/'+num, {signal:abort.signal}).then(res => {
|
fetch('log/'+name+'/'+num, {signal:abort.signal}).then(res => {
|
||||||
@@ -705,6 +722,9 @@ const Run = templateId => {
|
|||||||
state.logComplete = true;
|
state.logComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stickToBottom)
|
||||||
|
window.scrollTo(0, document.documentElement.scrollHeight);
|
||||||
|
|
||||||
lastUiUpdate = Date.now();
|
lastUiUpdate = Date.now();
|
||||||
tid = null;
|
tid = null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user