Replace pin button with floating scroll-to-bottom button

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jared Miller 2026-01-30 10:46:34 -05:00
parent 386c1e74cc
commit b67247e340
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

View file

@ -201,36 +201,38 @@
display: block;
}
.pin-scroll-btn {
.scroll-to-bottom-btn {
position: absolute;
bottom: 12px;
right: 12px;
background: rgba(42, 42, 42, 0.9);
border: 1px solid #3a3a3a;
border-radius: 6px;
padding: 8px 12px;
font-size: 16px;
border-radius: 50%;
width: 44px;
height: 44px;
font-size: 20px;
cursor: pointer;
transition: background 0.2s, opacity 0.2s;
transition: background 0.2s, opacity 0.2s, transform 0.2s;
z-index: 10;
min-width: 44px;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.pin-scroll-btn:hover {
.scroll-to-bottom-btn:hover {
background: rgba(58, 58, 58, 0.95);
transform: translateY(-2px);
}
.pin-scroll-btn:active {
.scroll-to-bottom-btn:active {
opacity: 0.7;
transform: translateY(0);
}
.pin-scroll-btn.pinned {
background: rgba(255, 152, 0, 0.2);
border-color: #ff9800;
.scroll-to-bottom-btn.hidden {
opacity: 0;
pointer-events: none;
}
.terminal {
@ -1369,10 +1371,10 @@
</div>
${renderStatsWidget(s)}
<div class="session-output" id="session-output-${s.id}">
<button class="pin-scroll-btn ${s.autoScroll ? 'pinned' : ''}"
onclick="toggleAutoScroll(${s.id}); event.stopPropagation();"
title="${s.autoScroll ? 'Auto-scroll enabled' : 'Auto-scroll disabled'}">
${s.autoScroll ? '📌' : '📍'}
<button class="scroll-to-bottom-btn ${s.autoScroll ? 'hidden' : ''}"
onclick="scrollToBottom(${s.id}); event.stopPropagation();"
title="Scroll to bottom">
</button>
<div class="terminal" id="output-${s.id}">${s.output}</div>
</div>
@ -1400,9 +1402,15 @@
$output.innerHTML += newChunk;
session.outputRenderedLength = session.output.length;
}
const $outputContainer = document.getElementById(`session-output-${sessionId}`);
if ($outputContainer) {
// Only auto-scroll if session is expanded and autoScroll is enabled
if (session.expanded && session.autoScroll) {
$output.parentElement.scrollTop = $output.parentElement.scrollHeight;
$outputContainer.scrollTop = $outputContainer.scrollHeight;
}
// Re-attach scroll listener after DOM update
attachScrollListener(sessionId, $outputContainer);
}
}
}
@ -2108,7 +2116,7 @@
if (session.autoScroll !== isAtBottom) {
session.autoScroll = isAtBottom;
updatePinButton(sessionId);
updateScrollButton(sessionId);
}
};
@ -2116,37 +2124,31 @@
scrollListeners.set(sessionId, listener);
}
window.toggleAutoScroll = (sessionId) => {
window.scrollToBottom = (sessionId) => {
const session = state.sessions.get(sessionId);
if (!session) return;
session.autoScroll = !session.autoScroll;
// If enabling auto-scroll, scroll to bottom immediately
if (session.autoScroll) {
// Scroll to bottom
const $outputContainer = document.getElementById(`session-output-${sessionId}`);
if ($outputContainer) {
$outputContainer.scrollTop = $outputContainer.scrollHeight;
}
}
updatePinButton(sessionId);
// Re-enable auto-scroll
session.autoScroll = true;
updateScrollButton(sessionId);
};
function updatePinButton(sessionId) {
function updateScrollButton(sessionId) {
const session = state.sessions.get(sessionId);
if (!session) return;
const $btn = document.querySelector(`#session-output-${sessionId} .pin-scroll-btn`);
const $btn = document.querySelector(`#session-output-${sessionId} .scroll-to-bottom-btn`);
if ($btn) {
if (session.autoScroll) {
$btn.classList.add('pinned');
$btn.textContent = '📌';
$btn.title = 'Auto-scroll enabled';
$btn.classList.add('hidden');
} else {
$btn.classList.remove('pinned');
$btn.textContent = '📍';
$btn.title = 'Auto-scroll disabled';
$btn.classList.remove('hidden');
}
}
}