From c85023170c887024c1e5f4cb1aa5ac9281a014c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Sat, 9 May 2026 20:35:47 -0400 Subject: [PATCH] Lift split panes onto two-layer drop shadow Match the design's `0 1px 0 rgba(0,0,0,0.05), 0 12px 30px -16px rgba(0,0,0,0.18)` shadow stack on every split pane card and tighten inter-pane gap from 12 px (`gap_3`) to the design's 10 px. Without the ambient shadow the panes read as flat seams against the wallpaper; with it they sit on the canvas the way the design renders them. Grid axis now also gets a 10 px row gap so the second row doesn't butt up against the first. cargo test --workspace: 440 passed, 0 failed. --- crates/ely_app/src/shell/splits.rs | 47 +++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/crates/ely_app/src/shell/splits.rs b/crates/ely_app/src/shell/splits.rs index 1aa3b43..97ec125 100644 --- a/crates/ely_app/src/shell/splits.rs +++ b/crates/ely_app/src/shell/splits.rs @@ -2,8 +2,8 @@ use ely_browser_core::BrowserSnapshot; use ely_design_system::{colors, spacing}; use ely_domain::{BrowserTab, SplitAxis, SplitLayout}; use gpui::{ - AnyElement, Context, InteractiveElement, IntoElement, ParentElement, SharedString, - StatefulInteractiveElement, Styled, Window, div, px, rgb, rgba, + AnyElement, BoxShadow, Context, InteractiveElement, IntoElement, ParentElement, SharedString, + StatefulInteractiveElement, Styled, Window, div, hsla, point, px, rgb, rgba, }; use gpui_component::{ IconName, Selectable, Sizable, StyledExt, @@ -139,7 +139,7 @@ impl ElyShell { .flex() .flex_col() .overflow_hidden(); - let pane_area = div().flex_1().min_h_0().gap_3().overflow_hidden(); + let pane_area = div().flex_1().min_h_0().gap(px(10.0)).overflow_hidden(); let compact_canvas = layout.axis() == &SplitAxis::Vertical && layout.pane_count() >= 4; let panes = match layout.axis() { @@ -167,14 +167,16 @@ impl ElyShell { snapshot: &BrowserSnapshot, cx: &mut Context, ) -> gpui::Div { - body.flex().flex_col().children(panes.chunks(2).enumerate().map(|(row_index, row)| { - div().flex().flex_1().min_h(px(180.0)).gap_3().children(row.iter().enumerate().map( - |(column_index, tab)| { - let pane_index = row_index * 2 + column_index; - self.render_split_pane(pane_index, tab, snapshot, false, cx) - }, - )) - })) + body.flex().flex_col().gap(px(10.0)).children( + panes.chunks(2).enumerate().map(|(row_index, row)| { + div().flex().flex_1().min_h(px(180.0)).gap(px(10.0)).children( + row.iter().enumerate().map(|(column_index, tab)| { + let pane_index = row_index * 2 + column_index; + self.render_split_pane(pane_index, tab, snapshot, false, cx) + }), + ) + }), + ) } fn render_split_pane( @@ -205,6 +207,7 @@ impl ElyShell { .border_1() .border_color(rgb(border)) .bg(rgb(0xffffff)) + .shadow(split_pane_shadow()) .cursor_pointer() .hover(|style| style.opacity(0.98)) .active(|style| style.opacity(0.92)) @@ -419,3 +422,25 @@ fn active_split_layout<'a>( snapshot.split_layouts.iter().find(|layout| layout.id() == split_id) } +/// Two-layer drop shadow under each split pane card, matching the design's +/// `boxShadow:'0 1px 0 rgba(0,0,0,0.05), 0 12px 30px -16px rgba(0,0,0,0.18)'`. +/// The first layer is the hairline that lifts the card off the wallpaper, +/// the second is the soft ambient lift the design uses to keep stacked +/// panes legible against any wallpaper theme. +fn split_pane_shadow() -> Vec { + vec![ + BoxShadow { + color: hsla(0.0, 0.0, 0.0, 0.05), + offset: point(px(0.0), px(1.0)), + blur_radius: px(0.0), + spread_radius: px(0.0), + }, + BoxShadow { + color: hsla(0.0, 0.0, 0.0, 0.18), + offset: point(px(0.0), px(12.0)), + blur_radius: px(30.0), + spread_radius: px(-16.0), + }, + ] +} +