Skip to content

Flatten desktop split panes to single surface with 1px dividers - #6329

Open
jbecke wants to merge 11 commits into
mainfrom
claude/beautiful-bell-20dhcc
Open

jbecke wants to merge 11 commits into
mainfrom
claude/beautiful-bell-20dhcc

Conversation

@jbecke

@jbecke jbecke commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Redesigns the desktop split layout to use a flat, unified surface instead of visually separated cards. Panes now meet edge-to-edge, separated only by 1px dividers that match the resize gutter, creating a cleaner, more integrated interface.

Key changes

  • Resize gutter: Reduced from 8px to 1px on desktop (touch layouts unchanged at 8px). The gutter now renders a thin divider even in fixed layouts; only resizable zones make it draggable.
  • Gutter hit area: Resizable gutters expand their drag target symmetrically to 8px minimum for usability while keeping the visual divider at 1px.
  • Panel styling: Removed rounded corners, shadows, borders, and depth from desktop split panes. Panels now use --color-panel: var(--color-page) to sit flat on the page surface.
  • Toolbar divider: Added 1px bottom border to ViewShell headers on desktop to close off the toolbar from content below, matching pane dividers.
  • Sidebar divider: Added explicit 1px divider between sidebar and panes when the sidebar is visible and expanded.
  • Theme unification: Macro Dark theme now uses true black (b0: l=0) for all pointer types instead of conditional graphite for desktop, supporting the flat layout aesthetic.
  • List and surface styling: Simplified Surface components in TaskList, EmailList, and fallback states to use flat styling (depth=0, no border, no radius) consistently across desktop and touch.
  • Removed styling logic: Eliminated conditional focus/unfocus styling, preview pair styling, and tucked viewer styling that relied on the card-based layout.

Implementation details

  • The Gutter component now accepts a resizable prop to distinguish between static dividers and draggable handles.
  • Gutter styling uses a barStyle() helper to center visual elements on the gutter axis.
  • Static dividers use pointer-events-none and aria-hidden to remain non-interactive.
  • Desktop layout now uses RESIZE_GUTTER = isTouchDevice() ? 8 : 1 consistently across SplitLayout and ViewShell.
  • Sidebar divider visibility is controlled by a new sidebarDividerVisible() memo that checks both visibility and expansion state.

https://claude.ai/code/session_01Eq54Rhy76eNDYXWppZYnDi


Note

Medium Risk
Broad visual and layout changes across split layout, shared UI primitives, and mobile navigation touch many surfaces; email list navigation and mobile compose routing add behavioral paths worth regression testing.

Overview
Desktop split layout drops the card metaphor: panes are flush on the page with 1px resize gutters as dividers, sidebar gets a matching rail divider, and split panels lose radius, shadow, focus-card, and preview-pair border tricks. ViewShell headers and list surfaces follow the same flat treatment.

A glass layer rolls through floating UI: dialogs and dropdowns use translucent menu glass and accent scrims; non-ghost buttons and button groups pick up glass; composers share a new ComposerSurface (glass input on desktop, chrome island on touch). Hover/active states move to overlay-* utilities; outline buttons get a tinted substrate for blur.

Mobile gets a reworked dock: Phosphor icons with fill variants for active tabs, five compact destinations plus overflow More, search on its own island, and a contextual create action in the accessory float region (e.g. new event on calendar) instead of a full create menu. Touch overflow menus and pill tabs adopt glass styling; task/calendar compose popovers open as bottom sheets on touch.

Product polish includes shared UserMessageBubble and send-motion hooks for chat/agent, provider icons in split headers, useEmailListNavigation for prev/next thread from the mail/inbox list on mobile, richer calendar event fills (no color bars), separate mobile vs desktop calendar period prefs, and removal of calendar UI flag gating in the dock. Playwright MCP page snapshots were added under .playwright-mcp/.

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

Standalone port of the Apple-style glass chrome from the
claude/v3-facebook-topbar-layout-et1kbq branch (as of its V4 state), with
none of the layout work: a backdrop blur, a bright inner top edge, a dark
inner bottom edge, a soft cast shadow, and a 135deg specular rim drawn as a
1px gradient masked to the border box.

