Skip to content

Refine light-mode sidebar surfaces#4268

Merged
juliusmarminge merged 25 commits into
mainfrom
t3code/fix-lightmode-sidebar
Jul 22, 2026
Merged

Refine light-mode sidebar surfaces#4268
juliusmarminge merged 25 commits into
mainfrom
t3code/fix-lightmode-sidebar

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Jul 22, 2026

Copy link
Copy Markdown
Member

Summary

  • Refine light-mode sidebar surfaces with clearer rail, card, selection, and hover treatments.
  • Improve contrast for sidebar text, controls, project filters, settled-thread indicators, and separators.
  • Preserve the existing dark-mode appearance while simplifying settled-thread reset handling.

Testing

  • Not run.

Note

Medium Risk
Touches primary navigation (mobile home/sidebar and web sidebar v2) and list filtering across v1/v2 code paths; behavior is mostly UI but incorrect scoping or header menu staleness would confuse users.

Overview
Mobile moves project scoping from inline chips into the home header filter menu (Android + iOS), wires that selection through HomeRouteScreen / HomeScreen, and applies it to both the legacy grouped list and Thread List v2. When Thread List v2 is on, sort/group controls are hidden because the list ignores them; the filter “customized” state only reflects environment and project. The iPad navigation sidebar gains the same v2 flat list (pending tasks, settle/unsettle, paged settled tail) and project filter behavior as home. Thread List v2 rows shift to flat edge-to-edge styling on phone, sidebar-style rounded rows on iPad, optional environment labels on multi-connection setups, and compact swipe actions for slim rows. NativeStackScreenOptions adds optionsVersion so native header menus refresh when async filter data loads.

Web refines Sidebar v2: shared row hover/selection tokens, rich hover tooltips (project, env, branch, model, errors), project filter as a dropdown instead of horizontal chips, and aligned status colors with mobile. Command palette assigns thread.jump.19 to the first nine visible project actions and executes them from the search input. Sidebar chrome, command dialog, composer, and related components get light/dark surface and contrast tweaks (sidebar-row-*, inset rings in dark mode, data-sidebar-version on the app sidebar).

Reviewed by Cursor Bugbot for commit 89830a0. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Refine light-mode sidebar surfaces with zinc-based tokens and sidebar-specific color roles

  • Overhauls the light/dark palette in index.css to use zinc-based background tokens and introduces explicit sidebar role variables (--color-sidebar*, --color-surface-raised, sidebar row hover/active/selected colors).
  • Updates sidebar UI components (SidebarV2, AppSidebarLayout, SidebarChrome, SettingsSidebarNav, sidebar.tsx) to consume the new sidebar-scoped tokens for hover, active, and selected states instead of generic accent tokens.
  • Adds a rich hover tooltip (SidebarV2ThreadTooltip) to thread rows showing project, environment, branch, model, and last error details; replaces inline error text and separate chip tooltips.
  • Replaces the horizontal project chip scroller in SidebarV2 with a dropdown radio menu for project filtering.
  • Removes the chat composer glass box-shadow and makes the lower composer chrome opaque when the terminal drawer is open (via a data-terminal-open attribute and CSS rule).
  • Behavioral Change: sidebar separators, menu button hover backgrounds, submenu active states, and badge colors all change visually due to token migration.

Macroscope summarized 89830a0.

- Improve light-mode contrast for rows, controls, and separators
- Use neutral sidebar tokens and preserve dark-mode styling
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d68af14d-e868-43be-917b-f7d5fe705cad

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/fix-lightmode-sidebar

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 22, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Jul 22, 2026
@macroscopeapp

macroscopeapp Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. This PR combines significant feature additions (project filtering, Thread List V2 sidebar support, command palette shortcuts) with styling refinements. Three unresolved medium-severity issues remain: keyboard focus visibility, CSS tokens not applying in mobile portals, and jump shortcuts mismatching filtered order.

