A preview moved the active tab's focus, and the sidebar took that as the focused session, so hovering another row dropped the accent from the row the operator had actually opened. Report the pre-preview focus instead.
104 lines
5.3 KiB
Markdown
104 lines
5.3 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.
|
|
|
|
## How a preview reads
|
|
|
|
A preview is provisional, so it never wears the accent — the accent is what
|
|
says "this is the one you picked". It has a hue of its own, and every surface
|
|
involved in the preview carries that same hue, so the pane and the row it came
|
|
from read as one thing rather than two unrelated highlights.
|
|
|
|
Web client (`--preview` and friends in `web/src/styles.css`):
|
|
|
|
| Surface | While previewing |
|
|
|---|---|
|
|
| The previewed pane's titlebar | Tinted in the preview hue, at full strength, in place of the focused pane's accent tint. |
|
|
| The canvas | A `preview` chip, top right, and a dashed inset ring. |
|
|
| A throwaway tab | Dashed border, italic label. |
|
|
| The sidebar row being previewed | Filled with the preview hue, over whatever open state the row already had — but the row of the session already showing in the pane keeps its accent fill, since previewing it changes nothing on screen. |
|
|
| The sidebar row of the session the operator picked | Keeps its accent fill for the whole preview. A preview never moves the accent; only opening another session does. |
|
|
| A hovered sidebar row, and the keyboard cursor on a session | A lighter wash of the same hue, because both are what previews a row. |
|
|
|
|
Rows say it with fill, not with an edge — see the tier ladder in
|
|
`docs/SIDEBAR.md`, which previewing sits at the bottom of. The dashed edges
|
|
belong to the pane: the canvas ring and the throwaway tab.
|
|
|
|
The hue is a palette token, not a fixed colour: a palette whose accent already
|
|
sits on it moves it (`--preview-h`), so "previewing" and "picked" never collide.
|
|
|
|
The TUI marks a preview in text only — the title bar reads `<name> · preview`
|
|
— and has no preview colour role yet.
|
|
|
|
## 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.
|