diff --git a/Cargo.lock b/Cargo.lock index 5ff56d195a..1a0390ef86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1466,7 +1466,7 @@ dependencies = [ [[package]] name = "collections" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "gpui_util", "indexmap", @@ -2113,7 +2113,7 @@ dependencies = [ [[package]] name = "derive_refineable" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "proc-macro2", "quote", @@ -3276,7 +3276,7 @@ dependencies = [ [[package]] name = "gpui" version = "0.2.2" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "accesskit", "anyhow", @@ -3392,7 +3392,7 @@ dependencies = [ [[package]] name = "gpui_linux" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "accesskit", "accesskit_unix", @@ -3444,7 +3444,7 @@ dependencies = [ [[package]] name = "gpui_macos" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "accesskit", "accesskit_macos", @@ -3493,7 +3493,7 @@ dependencies = [ [[package]] name = "gpui_macros" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3504,7 +3504,7 @@ dependencies = [ [[package]] name = "gpui_platform" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "console_error_panic_hook", "gpui", @@ -3517,7 +3517,7 @@ dependencies = [ [[package]] name = "gpui_shared_string" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "schemars", "serde", @@ -3527,7 +3527,7 @@ dependencies = [ [[package]] name = "gpui_tokio" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "anyhow", "gpui", @@ -3538,7 +3538,7 @@ dependencies = [ [[package]] name = "gpui_util" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "anyhow", "log", @@ -3548,7 +3548,7 @@ dependencies = [ [[package]] name = "gpui_web" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "anyhow", "console_error_panic_hook", @@ -3572,7 +3572,7 @@ dependencies = [ [[package]] name = "gpui_wgpu" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "anyhow", "bytemuck", @@ -3601,7 +3601,7 @@ dependencies = [ [[package]] name = "gpui_windows" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "accesskit", "accesskit_windows", @@ -3933,7 +3933,7 @@ dependencies = [ [[package]] name = "http_client" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "anyhow", "async-compression", @@ -5059,7 +5059,7 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "media" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "anyhow", "bindgen", @@ -6202,7 +6202,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "collections", "serde", @@ -7273,7 +7273,7 @@ dependencies = [ [[package]] name = "refineable" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "derive_refineable", ] @@ -7959,7 +7959,7 @@ checksum = "c62751faa8bc286982334a082fe125184a29fc89d17775766e4f891b7d726980" [[package]] name = "scheduler" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "async-task", "backtrace", @@ -8705,7 +8705,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sum_tree" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "heapless 0.9.3", "log", @@ -9963,7 +9963,7 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "util_macros" version = "0.1.0" -source = "git+https://github.com/zeronsh/zui?rev=c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add#c2d273dc3dadcb260b0fa7c35fc2fe02a14f5add" +source = "git+https://github.com/gaelcado/zui?rev=53869c204efb866d19af292cab8b1773898eeedd#53869c204efb866d19af292cab8b1773898eeedd" dependencies = [ "perf", "quote", diff --git a/Cargo.toml b/Cargo.toml index a3178cefea..a87a0270f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -143,3 +143,11 @@ opt-level = 0 [profile.dev.package."*"] opt-level = 2 + +# Temporary renderer override for the companion per-pixel text fade PR. +# Replace with an upstream revision once it merges. +[patch."https://github.com/zeronsh/zui"] +gpui = { git = "https://github.com/gaelcado/zui", rev = "53869c204efb866d19af292cab8b1773898eeedd" } +gpui_macros = { git = "https://github.com/gaelcado/zui", rev = "53869c204efb866d19af292cab8b1773898eeedd" } +gpui_platform = { git = "https://github.com/gaelcado/zui", rev = "53869c204efb866d19af292cab8b1773898eeedd" } +gpui_tokio = { git = "https://github.com/gaelcado/zui", rev = "53869c204efb866d19af292cab8b1773898eeedd" } diff --git a/crates/ui/src/edge_fade.rs b/crates/ui/src/edge_fade.rs index 1329f0e1a5..c78b8999e7 100644 --- a/crates/ui/src/edge_fade.rs +++ b/crates/ui/src/edge_fade.rs @@ -1,15 +1,49 @@ //! [`edge_faded`] — wraps a child so its whole subtree paints inside a //! [`gpui::EdgeFade`] scope: primitives fade by vertical distance to the -//! wrapper's own top/bottom edges (per-glyph granularity — a true static +//! wrapper's own top/bottom edges (per-pixel text opacity — a true static //! gradient, unlike whole-row opacity). Built for the GLASS sidebar's scroll //! fade: over a see-through blurred backdrop no painted overlay can fade //! content out, because "what is behind the window" is not a paintable color. +use std::cell::RefCell; + use gpui::{ - AnyElement, App, Bounds, EdgeFade, Element, GlobalElementId, InspectorElementId, IntoElement, - LayoutId, Pixels, ScrollHandle, Window, px, + AnyElement, App, Bounds, EdgeFade, Element, Global, GlobalElementId, InspectorElementId, + IntoElement, LayoutId, Pixels, ScrollHandle, Window, WindowId, px, }; +// GPUI replaces rather than composes nested EdgeFade scopes. Keep the active +// wrapper scopes during painting so a label can retain its scroll container's +// vertical fade. Window IDs prevent a nested draw of another window inheriting it. +#[derive(Default)] +struct PaintFades(RefCell>); + +impl Global for PaintFades {} + +fn active_fade(window: &Window, cx: &App) -> Option { + cx.try_global::()? + .0 + .borrow() + .iter() + .rev() + .find(|(id, _)| *id == window.window_handle().window_id()) + .map(|(_, fade)| *fade) +} + +fn inherit_vertical_fade(mut label: EdgeFade, parent: EdgeFade) -> EdgeFade { + if !label.top && !label.bottom && (parent.top || parent.bottom) { + label.bounds.origin.y = parent.bounds.origin.y; + label.bounds.size.height = parent.bounds.size.height; + label.top = parent.top; + label.bottom = parent.bottom; + // Keep the label's horizontal band independent of the container's + // vertical band, including asymmetric top/bottom overrides. + label.band_top = Some(parent.band_top.unwrap_or(parent.band)); + label.band_bottom = Some(parent.band_bottom.unwrap_or(parent.band)); + } + label +} + /// Fade the child's content at its own edges: `top`/`bottom` select which /// edges (pass the "is there hidden overflow" flags), `band` is the ramp /// height in px. Horizontal edges via [`EdgeFaded::fade_left`] / @@ -28,6 +62,7 @@ pub fn edge_faded(band: f32, top: bool, bottom: bool, child: impl IntoElement) - scroll_y: None, overflow_y: None, scroll_x: None, + smooth_overflow_x: false, child: child.into_any_element(), } } @@ -45,6 +80,7 @@ pub struct EdgeFaded { scroll_y: Option, overflow_y: Option (bool, bool)>>, scroll_x: Option, + smooth_overflow_x: bool, child: AnyElement, } @@ -103,6 +139,15 @@ impl EdgeFaded { self } + /// Ease a right-edge label fade into view as overflow grows from zero to + /// one band. Unlike scroll chrome, a label should not suddenly dim its + /// final characters as soon as it becomes a fraction too wide. + pub fn fade_label_overflow(mut self, handle: &ScrollHandle) -> Self { + self.scroll_x = Some(handle.clone()); + self.smooth_overflow_x = true; + self + } + /// Pull the fade's TOP edge `px` inside the wrapper: gpui clamps the ramp /// to 0 past an active edge, so content between the wrapper's real top /// and the inset edge paints fully transparent — content under opaque-ish @@ -175,14 +220,22 @@ impl Element for EdgeFaded { bottom &= overflow_bottom; } let (mut left, mut right) = (self.left, self.right); + let mut outset_right = 0.0; if let Some(scroll) = &self.scroll_x { let scrolled = -f32::from(scroll.offset().x); let max_scroll = f32::from(scroll.max_offset().x); left &= scrolled > 1.0; - right &= scrolled < max_scroll - 1.0; + if self.smooth_overflow_x { + let overflow = (max_scroll - scrolled).max(0.0); + right &= overflow > 0.0; + outset_right = label_fade_outset(overflow, self.band); + } else { + right &= scrolled < max_scroll - 1.0; + } } let fade = (top || bottom || left || right).then(|| { let mut bounds = bounds; + bounds.size.width += px(outset_right); let inset = px(self.inset_top).min(bounds.size.height); bounds.origin.y += inset; bounds.size.height -= inset; @@ -199,7 +252,169 @@ impl Element for EdgeFaded { right, } }); - window.with_edge_fade(fade, |window| self.child.paint(window, cx)); + let Some(mut fade) = fade else { + self.child.paint(window, cx); + return; + }; + if self.smooth_overflow_x + && let Some(parent) = active_fade(window, cx) + { + fade = inherit_vertical_fade(fade, parent); + } + if !cx.has_global::() { + cx.set_global(PaintFades::default()); + } + cx.global::() + .0 + .borrow_mut() + .push((window.window_handle().window_id(), fade)); + window.with_edge_fade(Some(fade), |window| self.child.paint(window, cx)); + cx.global::().0.borrow_mut().pop(); + } +} + +fn label_fade_outset(overflow: f32, band: f32) -> f32 { + let band = band.max(1.0); + let progress = (overflow / band).clamp(0.0, 1.0); + let eased = progress * progress * (3.0 - 2.0 * progress); + band * (1.0 - eased) +} + +#[cfg(test)] +mod tests { + use super::*; + use gpui::{AppContext, Context, Render, Styled, div, prelude::*}; + use std::rc::Rc; + + #[gpui::test] + fn painted_label_retains_scroll_fade_across_overflow_transitions( + cx: &mut gpui::TestAppContext, + ) { + struct Fixture { + width: f32, + top: bool, + bottom: bool, + observed: Rc>>>, + } + impl Render for Fixture { + fn render(&mut self, _: &mut Window, _: &mut Context) -> impl IntoElement { + let probe = |width: f32| { + let observed = self.observed.clone(); + gpui::canvas( + |_, _, _| (), + move |_, _, window, cx| { + observed.borrow_mut().push(active_fade(window, cx)); + }, + ) + .w(px(width)) + .h(px(20.0)) + .flex_none() + }; + let scroll = ScrollHandle::new(); + let label = edge_faded( + 20.0, + false, + false, + div() + .id("label") + .w(px(self.width)) + .overflow_hidden() + .track_scroll(&scroll) + .flex() + .child(probe(200.0)), + ) + .fade_right(true) + .fade_label_overflow(&scroll); + div() + .child( + edge_faded( + 24.0, + self.top, + self.bottom, + div() + .w(px(300.0)) + .h(px(100.0)) + .child(label) + .child(probe(20.0)), + ) + .band_top(12.0) + .band_bottom(30.0) + .inset_top(7.0) + .outset_bottom(9.0), + ) + .child(probe(20.0)) + } + } + let observed = Rc::new(RefCell::new(Vec::new())); + let handle = cx.add_window(|_, _| Fixture { + width: 80.0, + top: true, + bottom: true, + observed: observed.clone(), + }); + for (top, bottom) in [(true, true), (true, false), (false, true), (false, false)] { + for width in [80.0, 240.0, 80.0] { + handle + .update(cx, |view, _, cx| { + view.width = width; + view.top = top; + view.bottom = bottom; + cx.notify(); + }) + .unwrap(); + observed.borrow_mut().clear(); + cx.update_window(handle.into(), |_, window, cx| { + window.draw(cx).clear(); + assert!(active_fade(window, cx).is_none(), "paint scope leaked"); + }) + .unwrap(); + let seen = observed.borrow(); + let [label, sibling, outside] = &seen[seen.len() - 3..] else { + unreachable!() + }; + assert!(outside.is_none(), "fade leaked outside scroll container"); + let overflowing = width < 200.0; + if top || bottom { + let label = label.unwrap(); + let sibling = sibling.unwrap(); + assert_eq!((label.top, label.bottom), (top, bottom)); + assert_eq!(label.bounds.origin.y, sibling.bounds.origin.y); + assert_eq!(label.bounds.size.height, sibling.bounds.size.height); + assert_eq!(label.band_top, Some(px(12.0))); + assert_eq!(label.band_bottom, Some(px(30.0))); + assert_eq!(label.right, overflowing); + assert!(!sibling.right, "label fade leaked to a sibling"); + if overflowing { + assert_eq!(label.band, px(20.0)); + assert_eq!(label.bounds.size.width, px(width)); + } + } else { + assert!(sibling.is_none()); + assert_eq!(label.is_some(), overflowing); + if let Some(label) = label { + assert!(!label.top && !label.bottom); + assert!(label.right); + } + } + } + } + } + + #[test] + fn label_fade_enters_continuously_and_settles_at_one_band() { + let band = 20.0; + assert_eq!(label_fade_outset(0.0, band), band); + assert_eq!(label_fade_outset(band, band), 0.0); + assert_eq!(label_fade_outset(100.0, band), 0.0); + // Simulate resizing in 0.1 px increments across the old 1 px cutoff. + let mut previous = 1.0; + for step in 0..=400 { + let overflow = step as f32 / 10.0; + let edge_alpha = (label_fade_outset(overflow, band) / band).powi(2); + assert!(edge_alpha <= previous); + assert!(previous - edge_alpha < 0.02); + previous = edge_alpha; + } } } diff --git a/crates/ui/src/shell.rs b/crates/ui/src/shell.rs index 881210d682..78f3868556 100644 --- a/crates/ui/src/shell.rs +++ b/crates/ui/src/shell.rs @@ -703,6 +703,27 @@ const SIDEBAR_ACTIVE_HARNESS_TITLE_GAP: f32 = Theme::SPACE_SM; const SIDEBAR_ARCHIVED_HARNESS_ICON_SIZE: f32 = 14.0; const SIDEBAR_ARCHIVED_HARNESS_TITLE_GAP: f32 = 10.0; +/// Keep the fade short so only the last few glyphs recede. Tracking clipped +/// content lets the shared paint-time overflow gate leave fitting labels intact. +fn sidebar_faded_label(id: SharedString, fill: bool, label: impl IntoElement) -> impl IntoElement { + let overflow = gpui::ScrollHandle::new(); + crate::edge_fade::edge_faded( + 20.0, + false, + false, + div() + .id(id) + .when(fill, |el| el.flex_1()) + .min_w_0() + .overflow_hidden() + .track_scroll(&overflow) + .flex() + .child(div().flex_none().whitespace_nowrap().child(label)), + ) + .fade_right(true) + .fade_label_overflow(&overflow) +} + /// Ramp height of the sidebar's scroll-edge fade (the gpui /// [`gpui::EdgeFade`] scope — per-primitive, so text fades per glyph). const SIDEBAR_GLASS_FADE_BAND: f32 = 24.0; @@ -5777,16 +5798,15 @@ impl Shell { .flex_row() .items_center() .gap(px(Theme::SPACE_SM)) - .child( + .child(sidebar_faded_label( + format!("chat-device-{id}").into(), + true, div() - .flex_1() - .min_w_0() - .truncate() .text_size(crate::typography::ui_rems(11.0)) .line_height(px(14.0)) .text_color(subline) .child(popover::search_highlight(space_name, search_query, theme)), - ) + )) .child(div().text_color(subline).child(corner)), ) // Line 2: harness identity belongs directly with the title, @@ -5809,15 +5829,14 @@ impl Shell { ) }, ) - .child( + .child(sidebar_faded_label( + format!("chat-title-{id}").into(), + true, div() - .flex_1() - .min_w_0() - .truncate() .text_size(crate::typography::ui_rems(13.0)) .line_height(px(17.0)) .child(popover::search_highlight(title, search_query, theme)), - ), + )), ) // Line 3 is structural, not reserved whitespace: compact states // omit it completely when both Branch and Pull request are hidden. @@ -5836,15 +5855,15 @@ impl Shell { .flex_none() .text_color(subline), ) - .child( + .child(sidebar_faded_label( + format!("chat-branch-{id}").into(), + false, div() - .min_w_0() - .truncate() .text_size(crate::typography::ui_rems(11.0)) .line_height(px(14.0)) .text_color(subline) .child(popover::search_highlight(branch, search_query, theme)), - ) + )) }) // Stable invisible spring keeps the optional PR badge // pinned right without changing no-PR paint. diff --git a/crates/ui/src/shell/spaces.rs b/crates/ui/src/shell/spaces.rs index 022cbffedd..e8794321e5 100644 --- a/crates/ui/src/shell/spaces.rs +++ b/crates/ui/src/shell/spaces.rs @@ -160,14 +160,15 @@ fn sidebar_disclosure_header(theme: &Theme, label: SharedString, chevron: AnyEle .h(px(SIDEBAR_DISCLOSURE_HEADER_HEIGHT)) .px(px(Theme::SPACE_SM)) .cursor_pointer() - .child( + .child(super::sidebar_faded_label( + "sidebar-disclosure-label".into(), + false, div() - .flex_none() .text_size(crate::typography::ui_rems(12.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme.text_muted.opacity(0.5)) .child(label), - ) + )) .child(sidebar_separator(theme).flex_1()) .child(chevron) } @@ -823,7 +824,7 @@ impl Shell { .text_color(theme.text_muted), ) // flex_1 pushes the caret to the trigger's right edge and gives - // long space names a bound to truncate against; the "@ device" + // long space names a bound to fade against; the "@ device" // tag hugs the name inside it rather than sitting by the caret. .child( div() @@ -833,16 +834,21 @@ impl Shell { .flex_row() .items_center() .gap(px(6.0)) - .child(div().min_w_0().truncate().child(label)) + .child(super::sidebar_faded_label( + "spaces-filter-label".into(), + false, + label, + )) .when_some(device_tag, |el, (tag, offline)| { - el.child( + el.child(super::sidebar_faded_label( + "spaces-filter-device".into(), + false, div() - .flex_none() .text_size(crate::typography::ui_rems(10.0)) .font_weight(gpui::FontWeight::NORMAL) .text_color(theme.text_muted.opacity(0.45)) .child(tag), - ) + )) // Disconnected glyph, not the word (user request). .when(offline, |el| { el.child( @@ -1599,11 +1605,10 @@ impl Shell { }), ) }) - .child( + .child(super::sidebar_faded_label( + format!("archived-title-{id}").into(), + true, div() - .flex_1() - .min_w_0() - .truncate() .text_size(crate::typography::ui_rems(13.0)) .text_color(if hovered || is_selected { theme.text @@ -1611,7 +1616,7 @@ impl Shell { theme.text.opacity(0.55) }) .child(title), - ) + )) .child(right), ); } diff --git a/docs/screenshots/sidebar-text-fade/user-preview.png b/docs/screenshots/sidebar-text-fade/user-preview.png new file mode 100644 index 0000000000..5c3794c71d Binary files /dev/null and b/docs/screenshots/sidebar-text-fade/user-preview.png differ