You can customize Macroscope's approvability policy. Learn more.

juliusmarminge and others added 10 commits July 22, 2026 14:37
… rings

The previous light pass set the rail to near-white (oklch 0.992) with pure
white borderless cards on top, so the surface hierarchy collapsed. Drop the
rail to a light zinc (oklch 0.972) and lift every card/control off it as a
white object with a hairline ring: resting cards get a faint ring + shadow,
quiet (receded) cards go 70% white, hover deepens the ring, and the active
row becomes a crisp white pill (ring-black/13 + shadow). Selected rows use a
solid neutral tint. Scoped project chips get the same lifted-pill treatment
while unscoped chips stay quiet outlines. Dark mode keeps the original
graphite fills unchanged (verified against pre-change computed styles).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The translucent lower chrome lets the composer shadow taper into the message
canvas, but over the terminal drawer it rendered as a dirty light-to-black
gradient. Tag the chrome with data-terminal-open and switch it to the opaque
workspace background so the drawer border defines the boundary instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v2 cards used a black tint (2.5-4%) on the already-gray #f2f2f7 light
screen, reading dingy — the same failure just fixed in the web sidebar.
Follow the iOS grouped-list convention instead: cards are white surfaces on
the gray screen (quiet ready rows at 70% opacity so active work pops), and
the selected project-scope chip becomes a lifted white pill with a stronger
border while unscoped chips stay quiet outlines. Dark mode keeps the
original graphite tints via explicit dark: variants.

Verified on the iOS Simulator (iPhone 16 Pro, light + dark) against a
seeded local environment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rounded tonal cards read wrong on the phone in both schemes. Render
active threads as edge-to-edge rows on the screen background with an inset
hairline separator — colored status labels and text hierarchy carry state,
matching the settled tail's flat style so the whole list is one surface.
The opaque row background stays so swipe actions reveal behind it.

Verified on the iOS Simulator in light and dark.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sidebar v1 and the mobile Live Activity/widgets established amber for
approval, indigo for input, and sky for working — but sidebar v2 (web and
the mobile thread list) collapsed input into approval's amber and shifted
working to plain blue, so the same thread wore different colors across
surfaces and the two waiting-on-you states were indistinguishable at a
glance. Restore the convention in both v2 lists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Desktop cards mark remote threads with a cloud icon and a "Running on ..."
tooltip; mobile rows carried no environment signal at all. Phones have no
hover, so render the environment label as quiet text in the row's meta
line — and only when more than one environment is connected, since
repeating a single machine's name on every row is noise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The row already subscribed to the thread's PR (for merged/closed
auto-settle) but never showed it, while desktop cards render a
state-colored #number badge. Reuse the shared ThreadPrPresentation —
the same label/color source as the v1 rows — in the meta line between
the branch and the provider icon, mirroring the desktop order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Branch + PR + provider + machine on one meta line truncated the branch on
ordinary phone widths. Move the machine up beside the project title as
"project · machine" — both answer where the thread lives — leaving the
meta line to branch, PR, and provider.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sidebar pane (ThreadNavigationSidebar) only knew the v1 grouped list,
so the Thread List v2 beta silently did nothing on iPad. Reuse the shared
v2 partition (buildThreadListV2Items) and row component: when the beta is
on, the sidebar renders the flat creation-order card block and settled
tail — with statuses, PR badges, provider logos, machine labels, swipe
settle/un-settle, and Show more paging — scoped by the sidebar's existing
environment filter and search.

Split view needs to mark the thread open in the detail pane, so
ThreadListV2Row gains a `selected` tint (compact Home never sets it) and
a fullSwipeWidth override for narrow panes. The settled paging constants
move to threadListV2.ts so both surfaces page identically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The first iPad pass reused the compact-Home row shell verbatim, painting
opaque bg-screen slabs with square-edged selection tints onto the
sidebar's drawer surface — a visibly mismatched gray block. Give
ThreadListV2Row a pane variant instead: "screen" keeps the flat
edge-to-edge phone idiom, "sidebar" renders rounded rows that blend into
the drawer with the accent-filled white-text selection the v1 sidebar
rows use (every colored row fragment gains an on-accent variant), pane-
scoped paddings, and a rounded swipe container.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@macroscopeapp
macroscopeapp Bot dismissed their stale review July 22, 2026 15:32

