The pane waited 150 ms on hover and 60 ms on a keyboard step before following the sidebar highlight, so every preview paid for the fast walk it might have been. Replace both with a leading-edge 120 ms gap: the first move shows at once, a burst is coalesced to its start and its end. The row's own hover no longer eases either — `background` was on a 120 ms transition, which is what read as lag on the row itself. The sidebar also rebuilt its whole tree on every `SessionUpdated`, a couple of times a minute per live session, dropping `:hover` from the row under the pointer. Refreshes that change nothing structural now patch the activity rail and meta line into the standing rows instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
76 lines
3.6 KiB
Markdown
76 lines
3.6 KiB
Markdown
# PREVIEW.md — the sidebar preview contract
|
|
|
|
One rule for what the content pane shows while the operator is only moving
|
|
around the sidebar, so the web client and the TUI behave the same. Read this
|
|
before changing either. If the behaviour needs to change, change it here first.
|
|
|
|
## The rule
|
|
|
|
Highlighting a session in the sidebar shows that session in the content pane,
|
|
as if it were focused, **without focusing it and without changing the layout**.
|
|
Moving the highlight elsewhere puts back exactly what was on screen before.
|
|
|
|
A preview is a view, not a state. Nothing about it is durable:
|
|
|
|
- The layout is byte-for-byte identical before the preview and after it ends.
|
|
- Nothing is persisted while a preview is up (the web client's layout is saved
|
|
to `localStorage`; a preview never reaches it).
|
|
- The daemon is never told the previewed pane is focused, so a preview never
|
|
clears a session's `AwaitingInput` glow (`docs/SIDEBAR.md`).
|
|
- The keyboard stays in the sidebar: the previewed terminal is on screen but
|
|
does not take focus, so the next `j`/`k` still walks the list.
|
|
|
|
## Where the preview is shown
|
|
|
|
| The previewed session is… | What happens |
|
|
|---|---|
|
|
| Already in a pane, in the active tab | That pane comes forward (its tab's focus moves to it). |
|
|
| Already in a pane, in another tab | That tab is brought forward. The active tab is restored when the preview ends. |
|
|
| Not in any pane | A throwaway tab carries it. It is removed when the preview ends. |
|
|
|
|
The throwaway tab never counts as an open session: the tab bar does not appear
|
|
because of it, the mobile shell does not switch away from the session list for
|
|
it, and the sidebar does not mark the session as open.
|
|
|
|
## What ends a preview
|
|
|
|
- The highlight moves to another session — that session is previewed instead.
|
|
- The highlight leaves every session (a folder row, or the list losing the
|
|
keyboard, or the pointer leaving the list): the previous view comes back.
|
|
- Any real layout change (split, close, new tab, tab switch, drag): the preview
|
|
is discarded first, so a throwaway tab is never baked into the arrangement.
|
|
|
|
## What commits a preview
|
|
|
|
Choosing the previewed session — clicking or pressing Enter on its row,
|
|
clicking into its pane, or handing the keyboard to the pane (web: `Tab` from
|
|
the list; TUI: the attach binding) — keeps exactly what is on screen. A
|
|
throwaway tab becomes a real one; a focus move inside an existing tab stands.
|
|
Nothing moves a second time on commit.
|
|
|
|
## Timing
|
|
|
|
**A preview is never delayed.** Landing on a row — by pointer or by `j`/`k` —
|
|
shows it on the next frame, and so does leaving every row. There is no
|
|
settling period in front of the first preview, because that period would sit
|
|
in front of the one preview the operator actually meant.
|
|
|
|
What is bounded is how *often* the pane may swap: at most once per 120 ms.
|
|
A burst inside one window — `j` held down, or the pointer sweeping the length
|
|
of the sidebar — shows the row it started on, then the row it ended on, and
|
|
none of the rows in between. So a walk costs a couple of pane mounts rather
|
|
than one per row, without the operator ever waiting on one.
|
|
|
|
The highlight itself is not bounded by any of this: the row lights up on the
|
|
same frame as the input, whatever the pane behind it is doing.
|
|
|
|
Touch has no hover, and a tap already opens a session, so touch never previews.
|
|
|
|
## Cost
|
|
|
|
A previewed session that no pane holds needs a live attach. Both clients keep
|
|
it connected after the preview ends — the web client parks it in the connection
|
|
pool's LRU, the TUI keeps its emulator until it falls out of the preview
|
|
budget — so stepping back onto a row is instant rather than re-fetching
|
|
scrollback.
|