diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index d8bfae85bcd40654086c05d52d0004c618055c31..5b38afcd5ef3a576388996958b821f426922d322 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -7,8 +7,8 @@ use editor::{Editor, EditorElement, EditorStyle}; use feature_flags::{AgentV2FeatureFlag, FeatureFlagViewExt as _}; use gpui::{ AnyElement, App, Context, Entity, EventEmitter, FocusHandle, Focusable, FontStyle, ListState, - Pixels, Render, SharedString, TextStyle, WeakEntity, Window, actions, linear_color_stop, - linear_gradient, list, prelude::*, px, relative, rems, + Pixels, Render, SharedString, TextStyle, WeakEntity, Window, actions, list, prelude::*, px, + relative, rems, }; use menu::{Cancel, Confirm, SelectFirst, SelectLast, SelectNext, SelectPrevious}; use project::Event as ProjectEvent; @@ -18,8 +18,8 @@ use std::mem; use theme::{ActiveTheme, ThemeSettings}; use ui::utils::TRAFFIC_LIGHT_PADDING; use ui::{ - AgentThreadStatus, HighlightedLabel, IconButtonShape, KeyBinding, ListItem, Tab, ThreadItem, - Tooltip, WithScrollbar, prelude::*, + AgentThreadStatus, GradientFade, HighlightedLabel, IconButtonShape, KeyBinding, ListItem, Tab, + ThreadItem, Tooltip, WithScrollbar, prelude::*, }; use util::path_list::PathList; use workspace::{ @@ -803,33 +803,13 @@ impl Sidebar { }; let color = cx.theme().colors(); - let base_bg = color.panel_background; - let gradient_overlay = div() - .id("gradient_overlay") - .absolute() - .top_0() - .right_0() - .w_12() - .h_full() - .bg(linear_gradient( - 90., - linear_color_stop(base_bg, 0.6), - linear_color_stop(base_bg.opacity(0.0), 0.), - )) - .group_hover(group_name.clone(), |s| { - s.bg(linear_gradient( - 90., - linear_color_stop(color.element_hover, 0.6), - linear_color_stop(color.element_hover.opacity(0.0), 0.), - )) - }) - .group_active(group_name.clone(), |s| { - s.bg(linear_gradient( - 90., - linear_color_stop(color.element_active, 0.6), - linear_color_stop(color.element_active.opacity(0.0), 0.), - )) - }); + let gradient_overlay = GradientFade::new( + color.panel_background, + color.element_hover, + color.element_active, + ) + .width(px(48.0)) + .group_name(group_name.clone()); ListItem::new(id) .group_name(group_name) diff --git a/crates/ui/src/components.rs b/crates/ui/src/components.rs index cce736e237e2c2500b56f13ae579dee4426b5bfb..ef344529cd92efcbf8f57d192c44bbb53befc25e 100644 --- a/crates/ui/src/components.rs +++ b/crates/ui/src/components.rs @@ -12,6 +12,7 @@ mod disclosure; mod divider; mod dropdown_menu; mod facepile; +mod gradient_fade; mod group; mod icon; mod image; @@ -54,6 +55,7 @@ pub use disclosure::*; pub use divider::*; pub use dropdown_menu::*; pub use facepile::*; +pub use gradient_fade::*; pub use group::*; pub use icon::*; pub use image::*; diff --git a/crates/ui/src/components/ai/thread_item.rs b/crates/ui/src/components/ai/thread_item.rs index be27e6332ca500747e1836bbd577c7fd5ffb2507..3c08bd946710f76ccf49f933b82091a3bcb06e08 100644 --- a/crates/ui/src/components/ai/thread_item.rs +++ b/crates/ui/src/components/ai/thread_item.rs @@ -1,9 +1,9 @@ use crate::{ - DecoratedIcon, DiffStat, HighlightedLabel, IconDecoration, IconDecorationKind, SpinnerLabel, - prelude::*, + DecoratedIcon, DiffStat, GradientFade, HighlightedLabel, IconDecoration, IconDecorationKind, + SpinnerLabel, prelude::*, }; -use gpui::{AnyView, ClickEvent, Hsla, SharedString, linear_color_stop, linear_gradient}; +use gpui::{AnyView, ClickEvent, Hsla, SharedString}; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum AgentThreadStatus { @@ -220,24 +220,12 @@ impl RenderOnce for ThreadItem { color.panel_background }; - let gradient_overlay = div() - .absolute() - .top_0() - .right(px(-10.0)) - .w_8() - .h_full() - .bg(linear_gradient( - 90., - linear_color_stop(base_bg, 0.8), - linear_color_stop(base_bg.opacity(0.0), 0.), - )) - .group_hover("thread-item", |s| { - s.bg(linear_gradient( - 90., - linear_color_stop(color.element_hover, 0.8), - linear_color_stop(color.element_hover.opacity(0.0), 0.), - )) - }); + let gradient_overlay = + GradientFade::new(base_bg, color.element_hover, color.element_active) + .width(px(32.0)) + .right(px(-10.0)) + .gradient_stop(0.8) + .group_name("thread-item"); v_flex() .id(self.id.clone()) diff --git a/crates/ui/src/components/gradient_fade.rs b/crates/ui/src/components/gradient_fade.rs new file mode 100644 index 0000000000000000000000000000000000000000..2173fdf06ea8c07c947f092066c2a12d716d4b44 --- /dev/null +++ b/crates/ui/src/components/gradient_fade.rs @@ -0,0 +1,88 @@ +use gpui::{Hsla, Pixels, SharedString, linear_color_stop, linear_gradient, px}; + +use crate::prelude::*; + +/// A gradient overlay that fades from a solid color to transparent. +#[derive(IntoElement)] +pub struct GradientFade { + base_bg: Hsla, + hover_bg: Hsla, + active_bg: Hsla, + width: Pixels, + right: Pixels, + gradient_stop: f32, + group_name: Option, +} + +impl GradientFade { + pub fn new(base_bg: Hsla, hover_bg: Hsla, active_bg: Hsla) -> Self { + Self { + base_bg, + hover_bg, + active_bg, + width: px(48.0), + right: px(0.0), + gradient_stop: 0.6, + group_name: None, + } + } + + pub fn width(mut self, width: Pixels) -> Self { + self.width = width; + self + } + + pub fn right(mut self, right: Pixels) -> Self { + self.right = right; + self + } + + pub fn gradient_stop(mut self, stop: f32) -> Self { + self.gradient_stop = stop; + self + } + + pub fn group_name(mut self, name: impl Into) -> Self { + self.group_name = Some(name.into()); + self + } +} + +impl RenderOnce for GradientFade { + fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement { + let stop = self.gradient_stop; + let hover_bg = self.hover_bg; + let active_bg = self.active_bg; + + div() + .id("gradient_fade") + .absolute() + .top_0() + .right(self.right) + .w(self.width) + .h_full() + .bg(linear_gradient( + 90., + linear_color_stop(self.base_bg, stop), + linear_color_stop(self.base_bg.opacity(0.0), 0.), + )) + .when_some(self.group_name.clone(), |element, group_name| { + element.group_hover(group_name, move |s| { + s.bg(linear_gradient( + 90., + linear_color_stop(hover_bg, stop), + linear_color_stop(hover_bg.opacity(0.0), 0.), + )) + }) + }) + .when_some(self.group_name, |element, group_name| { + element.group_active(group_name, move |s| { + s.bg(linear_gradient( + 90., + linear_color_stop(active_bg, stop), + linear_color_stop(active_bg.opacity(0.0), 0.), + )) + }) + }) + } +} diff --git a/crates/ui/src/components/list/list_item.rs b/crates/ui/src/components/list/list_item.rs index 0a1fbe7f40970f265513751090ed998a5521dfef..dc2fc76a06c29c72457d385effd06ea71e5f9625 100644 --- a/crates/ui/src/components/list/list_item.rs +++ b/crates/ui/src/components/list/list_item.rs @@ -1,13 +1,10 @@ use std::sync::Arc; use component::{Component, ComponentScope, example_group_with_title, single_example}; -use gpui::{ - AnyElement, AnyView, ClickEvent, MouseButton, MouseDownEvent, Pixels, linear_color_stop, - linear_gradient, px, -}; +use gpui::{AnyElement, AnyView, ClickEvent, MouseButton, MouseDownEvent, Pixels, px}; use smallvec::SmallVec; -use crate::{Disclosure, prelude::*}; +use crate::{Disclosure, GradientFade, prelude::*}; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] pub enum ListItemSpacing { @@ -220,34 +217,12 @@ impl RenderOnce for ListItem { color.panel_background }; - let end_hover_gradient_overlay = div() - .id("gradient_overlay") - .absolute() - .top_0() - .right_0() - .w_24() - .h_full() - .bg(linear_gradient( - 90., - linear_color_stop(base_bg, 0.6), - linear_color_stop(base_bg.opacity(0.0), 0.), - )) - .when_some(self.group_name.clone(), |s, group_name| { - s.group_hover(group_name.clone(), |s| { - s.bg(linear_gradient( - 90., - linear_color_stop(color.element_hover, 0.6), - linear_color_stop(color.element_hover.opacity(0.0), 0.), - )) - }) - .group_active(group_name, |s| { - s.bg(linear_gradient( - 90., - linear_color_stop(color.element_active, 0.6), - linear_color_stop(color.element_active.opacity(0.0), 0.), - )) - }) - }); + let end_hover_gradient_overlay = + GradientFade::new(base_bg, color.element_hover, color.element_active) + .width(px(96.0)) + .when_some(self.group_name.clone(), |fade, group| { + fade.group_name(group) + }); h_flex() .id(self.id)