Dismissing prior approval to re-evaluate ab492a5

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 22, 2026
Comment thread apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx
Comment thread apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx Outdated
Comment thread apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx
Comment thread apps/mobile/src/features/home/HomeScreen.tsx
juliusmarminge and others added 2 commits July 22, 2026 17:42
…sidebar

# Conflicts:
#	apps/web/src/components/SidebarV2.tsx
…e clock

Four review findings on the Thread List v2 surfaces:

- The filter menus (iPad sidebar, iOS and Android Home headers) kept
  offering Sort projects / Sort threads / Group projects while v2
  silently ignored them — its layout is fixed creation order. Hide those
  submenus when the beta is on (the environment filter still applies)
  and key the "customized" icon state off the environment alone.
- The sidebar v2 list dropped queued offline tasks entirely; render them
  above the thread rows with the sidebar row treatment, respecting the
  environment scope and search filter (mirrors the compact Home v2 list).
- nowMinute was captured at mount but the tick only started once v2 was
  enabled, so flipping the beta on after a long v1 session partitioned
  with an hours-old clock until the first tick. Refresh it on enable, in
  both the sidebar and the compact Home list.
- The compact Home v2 FlatList's extraData omitted savedConnectionsById,
  so connection changes didn't invalidate rows' machine labels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Jul 22, 2026
- Add project scope menus and filter state across home and sidebar views
- Refresh dynamic native header menus as project data loads
- Add coverage for project filter menu actions
@macroscopeapp
macroscopeapp Bot dismissed their stale review July 22, 2026 16:08

Dismissing prior approval to re-evaluate ddc8c71

@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Jul 22, 2026
Comment thread apps/mobile/src/features/home/HomeHeader.tsx
Comment thread apps/mobile/src/features/home/HomeHeader.tsx
Comment thread apps/mobile/src/features/home/HomeScreen.tsx
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/mobile/src/features/home/HomeScreen.tsx
juliusmarminge and others added 5 commits July 22, 2026 18:19
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
The compact Home list carried a horizontal project-chip scroller above the
v2 threads, duplicating the project filter that now lives in the header
filter menu. Remove the chip row and its component — the menu entry is the
single scoping mechanism on mobile; the chip idiom stays desktop-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"project · machine" crowded the top line into truncation while non-git
projects left the meta row empty with a lone provider icon. Pair the
machine with the branch instead — "branch · machine" on one truncating
line, machine last so a tight fit cuts the repetitive label rather than
the branch, and machine-only filling the row when there is no branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread apps/mobile/src/features/home/HomeHeader.tsx
Comment thread apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/web/src/components/SidebarV2.tsx Outdated
Comment thread apps/web/src/components/SidebarV2.tsx Outdated
Co-authored-by: codex <codex@users.noreply.github.com>
Comment thread apps/web/src/components/SidebarV2.tsx Outdated
? "bg-muted text-foreground"
: shouldRecede
? "text-muted-foreground/75 hover:bg-muted hover:text-foreground"
: "bg-transparent text-foreground hover:bg-muted",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thread rows hide keyboard focus

Medium Severity

The rowSurfaceClassName applies outline-none to focusable sidebar rows, removing the visual focus indicator for keyboard users. This impacts both slim and card rows, as no focus-visible styling is present to compensate.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 10f29ef. Configure here.

- Align sidebar surfaces, controls, states, and contrast with theme tokens
- Add thread detail tooltips and streamlined project scope controls
Comment thread apps/web/src/components/SidebarV2.tsx
Comment thread apps/web/src/index.css Outdated
global chrome background, or the fade shows a seam (same rule as the
light palette above). */
--sidebar-stage-fade: var(--card);
[data-sidebar-version="v2"] {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium src/index.css:501

The Sidebar V2 token overrides on [data-sidebar-version="v2"] never apply on mobile because Sheet/Dialog.Root receives the data-sidebar-version attribute but SheetPopup is rendered through a portal that does not inherit it. The portaled popup falls back to the root sidebar tokens (--sidebar: var(--card), etc.), so V2 row colors, borders, and surfaces are lost on mobile. Apply data-sidebar-version="v2" (or the token overrides) to the portaled popup or an ancestor inside the portal.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/index.css around line 501:

The Sidebar V2 token overrides on `[data-sidebar-version="v2"]` never apply on mobile because `Sheet`/`Dialog.Root` receives the `data-sidebar-version` attribute but `SheetPopup` is rendered through a portal that does not inherit it. The portaled popup falls back to the root sidebar tokens (`--sidebar: var(--card)`, etc.), so V2 row colors, borders, and surfaces are lost on mobile. Apply `data-sidebar-version="v2"` (or the token overrides) to the portaled popup or an ancestor inside the portal.

- Normalize sidebar colors and surfaces across app and settings navigation
- Restore positional command-palette shortcuts for project items
return itemWithoutShortcut;
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Jump keys ignore filtered order

Medium Severity

enumerateCommandPaletteItems binds thread.jump.19 from the original project list index, but filterCommandPaletteGroups re-sorts and drops rows when the palette query is non-empty. Visible row order and shortcut badges no longer match, and handleKeyDown still resolves jumps by the stale shortcutCommand on each item.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4168fec. Configure here.

- Add compact action sizing for slim mobile thread-list rows
- Preserve full-row press targets while reducing action visuals

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit 89830a0. Configure here.

{ height: 14, justifyContent: "center", paddingTop: props.compact ? 0 : 2 },
labelStyle,
]}
>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Swipe label clipped non-compact

Low Severity

SwipeActionButton now fixes the label wrapper at 14px tall for every mode, but non-compact actions still apply 2px top padding while the label uses 14px line height. That leaves only 12px for the text, so action captions like Delete or Un-settle can clip on card rows and other non-compact swipe surfaces.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 89830a0. Configure here.

@juliusmarminge
juliusmarminge merged commit 593289c into main Jul 22, 2026
16 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/fix-lightmode-sidebar branch July 22, 2026 21:51
t3dotgg added a commit that referenced this pull request Jul 22, 2026
Merge resolves the SidebarV2 restyle (#4268) by re-applying snooze onto
the new surface model (sidebar tokens, thread tooltips, restyled action
buttons), and folds in serverSelfUpdate capability alongside threadSnooze.

Review fixes:
- Snooze classification now uses a precise clock instead of the
  minute-quantized partition time, plus a timeout armed at the earliest
  upcoming wake — the shelf empties the moment a snooze expires instead
  of up to a minute late (Cursor)
- thread.snooze now rejects queued turn starts exactly like
  thread.settle, server-side (shared threadHasQueuedTurnStart helper)
  and client-side (canSnooze gains the hasQueuedTurnStart check) (Cursor)
- threadWokeAt keeps an early hand-raise wake authoritative after the
  scheduled wake time passes, so a visited-and-cleared Woke pill cannot
  resurface when snoozedUntil elapses (Macroscope)
- resolveSnoozePresets advances calendar days with setDate instead of
  DAY_MS offsets, fixing tomorrow/next-week presets across DST
  transitions (Macroscope)
- Documented why hasOpenBlockingRequest's scan of the 500-capped
  activities array is sound for the snooze invariant (Macroscope)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
UNN-Devotek pushed a commit to unn-corp/t3code that referenced this pull request Jul 23, 2026
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant