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