Skip to content

feat(desktop): add focused thread mode#2108

Merged
morgmart merged 11 commits into
mainfrom
feat/thread-focus-mode
Jul 19, 2026
Merged

feat(desktop): add focused thread mode#2108
morgmart merged 11 commits into
mainfrom
feat/thread-focus-mode

Conversation

@morgmart

@morgmart morgmart commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • adds a focused thread drawer that makes long agent and human threads the primary work surface while preserving channel context
  • keeps the existing resizable split pane and lets people switch layouts from the thread header or Settings, persisting their preference
  • centers wide thread content, improves drawer motion and chrome, removes message-row hover fills, and prevents channel controls from leaking above focused threads
  • preserves the visible reply and keyboard focus across layout changes, with responsive fallback to the existing narrow-screen presentation

Testing

  • cd desktop && pnpm check
  • cd desktop && pnpm typecheck
  • cd desktop && pnpm test (3,164 tests)
  • cd desktop && pnpm exec playwright test tests/e2e/thread-focus-mode.spec.ts --project=smoke (2 tests)
  • pre-push checks: desktop, Rust, mobile, and Tauri tests

Screenshots

Screen.Recording.2026-07-18.at.7.42.18.PM.mov

morgmart and others added 5 commits July 18, 2026 16:27
A thread is where the work actually happens, but it opened into a 380px
right rail it shared with three other panels — one of four interchangeable
occupants of a peek slot. At 100+ messages of humans and agents working
back and forth, that reads as secondary to the channel that merely holds
its root message.

Focus mode makes the thread a place. A right-anchored drawer overlays the
channel content area, leaving a 72px scrim-dimmed sliver of the channel
visible: orientation ("the channel is where you are, the thread is where
you're focused") plus a tall click target back. The sidebar is never
covered, so channel-hopping stays live.

This is additive. The split pane is preserved exactly and is one setting
away; focus is the default. An Appearance setting picks between them —
in-channel toggling comes later, once the surface itself has settled.

Notes on the pieces:

- Scrim fades toward `background`, not black. A black wash is a multiply:
  it scales text and surface down together, so dark-on-light text keeps
  its contrast ratio and stays readable at any opacity short of a solid
  bar. Fading toward the surface colour compresses text against it
  instead.
- `shadow-panel-left` is a new token. Tailwind's stock shadows are all
  y-offset, so they cast nothing on the drawer's only exposed edge. Both
  layers run -x, following the precedent already set by `content-edge`.
  A left-only border cannot do this job: it tapers out at each rounded
  corner instead of turning it.
- Enter/exit decouple opacity from transform, which a single CSS keyframe
  pair cannot. Front-loading the fade leaves the rest of the enter as pure
  travel — and stops the drawer's own entrance from exposing its contents'
  load order. `AnimatePresence` keeps the drawer mounted through its exit.
- `MessageThreadPanelSkeleton` is extracted because the change pushed
  `MessageThreadPanel` past the file-size guard.
- The screenshot helper gains `--local-storage` and `BUZZ_HEADED=1`.
  Headless Chromium's software rasterizer mis-renders `backdrop-filter`
  under a rounded clip, which the drawer now has; WKWebView is unaffected,
  so this is capture-only.

Co-Authored-By: Claude <noreply@anthropic.com>
* origin/main:
  Route lag-tolerant reads to an optional Postgres read replica (#2084)
  Polish community profile onboarding UI (#2088)
  fix(cli): report presence subject (#2104)
  test(desktop): fix Escape-before-mount race in channel browser e2e (#2101)
  style(desktop): match PendingInviteGate to startup interstitials (#2097)
  Remove additional agents gallery (#2098)
  fix(agents): stop the reply loop and the premature kickoff closer (#2094)
  chore(release): release Buzz Desktop version 0.4.18 (#2091)
  fix(desktop): recover first community joins (#2087)
  fix(chart): support CPU-only relay autoscaling (#2086)
  feat(chart): add relay horizontal autoscaling (#2077)
  fix: recover community access visibility (#2074)
  chore(release): release Buzz Desktop version 0.4.17 (#2082)
  fix(desktop): own native WebSocket lifecycle (#2076)
  fix(desktop): onboarding defaults — API key field and model search (#2081)
  feat(desktop): show agent owners in messages (#2080)
  fix(desktop): restore onboarding provider choices (#2079)
  Fix Claude onboarding terminal popup (#2078)
@morgmart
morgmart requested a review from a team as a code owner July 19, 2026 02:47
@morgmart
morgmart enabled auto-merge (squash) July 19, 2026 04:20
morgmart added 2 commits July 18, 2026 21:43
* origin/main:
  fix(git): carry NIP-OA delegation in auth event (#2120)
  Add native Builderlab auth and community client (#2099)
  Open community creation signup from desktop (#2110)

# Conflicts:
#	desktop/src/features/settings/ui/SettingsPanels.tsx

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving on Wes's behalf after full review in Buzz.

  • CI fully green: all smoke + integration E2E shards, Desktop Core/Build, DCO; branch merged with latest main.
  • Diff matches the stated intent; desktop-only. The one shared-code risk — useAnchoredScroll's mount pin now scrolling in the layout effect with an rAF settling pass (affects every timeline, not just threads) — is covered by the passing scroll-history/timeline-no-shift/virtualization smoke specs, and the unit test was strengthened to assert the new first-frame pin rather than weakened.
  • Solid details: escape-surface counter is fail-safe (idempotent release, tested); split stays the default so existing users see no change; the new spec runs in the smoke project (2 tests, non-vacuous); the skeleton extraction is a real file split rather than a size-guard bump.

Non-blocking nits: useThreadViewModeSwitch locates the thread body via a global data-testid query (DOM coupling — fine while only one thread panel mounts), and the animation-timing comment blocks are much chattier than repo norm.

Reviewed-by: Brain (Buzz agent) on behalf of Wes

@morgmart
morgmart merged commit 2d0bd6e into main Jul 19, 2026
25 checks passed
@morgmart
morgmart deleted the feat/thread-focus-mode branch July 19, 2026 15:55
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