- `glass` / `glass-sm` / `glass-lg` utilities in index.css, with palette
  tokens (themed, light-mode pass) split from geometry tokens (per size).
- Button applies it to every variant except `ghost`, which picks it up on
  hover; compact sizes step down to `glass-sm`. ButtonGroup carries one pane
  for the whole row and its buttons opt out. `base` gets a tinted background
  so the blur has a substrate.
- `glass-lg` + `bg-menu-glass` on floating chrome: dropdowns, context menus,
  selects, popovers, the Lexical typeahead menus, cmd+k and the create
  launcher, and floating dialogs (fullscreen dialogs stay opaque).
- `glass-input` (wide faint ambient shadow, quieter in light mode) on the
  desktop channel input, AI chat input, agent input, and email compose.
- `scrim-glass` dims the page behind floating dialogs with an accent-tinted
  wash and a whisper of blur; `visibleScrim` layers its heavier coat on top.
- `glass-none` opts out under a variant (collapsed property pills).
- Only the standard `backdrop-filter` is declared: Lightning CSS adds the
  -webkit- prefix itself, and a hand-written prefix after it made the pair
  collapse to the prefixed form alone in production builds.
# Conflicts:
#	apps/web/src/features/block-agent/ui/AgentInput.tsx
#	apps/web/src/features/block-email/component/BaseInput.tsx
The specular rim was reading as shimmer, so both palette passes drop its
strengths to 75% (dark 18/12 -> 13.5/9, light 70/40 -> 52.5/30).

The `outline` variant is the one button with a hard border of its own, and
under the glass rim plus the inset highlight it read as a double line. When
glassed (i.e. outside a ButtonGroup) its border goes transparent, so the
tinted fill and the rim carry the shape — a flat, soft pill in the YouTube
mould. ButtonGroup applies the same rule to its frame.
Buttons were on a stepped-down version of the glass (0.72 scale, compact
sizes at 0.5) while menus and dialogs carried the full recipe. There is no
reason for two materials: the size scale goes away and `glass` is the one
utility, at the strength the modals already use. `glass-sm` and `glass-lg`
are gone; every consumer points at `glass`, `glass-input` builds on it, and
Button/ButtonGroup drop their per-size maps.

The mobile `island` utility — the dock bar, the Create island, the header
islands in blocks, and the soup view pills — picks the glass up too. Its
ring and hand-tuned light-mode shadow go: Tailwind rings are box-shadows and
would fight the glass box-shadow, and the rim plus cast shadow now play that
part. The active pill's `ring-accent` had nothing left to color.
Replace the desktop bento treatment (rounded, shadowed split cards on a
lighter backdrop with 8px gaps) with a flat layout: the icon rail, view
sidebars, toolbars, and every split pane share one surface-0 background
and meet edge-to-edge, separated only by 1px dividers.

- Resize gutters shrink to 1px on desktop and always paint a 1px divider,
  even in non-resizable zones; the drag hit area stays 8px wide and the
  accent hover/focus/drag bar is preserved.
- Split panes drop radius, shadow, inset border, and focus/preview-pair
  border styling; a scoped --color-panel makes nested panel chrome share
  the page surface. The outer split-layout padding is removed.
- ViewShell headers gain a 1px bottom divider; view sidebars and rails no
  longer draw their own right border so lines never double.
- Email and task lists sit flat on the pane instead of as lifted cards.
- A 1px divider separates the sidebar column from the panes.
- Macro Dark uses one true-black ramp for every pointer type.

Touch layouts keep their previous spacing, gutters, and card backgrounds.
@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Important

Review skipped

Auto incremental 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 4aee57ba-34fc-4575-8b4d-0bd9fca5ecef

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: d660e0d6-d872-4e9c-b436-7b3b014097d9

📥 Commits

Reviewing files that changed from the base of the PR and between cc9a113 and c62466a.

📒 Files selected for processing (17)
  • apps/web/src/components/app/Layout.tsx
  • apps/web/src/components/app/split-layout/SplitLayout.tsx
  • apps/web/src/components/app/split-layout/components/SplitHeader.tsx
  • apps/web/src/components/app/split-layout/components/SplitPanel.tsx
  • apps/web/src/components/view-shell/ViewShell.tsx
  • apps/web/src/components/view-shell/ViewSidebar.tsx
  • apps/web/src/features/channels-view/components/rail/ChannelsRail.tsx
  • apps/web/src/features/email-view/components/EmailList.tsx
  • apps/web/src/features/email-view/components/EmailSidebar.tsx
  • apps/web/src/features/email-view/email-view.tsx
  • apps/web/src/features/inbox-view/inbox-view.tsx
  • apps/web/src/features/tasks-view/components/TasksSidebar.tsx
  • apps/web/src/features/tasks-view/components/task-list/TaskList.tsx
  • apps/web/src/features/tasks-view/tasks-view.tsx
  • apps/web/src/features/theme/themes/macro-dark.ts
  • apps/web/src/index.css
  • apps/web/src/lib/core/component/Resize/Resize.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Summary

Summary by CodeRabbit

  • Style
    • Updated split panels, email lists, task lists, and loading states with flatter, borderless surfaces and square corners.
    • Added consistent 1px dividers between visible panels and adjusted resize spacing for touch and desktop layouts.
    • Refined sidebar, channel rail, and notification panel borders for a cleaner layout.
    • Expanded resize gutter visuals while preserving drag behavior where supported.
    • Updated dark-theme colors and the default font stack.
    • Removed rounded corners from the entity drag-and-drop overlay.

Walkthrough

The update flattens split panels, email lists, task lists, and fallback surfaces across platforms. Desktop layouts use one-pixel pane and header dividers, while touch layouts retain wider gutters. Resize gutters now render as static dividers when resizing is disabled and retain interactive behavior when enabled. Sidebar borders and rounded drag overlays are removed. The dark theme uses one token ramp for touch and desktop runtimes. The panel surface token and font stack are updated.

Merge Risk: ⚪ Minimal · up to c6246

The layout and theme changes have no substantiated merge-blocking issue.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title accurately summarizes the changes and is 63 characters long, but it does not follow the required Conventional Commits format because it lacks a prefix such as "feat:" or "chore:". Add a Conventional Commits prefix. For example: "feat: flatten desktop split panes with 1px dividers".
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the flat desktop split layout, 1px dividers, gutter behavior, panel styling, and related theme changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch claude/beautiful-bell-20dhcc

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Put -apple-system / BlinkMacSystemFont first in the sans stack so macOS,
iOS, and iPadOS render text in SF; those names only resolve on Apple
platforms, so every other OS falls through to the bundled Inter as before.
Drop system-ui and "Segoe UI" from the text fallbacks so Windows never
picks Segoe; the Segoe emoji/symbol fonts stay as glyph fallbacks only.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

* divider the resize gutter paints, so the regions meet edge-to-edge; touch
* layouts keep their wider spacing.
*/
const RESIZE_GUTTER = isTouchDevice() ? 8 : 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ViewShell gutter ignores device changes

Medium Severity

RESIZE_GUTTER reads isTouchDevice() once at module load and never updates. Aside/main/detail spacing and canFitInlineDetail stay locked to that first value, while SplitLayout and the touch: CSS chrome follow the live signal, so a later pointer-class change leaves ViewShell gutters and fit math out of sync with the rest of the layout.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c62466a. Configure here.

onPointerDown={onPointerDown}
onKeyDown={onKeyDown}
onPointerDown={props.resizable ? onPointerDown : undefined}
onKeyDown={props.resizable ? onKeyDown : undefined}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Header covers resize hit area

Medium Severity

The expanded 8px gutter hit area sits at z-index: auto while Panel.Header uses z-split-panel-chrome (30). Along the toolbar the extra 3.5px on each side is stolen by the headers, so the draggable target collapses back to the 1px seam—the exact case the hit-area expansion was meant to fix.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c62466a. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

