Replace pin button with floating scroll-to-bottom button
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
386c1e74cc
commit
b67247e340
1 changed files with 40 additions and 38 deletions
|
|
@ -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';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue