Reader follow-ups: zoom, the prompt band, where it opens, one composer - #49
Open
lvwerra wants to merge 1 commit into
Open
Reader follow-ups: zoom, the prompt band, where it opens, one composer#49lvwerra wants to merge 1 commit into
lvwerra wants to merge 1 commit into
Conversation
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
force-pushed
the
design/reader-followups
branch
from
August 7, 2026 22:08
516488a to
2fdba8a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Composercomponent. 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) andabove(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: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