Skip to content

feat(chat): add resizable transcript width#266

Merged
su-fen merged 3 commits into
Stack-Cairn:mainfrom
AlphaCatMeow:codex/resizable-transcript-width
Jul 26, 2026
Merged

feat(chat): add resizable transcript width#266
su-fen merged 3 commits into
Stack-Cairn:mainfrom
AlphaCatMeow:codex/resizable-transcript-width

Conversation

@AlphaCatMeow

Copy link
Copy Markdown
Contributor

Summary

  • add locally persisted transcript-body width controls to desktop and gateway chat views
  • support bilateral dragging, keyboard resizing, double-click reset, responsive clamping, and coarse-pointer hiding
  • keep the composer width independent and exclude the preference from gateway settings synchronization
  • preserve width-qualified virtualizer measurements and bottom-follow behavior across resize and conversation switches

Validation

  • desktop Tauri runtime: 39 interaction checkpoints, zero mounted-row overlaps
  • gateway browser runtime: verified 1200 px and 800 px transcript widths with a 768 px composer and zero overlaps
  • desktop focused tests: 7/7
  • gateway focused tests: 8/8
  • settings normalization tests: 53/53
  • desktop and gateway production builds
  • mirror check: 105 files
  • staged diff whitespace check

AlphaCatMeow and others added 3 commits July 25, 2026 10:28
- persist the preferred transcript width locally with bilateral resize controls
- preserve virtualized row measurements and bottom-follow behavior across width changes
- mirror the interaction in desktop and gateway clients
Follow-up to the resizable-transcript-width feature, addressing the review
findings without changing the shipped behaviour.

- Extract the column geometry into lib/transcript-width/transcriptWidthModel,
  a dependency-free mirrored leaf. lib/settings now re-exports the bounds from
  there instead of redeclaring them, so the persisted range and the arithmetic
  that enforces it cannot drift.
- Clamp the width from a layout effect rather than a passive one. The host
  element's inline style carries the preferred width and this component
  narrows it to the stage; a passive write landed after paint, flashing the
  unclamped width for a frame whenever a commit had to be clamped. Both call
  sites now document that ownership split.
- Stop re-arming the stage ResizeObserver on every width commit: it reads the
  current width through a ref, so the observer is keyed off the host alone.
- Step keyboard resizes from the rendered width instead of the stored
  preference. With a preference wider than the stage, arrow keys walked a
  value nothing could see and took ~29 presses to move the column.
- Expose one focusable separator to assistive tech. aria-value* is only
  meaningful on a focusable separator, so the left handle is now a pointer-only
  affordance instead of advertising values nothing can focus to change; both
  handles carry the same title.
- Gate the mount on the same media query the CSS uses, via a shared constant,
  so a coarse pointer neither renders the handles nor pays for their listeners.
- Fall back to the upper bound when the stage is unmeasured, instead of
  guessing from window.innerWidth, which also counts the sidebar and dock.
- Route both transcripts through buildTranscriptLayoutKey, which restores the
  zero-width guard the plain-number measurement key used to carry.
- Anchor the scroll-follow opt-out attribute in scrollFollowCore and build the
  selector from it, so the widget and the follow engine share one name.
- Replace the source-regex tests with behaviour tests over the extracted
  model: clamping, stage fallback, drag arithmetic, keyboard stepping and
  layout-key identity. The remaining cross-file assertion derives its expected
  string from the exported constant rather than hardcoding a pattern.

gui tests 1261/1261, gateway webui tests 423/423, both typecheck and build
clean, mirror check 106 files.
@su-fen
su-fen merged commit 18f6ada into Stack-Cairn:main Jul 26, 2026
7 checks passed
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.

2 participants