diff --git a/crates/ui/src/floating_sidebar/mod.rs b/crates/ui/src/floating_sidebar/mod.rs index 956b0481..1ccb57a6 100644 --- a/crates/ui/src/floating_sidebar/mod.rs +++ b/crates/ui/src/floating_sidebar/mod.rs @@ -40,8 +40,8 @@ impl FloatingSidebarState { /// A floating sidebar that composes SidebarShell and Sidebar with internal resize handling. /// -/// The default elevation is [`ElevationToken::Sm`]. Large elevations may require -/// a larger inset near window edges to avoid native-window clipping. +/// By default, the sidebar uses the theme's panel elevation. Explicit elevation overrides may +/// require a larger inset near window edges to avoid native-window clipping. #[derive(IntoElement)] pub struct FloatingSidebar { id: ElementId, @@ -57,7 +57,7 @@ pub struct FloatingSidebar { inset: Option, top_inset: Pixels, blur_enabled: Option, - elevation: ElevationToken, + elevation: Option, on_resize_end: Option>, } @@ -79,7 +79,7 @@ impl FloatingSidebar { inset: Some(DEFAULT_INSET), top_inset: px(0.0), blur_enabled: None, - elevation: ElevationToken::Sm, + elevation: None, on_resize_end: None, } } @@ -166,10 +166,10 @@ impl FloatingSidebar { /// Set the shadow elevation level for the complete sidebar panel. /// - /// Default is [`ElevationToken::Sm`]. Large elevations may require a larger + /// When not set, the theme's panel elevation is used. Large elevations may require a larger /// inset near window edges to avoid native-window clipping. pub fn elevation(mut self, elevation: ElevationToken) -> Self { - self.elevation = elevation; + self.elevation = Some(elevation); self } @@ -334,12 +334,14 @@ impl RenderOnce for FloatingSidebar { .max_width(max_width) .resizer_width(resizer_width) .top_inset(top_inset) - .elevation(elevation) .on_resize_start(on_resize_start) .on_resize_end(move |window, cx| { end_resize(window, cx); }); + if let Some(elevation) = elevation { + shell = shell.elevation(elevation); + } if let Some(color) = resizer_hover_bg { shell = shell.resizer_hover_bg(color); } @@ -487,7 +489,7 @@ mod tests { #[gpui::test] fn test_floating_sidebar_builder(_cx: &mut gpui::TestAppContext) { let default_sidebar = FloatingSidebar::::new("default-floating-sidebar"); - assert_eq!(default_sidebar.elevation, ElevationToken::Sm); + assert_eq!(default_sidebar.elevation, None); assert_eq!(default_sidebar.width, DEFAULT_WIDTH); assert_eq!(default_sidebar.inset, Some(DEFAULT_INSET)); assert_eq!(default_sidebar.resizer_width, DEFAULT_RESIZER_WIDTH); @@ -516,16 +518,16 @@ mod tests { assert_eq!(sidebar.inset, Some(px(6.0))); assert_eq!(sidebar.top_inset, px(12.0)); assert_eq!(sidebar.blur_enabled, Some(false)); - assert_eq!(sidebar.elevation, ElevationToken::Md); + assert_eq!(sidebar.elevation, Some(ElevationToken::Md)); assert!(sidebar.on_resize_end.is_some()); let no_shadow = FloatingSidebar::::new("no-shadow").elevation(ElevationToken::None); - assert_eq!(no_shadow.elevation, ElevationToken::None); + assert_eq!(no_shadow.elevation, Some(ElevationToken::None)); let large_shadow = FloatingSidebar::::new("large-shadow").elevation(ElevationToken::Lg); - assert_eq!(large_shadow.elevation, ElevationToken::Lg); + assert_eq!(large_shadow.elevation, Some(ElevationToken::Lg)); } #[gpui::test] diff --git a/crates/ui/src/sidebar_shell/mod.rs b/crates/ui/src/sidebar_shell/mod.rs index 34aa8d7a..2045da0f 100644 --- a/crates/ui/src/sidebar_shell/mod.rs +++ b/crates/ui/src/sidebar_shell/mod.rs @@ -96,8 +96,8 @@ pub fn sidebar_shadow() -> Vec { /// - Glass blur and noise effects via SurfacePreset::panel() /// - Draggable resize handle with hover feedback /// -/// The default elevation is [`ElevationToken::Sm`]. Large elevations may require -/// a larger inset near window edges to avoid native-window clipping. +/// By default, the shell uses the theme's panel elevation. Explicit elevation overrides may +/// require a larger inset near window edges to avoid native-window clipping. /// /// The component uses a builder pattern for configuration and implements /// `ParentElement` for adding child content, `Styled` for style refinement, @@ -138,9 +138,9 @@ pub struct SidebarShell { on_resize_start: Option>, /// Callback invoked when resize ends (mouse up). on_resize_end: Option>, - /// Shadow elevation level for the complete sidebar panel. - /// Default: `ElevationToken::Sm`. - elevation: ElevationToken, + /// Optional shadow elevation override for the complete sidebar panel. + /// If `None`, the theme's panel elevation is used. + elevation: Option, /// Placement side (left or right). side: Side, /// Inset from window edges in pixels. If `None`, inherits from context. @@ -197,7 +197,7 @@ impl SidebarShell { resizer_hover_bg: None, on_resize_start: None, on_resize_end: None, - elevation: ElevationToken::Sm, + elevation: None, side, inset: None, top_inset: px(0.0), @@ -326,7 +326,7 @@ impl SidebarShell { /// Sets the shadow elevation level for the complete sidebar panel. /// /// Controls the single panel shadow using the theme's elevation system. - /// Default: `ElevationToken::Sm`. Large elevations may require a larger + /// When not set, the theme's panel elevation is used. Large elevations may require a larger /// inset near window edges to avoid native-window clipping. /// /// # Example @@ -337,9 +337,17 @@ impl SidebarShell { /// .child(content) /// ``` pub fn elevation(mut self, elevation: ElevationToken) -> Self { - self.elevation = elevation; + self.elevation = Some(elevation); self } + + fn surface_preset(&self) -> SurfacePreset { + let mut surface_preset = SurfacePreset::panel(); + if let Some(elevation) = self.elevation { + surface_preset = surface_preset.with_elevation(elevation); + } + surface_preset + } } impl ParentElement for SidebarShell { @@ -375,8 +383,8 @@ impl RenderOnce for SidebarShell { .blur_enabled .unwrap_or_else(|| GlobalState::global(cx).blur_enabled()); - let sidebar_surface = SurfacePreset::panel() - .with_elevation(self.elevation) + let sidebar_surface = self + .surface_preset() .wrap_with_bounds( div(), sidebar_width, @@ -458,7 +466,7 @@ mod tests { #[test] fn test_sidebar_shell_defaults_and_elevation_builder() { let default_shell = SidebarShell::left(px(260.0)); - assert_eq!(default_shell.elevation, ElevationToken::Sm); + assert_eq!(default_shell.elevation, None); assert_eq!(default_shell.min_width, px(DEFAULT_MIN_WIDTH)); assert_eq!(default_shell.max_width, px(DEFAULT_MAX_WIDTH)); assert_eq!(default_shell.resizer_width, px(DEFAULT_RESIZER_WIDTH)); @@ -466,15 +474,34 @@ mod tests { assert_eq!(default_shell.side, Side::Left); let no_shadow = SidebarShell::left(px(260.0)).elevation(ElevationToken::None); - assert_eq!(no_shadow.elevation, ElevationToken::None); + assert_eq!(no_shadow.elevation, Some(ElevationToken::None)); let large_shadow = SidebarShell::right(px(300.0)) .inset(px(12.0)) .resizer_width(px(8.0)) .elevation(ElevationToken::Lg); - assert_eq!(large_shadow.elevation, ElevationToken::Lg); + assert_eq!(large_shadow.elevation, Some(ElevationToken::Lg)); assert_eq!(large_shadow.inset, Some(px(12.0))); assert_eq!(large_shadow.resizer_width, px(8.0)); assert_eq!(large_shadow.side, Side::Right); } + + #[test] + fn test_sidebar_shell_surface_preset_elevation() { + let theme_default = SidebarShell::left(px(260.0)).surface_preset(); + assert_eq!(theme_default.elevation, ElevationToken::Lg); + assert!(theme_default.use_theme_elevation_defaults); + + let no_shadow = SidebarShell::left(px(260.0)) + .elevation(ElevationToken::None) + .surface_preset(); + assert_eq!(no_shadow.elevation, ElevationToken::None); + assert!(!no_shadow.use_theme_elevation_defaults); + + let large_shadow = SidebarShell::left(px(260.0)) + .elevation(ElevationToken::Lg) + .surface_preset(); + assert_eq!(large_shadow.elevation, ElevationToken::Lg); + assert!(!large_shadow.use_theme_elevation_defaults); + } } diff --git a/crates/ui/src/surface/mod.rs b/crates/ui/src/surface/mod.rs index b8d6f911..a9d15d2c 100644 --- a/crates/ui/src/surface/mod.rs +++ b/crates/ui/src/surface/mod.rs @@ -513,7 +513,9 @@ struct NoiseTileLayout { } fn noise_tile_layout(width: Pixels, height: Pixels, scale_factor: f32) -> NoiseTileLayout { - let tile_size_value = (GLASS_NOISE_TILE_SIZE_BASE / scale_factor.max(1.0)).round(); + let tile_size_value = (GLASS_NOISE_TILE_SIZE_BASE / scale_factor.max(1.0)) + .round() + .max(1.0); let tile_size = px(tile_size_value); if width <= px(0.0) || height <= px(0.0) { @@ -631,6 +633,17 @@ mod tests { assert_eq!(layout.last_tile_height, px(60.0)); } + #[test] + fn noise_tile_layout_clamps_tile_size_at_extreme_scale_factors() { + let layout = noise_tile_layout(px(3.0), px(2.0), 512.0); + + assert_eq!(layout.tile_size, px(1.0)); + assert_eq!(layout.cols, 3); + assert_eq!(layout.rows, 2); + assert_eq!(layout.last_tile_width, px(1.0)); + assert_eq!(layout.last_tile_height, px(1.0)); + } + #[test] fn noise_tile_layout_handles_zero_dimensions() { let layout = noise_tile_layout(px(0.0), px(0.0), 1.0); diff --git a/docs/docs/components/sidebar.md b/docs/docs/components/sidebar.md index 88f00747..100400e1 100644 --- a/docs/docs/components/sidebar.md +++ b/docs/docs/components/sidebar.md @@ -89,8 +89,8 @@ SidebarToggleButton::new() ### Floating Sidebar (SidebarShell + Sidebar) `FloatingSidebar` composes `SidebarShell` with `Sidebar`, handling resize internally. -It defaults to an 8px inset, `ElevationToken::Sm`, and can be resized when expanded. -The shell elevation controls the complete panel shadow. Larger elevations may need a larger +It defaults to an 8px inset, uses the theme's panel elevation, and can be resized when expanded. +Call `.elevation(...)` to override the complete panel shadow. Larger elevations may need a larger inset near window edges to avoid native-window clipping; the inset is never adjusted automatically. ```rust