return (
<Panel
class={cn('max-h-[75vh] rounded-xl bg-dialog', local.class)}
class={cn('max-h-[75vh] rounded-xl bg-transparent', local.class)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Onboarding command menu lost its pane

Medium Severity

CommandMenuShell now paints a transparent pane and relies on its parent to supply the glass surface. Launcher was updated for that, but the onboarding command-k lesson still mounts CommandMenuInner in a raw Kobalte Dialog.Content with no background, so the tutorial menu body and header sit over the patterned overlay while only the toolbar and footer keep bg-dialog.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4b135c8. Configure here.

// to separate the button from the surface behind it.
outline:
'bg-transparent text-ink-muted border-edge-muted not-disabled:hover:bg-hover not-disabled:hover:text-ink not-disabled:active:bg-active',
'bg-lift/70 text-ink-muted border-edge-muted not-disabled:hover:overlay-hover not-disabled:hover:text-ink not-disabled:active:overlay-active',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Outline buttons use missing lift token

Medium Severity

The outline variant now fills with bg-lift/70 so glass has a tinted substrate, but --color-lift is not a theme color. normalizeThemeColorTokens deletes lift, and @theme never defines it, so the utility does not resolve. Combined with glass border-transparent, outline buttons lose both fill and hard edge.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4b135c8. Configure here.

…n hover

- Side panel sections step down from depth 2 to depth 1 so they read as
  grouped content on the pane rather than raised cards.
- Calendar event chips get the glass inner edges, cast shadow and specular
  rim from the shared --glass-* palette, restated in calendar.css because
  the utility's position: relative would unseat FullCalendar's absolutely
  positioned timegrid events. Hover and focus rings now compose with the
  edges through --calendar-event-ring instead of replacing them. Mirrors,
  selection previews and month dot events stay flat.
- The glass treatment reaches the floating surfaces the port missed: the
  event details and calendar search popovers, the guest picker, link hover
  card and floating link menu, property tooltip, tag picker, color picker,
  emoji and reaction popovers, code file-type picker, in-call roster,
  PR checks popover, desktop toasts and the sidebar calendar's New event
  button.
- Ghost buttons and ghost button groups no longer pick up the glass rim on
  hover; their hover scrim alone marks the state.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread apps/web/src/features/calendar/calendar.css Outdated
>
<Popover.Arrow class="fill-surface" />
<div class="w-fit min-w-[min(20rem,calc(100vw-2rem))] max-w-[min(24rem,calc(100vw-2rem))] overflow-hidden rounded-xl bg-surface text-ink shadow-menu ring ring-edge-muted">
<div class="w-fit min-w-[min(20rem,calc(100vw-2rem))] max-w-[min(24rem,calc(100vw-2rem))] overflow-hidden rounded-xl glass bg-menu-glass text-ink">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Popover arrows mismatch glass bodies

Low Severity

These popovers switched their content to translucent bg-menu-glass but left Popover.Arrow on fill-surface. The arrow still paints the opaque layer surface, so it no longer matches the frosted body and shows a hard color seam at the junction.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9d71054. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 2 potential issues.

There are 7 total unresolved issues (including 5 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 929efef. Configure here.

- link "DPA" [ref=e1984] [cursor=pointer]:
- /url: /dpa
- link "AUP" [ref=e1985] [cursor=pointer]:
- /url: /legal/aup No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Playwright snapshots committed by accident

Medium Severity

Three Playwright MCP page dumps landed in .playwright-mcp/ — a Linear marketing snapshot, a Macro marketing snapshot, and a login-screen tree. They are unrelated to the split-pane work and are local browser-tool artifacts, not fixtures the app or CI reads.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 929efef. Configure here.

onClick={props.onClick}
ref={(el) =>
ref={(el) => {
messageSendMotion(el, () => `channel:${props.message.id}`, 'channel');

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Channel send motion never runs

Medium Severity

ChannelMessage attaches messageSendMotion with a channel: key, but no channel send path calls markMessageSent. The hook only animates tickets created by that mark, so newly posted channel messages stay still while chat and agent sends animate.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 929efef. Configure here.

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