Skip to content

Reader follow-ups: zoom, the prompt band, where it opens, one composer - #49

Open
lvwerra wants to merge 1 commit into
mainfrom
design/reader-followups
Open

Reader follow-ups: zoom, the prompt band, where it opens, one composer#49
lvwerra wants to merge 1 commit into
mainfrom
design/reader-followups

Conversation

@lvwerra

@lvwerra lvwerra commented Aug 7, 2026

Copy link
Copy Markdown
Member

Stacked on #37 — targets design/trace-unify, so the diff is only the follow-ups. Five things found by reading a real session in a real pane.

Zoom reaches the reader. Reader mode covers a terminal whose font the zoom keys scale, so a reader that ignored them made the zoom control look broken. The conversation and the reply line scale (zoom: var(--cx-zoom)); the toolbar and the path footer are chrome and stay put.

The prompt band spans the pane. It reached into the left gutter but stopped at the text column on the right — that asymmetry is what made it read as a card floating over the answer rather than as the head of it. Full bleed both sides, the meta row tight under the band it belongs to, and daylight between exchanges.

Everything opens on the newest turn. Reader mode landed at the top of a 400-turn window — scroll past a month of work to reach the thing you flipped the switch to read. The trace viewer was worse: it opened on page 0. Both land on the last turn now; the viewer does it by the same two-step landing the prompt nav uses, because row heights start as estimates and get corrected as rows measure.

The bottom bar is one height. The mode toggle rendered 19px next to 22px zoom keys.

One composer. The card and reader mode now render the same Composer component. Duplicated markup is how one surface quietly gets a feature and the other does not — which is exactly the risk for #39's screenshot input, so the seam is here: onPasteFiles (paste carrying files, not text) and above (an attachment strip). Until #39 lands neither surface accepts a pasted screenshot — this PR does not implement that feature, it makes wiring it one place instead of two.

While extracting it I found the echo was not actually optimistic: it waited for the POST to return, leaving a beat where the box was still full and nothing had happened. It now goes up immediately and is withdrawn — text restored to the box — if the send fails. Both surfaces.

Verification

tsc --noEmit, npm test (web + server), production build. Then a local harness (web/app-shots.mjs, excluded from the repo like the lab — see §9) drives a running instance for sixteen checks; the ones this PR adds:

PASS  reader mode opens at the newest turn (430/430)
PASS  zoom reaches reader mode (16.0px → 19.2px)
PASS  the bottom bar is one height (zoom 22px, mode 22px)
PASS  the sent prompt appears at the bottom straight away
PASS  the trace viewer opens at the end (935/935)

It also gains web/fixtures.mjs (local, same convention): it writes a Claude transcript and the sessions to read it from, so the pane counts the harness asserts hold on any machine rather than depending on whatever the last run left behind. Two failures in this round were that ambient state, not the app.

🤖 Generated with Claude Code

Six things from reading a real session in a real pane.

**Zoom reaches the reader.** It covers a terminal whose font the zoom keys
scale, so a reader that ignored them made the zoom control look broken. The
conversation and the reply line scale; the toolbar and the path footer are
chrome and stay put.

**The prompt band spans the pane.** It reached into the left gutter but stopped
at the text column on the right, which is what made it read as a card floating
over the answer rather than as the head of it. Full bleed both sides, the meta
row tight under the band it belongs to, and daylight between exchanges.

**Everything opens on the newest turn.** Reader mode landed at the top of a
400-turn window — scroll through a month to reach the thing you flipped the
switch to read. The trace viewer was worse: it opened on page 0. Both land on
the last turn now; the viewer does it by the same two-step the prompt nav uses,
because row heights start as estimates.

**The bottom bar is one height.** The mode toggle was 19px next to 22px keys.

**Nothing of the terminal's paints over the reader.** Its covers — `restoring
last view…`, `starting claude…`, `stopped · output preserved` — are z-index 4
and the overlay was 3, so a reconnect drew the last terminal screen straight
over the conversation, leaving a reader toolbar above a terminal. They are
gated off while reading, and the overlay outranks anything the terminal can
raise. Reported from dev-3; reproduced by injecting the real cover markup.

**One composer, and it is honestly optimistic.** The card and the reader render
the same `Composer` — duplicated markup is how one surface quietly gets a
feature and the other does not. The seam for PR #39's screenshot input is
`onPasteFiles` + `above`; until #39 lands neither surface accepts a pasted
image, and wiring both is then one place. While extracting it: the echo was not
actually optimistic — it waited for the POST, leaving a beat where the box was
still full and nothing had happened. It now goes up first and is withdrawn,
text restored, if the send fails.
@lvwerra
lvwerra force-pushed the design/reader-followups branch from 516488a to 2fdba8a Compare August 7, 2026 22:08
@lvwerra
lvwerra changed the base branch from design/trace-unify to main August 7, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant