mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-20 10:11:58 +00:00
feat(desktop): follow streaming output at bottom + jump-to-bottom button (#45263)
Strict sticky-bottom autoscroll for the chat thread: while the viewport is parked at the bottom, the tail follows content growth (streaming tokens, late measurement, Shiki re-highlight) via a useLayoutEffect keyed on the virtualizer's own size signal, pinned in the same pre-paint pass as its scrollToFn so the two never rubber-band. The gate is a single boolean — one upward pixel (scroll/wheel/touch) disarms follow until the user returns to the bottom. Adds a floating jump-to-bottom control that appears once scrolled ~10px away (above the dim threshold so a sub-pixel settle never flashes it), positioned above the composer with respect to the status stack, with a subtle scale + slide in/out animation that honours prefers-reduced-motion. The button bridges to the virtualizer's re-arm + pin path through a small nanostore emitter. Supersedes #43624.
This commit is contained in:
parent
135fe90166
commit
bbf020e709
8 changed files with 198 additions and 30 deletions
|
|
@ -1255,6 +1255,62 @@ canvas {
|
|||
}
|
||||
}
|
||||
|
||||
/* Floating "jump to bottom" control (see scroll-to-bottom-button.tsx).
|
||||
Directional scale: it contracts toward 1 as it arrives (from 1.1) and keeps
|
||||
contracting to 0.9 as it leaves — always shrinking in the direction of
|
||||
travel, so the motion reads as a soft settle / recede rather than a pop. The
|
||||
X half-offset stays baked into every transform so `left-1/2` centering holds
|
||||
through the animation. */
|
||||
.thread-jump-button {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(0.3rem) scale(0.9);
|
||||
}
|
||||
|
||||
.thread-jump-button[data-state='in'] {
|
||||
animation: thread-jump-in 200ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
|
||||
}
|
||||
|
||||
.thread-jump-button[data-state='out'] {
|
||||
animation: thread-jump-out 180ms ease-in forwards;
|
||||
}
|
||||
|
||||
@keyframes thread-jump-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(0.3rem) scale(1.1);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes thread-jump-out {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0) scale(1);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(0.3rem) scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.thread-jump-button[data-state='in'],
|
||||
.thread-jump-button[data-state='out'] {
|
||||
animation: none;
|
||||
transition: opacity 120ms linear;
|
||||
}
|
||||
|
||||
.thread-jump-button[data-state='in'] {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes code-card-stream-glow {
|
||||
from {
|
||||
border-color: color-mix(in srgb, var(--dt-ring) 18%, var(--ui-stroke-tertiary));
|
||||
|
|
@ -1276,4 +1332,3 @@ canvas {
|
|||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue