From f4609c04eb7b908f7565f6e89c54d968452a8cf0 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Wed, 15 Oct 2025 19:50:44 -0300 Subject: [PATCH] agent: Improve pickers and their triggers styles in the panel (#40284) Making all triggers have the same style when the picker is open (including changing the icon when the picker opens on top of the trigger). Also removed the footer from the ACP model selector given there's nothing to consider when that's the case; users can only configure LLM providers when using Zed's built-in agent. Release Notes: - N/A --- crates/agent_ui/src/acp/mode_selector.rs | 9 ++++- crates/agent_ui/src/acp/model_selector.rs | 38 ++----------------- .../src/acp/model_selector_popover.rs | 14 +++---- crates/agent_ui/src/agent_model_selector.rs | 20 +++++++--- crates/agent_ui/src/profile_selector.rs | 8 +++- crates/agent_ui/src/text_thread_editor.rs | 27 +++++++------ crates/picker/src/popover_menu.rs | 21 ++++++---- 7 files changed, 65 insertions(+), 72 deletions(-) diff --git a/crates/agent_ui/src/acp/mode_selector.rs b/crates/agent_ui/src/acp/mode_selector.rs index 4108741266..dda33bd17d 100644 --- a/crates/agent_ui/src/acp/mode_selector.rs +++ b/crates/agent_ui/src/acp/mode_selector.rs @@ -174,11 +174,16 @@ impl Render for ModeSelector { let this = cx.entity(); + let icon = if self.menu_handle.is_deployed() { + IconName::ChevronUp + } else { + IconName::ChevronDown + }; + let trigger_button = Button::new("mode-selector-trigger", current_mode_name) .label_size(LabelSize::Small) - .style(ButtonStyle::Subtle) .color(Color::Muted) - .icon(IconName::ChevronDown) + .icon(icon) .icon_size(IconSize::XSmall) .icon_position(IconPosition::End) .icon_color(Color::Muted) diff --git a/crates/agent_ui/src/acp/model_selector.rs b/crates/agent_ui/src/acp/model_selector.rs index 381bdb01ed..45fec55872 100644 --- a/crates/agent_ui/src/acp/model_selector.rs +++ b/crates/agent_ui/src/acp/model_selector.rs @@ -5,12 +5,12 @@ use anyhow::Result; use collections::IndexMap; use futures::FutureExt; use fuzzy::{StringMatchCandidate, match_strings}; -use gpui::{Action, AsyncWindowContext, BackgroundExecutor, DismissEvent, Task, WeakEntity}; +use gpui::{AsyncWindowContext, BackgroundExecutor, DismissEvent, Task, WeakEntity}; use ordered_float::OrderedFloat; use picker::{Picker, PickerDelegate}; use ui::{ - AnyElement, App, Context, DocumentationAside, DocumentationEdge, DocumentationSide, - IntoElement, ListItem, ListItemSpacing, SharedString, Window, prelude::*, rems, + DocumentationAside, DocumentationEdge, DocumentationSide, IntoElement, ListItem, + ListItemSpacing, prelude::*, }; use util::ResultExt; @@ -278,36 +278,6 @@ impl PickerDelegate for AcpModelPickerDelegate { } } - fn render_footer( - &self, - _: &mut Window, - cx: &mut Context>, - ) -> Option { - Some( - h_flex() - .w_full() - .border_t_1() - .border_color(cx.theme().colors().border_variant) - .p_1() - .gap_4() - .justify_between() - .child( - Button::new("configure", "Configure") - .icon(IconName::Settings) - .icon_size(IconSize::Small) - .icon_color(Color::Muted) - .icon_position(IconPosition::Start) - .on_click(|_, window, cx| { - window.dispatch_action( - zed_actions::agent::OpenSettings.boxed_clone(), - cx, - ); - }), - ) - .into_any(), - ) - } - fn documentation_aside( &self, _window: &mut Window, @@ -317,7 +287,7 @@ impl PickerDelegate for AcpModelPickerDelegate { let description = description.clone(); DocumentationAside::new( DocumentationSide::Left, - DocumentationEdge::Bottom, + DocumentationEdge::Top, Rc::new(move |_| Label::new(description.clone()).into_any_element()), ) }) diff --git a/crates/agent_ui/src/acp/model_selector_popover.rs b/crates/agent_ui/src/acp/model_selector_popover.rs index 55f530c81b..474125d69d 100644 --- a/crates/agent_ui/src/acp/model_selector_popover.rs +++ b/crates/agent_ui/src/acp/model_selector_popover.rs @@ -57,30 +57,26 @@ impl Render for AcpModelSelectorPopover { let focus_handle = self.focus_handle.clone(); - let color = if self.menu_handle.is_deployed() { - Color::Accent + let (color, icon) = if self.menu_handle.is_deployed() { + (Color::Accent, IconName::ChevronUp) } else { - Color::Muted + (Color::Muted, IconName::ChevronDown) }; PickerPopoverMenu::new( self.selector.clone(), ButtonLike::new("active-model") + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .when_some(model_icon, |this, icon| { this.child(Icon::new(icon).color(color).size(IconSize::XSmall)) }) - .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .child( Label::new(model_name) .color(color) .size(LabelSize::Small) .ml_0p5(), ) - .child( - Icon::new(IconName::ChevronDown) - .color(Color::Muted) - .size(IconSize::XSmall), - ), + .child(Icon::new(icon).color(Color::Muted).size(IconSize::XSmall)), move |window, cx| { Tooltip::for_action_in( "Change Model", diff --git a/crates/agent_ui/src/agent_model_selector.rs b/crates/agent_ui/src/agent_model_selector.rs index fe25cadc3c..c368ee73b3 100644 --- a/crates/agent_ui/src/agent_model_selector.rs +++ b/crates/agent_ui/src/agent_model_selector.rs @@ -7,7 +7,7 @@ use gpui::{Entity, FocusHandle, SharedString}; use picker::popover_menu::PickerPopoverMenu; use settings::update_settings_file; use std::sync::Arc; -use ui::{ButtonLike, PopoverMenuHandle, Tooltip, prelude::*}; +use ui::{ButtonLike, PopoverMenuHandle, TintColor, Tooltip, prelude::*}; use zed_actions::agent::ToggleModelSelector; pub struct AgentModelSelector { @@ -70,6 +70,11 @@ impl Render for AgentModelSelector { .unwrap_or_else(|| SharedString::from("Select a Model")); let provider_icon = model.as_ref().map(|model| model.provider.icon()); + let color = if self.menu_handle.is_deployed() { + Color::Accent + } else { + Color::Muted + }; let focus_handle = self.focus_handle.clone(); @@ -77,17 +82,18 @@ impl Render for AgentModelSelector { self.selector.clone(), ButtonLike::new("active-model") .when_some(provider_icon, |this, icon| { - this.child(Icon::new(icon).color(Color::Muted).size(IconSize::XSmall)) + this.child(Icon::new(icon).color(color).size(IconSize::XSmall)) }) + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .child( Label::new(model_name) - .color(Color::Muted) + .color(color) .size(LabelSize::Small) .ml_0p5(), ) .child( Icon::new(IconName::ChevronDown) - .color(Color::Muted) + .color(color) .size(IconSize::XSmall), ), move |window, cx| { @@ -99,10 +105,14 @@ impl Render for AgentModelSelector { cx, ) }, - gpui::Corner::BottomRight, + gpui::Corner::TopRight, cx, ) .with_handle(self.menu_handle.clone()) + .offset(gpui::Point { + x: px(0.0), + y: px(2.0), + }) .render(window, cx) } } diff --git a/crates/agent_ui/src/profile_selector.rs b/crates/agent_ui/src/profile_selector.rs index d52b2436d6..ef9e1e6917 100644 --- a/crates/agent_ui/src/profile_selector.rs +++ b/crates/agent_ui/src/profile_selector.rs @@ -144,10 +144,16 @@ impl Render for ProfileSelector { .unwrap_or_else(|| "Unknown".into()); let focus_handle = self.focus_handle.clone(); + let icon = if self.picker_handle.is_deployed() { + IconName::ChevronUp + } else { + IconName::ChevronDown + }; + let trigger_button = Button::new("profile-selector", selected_profile) .label_size(LabelSize::Small) .color(Color::Muted) - .icon(IconName::ChevronDown) + .icon(icon) .icon_size(IconSize::XSmall) .icon_position(IconPosition::End) .icon_color(Color::Muted) diff --git a/crates/agent_ui/src/text_thread_editor.rs b/crates/agent_ui/src/text_thread_editor.rs index e1265e923e..5e4ecf3db1 100644 --- a/crates/agent_ui/src/text_thread_editor.rs +++ b/crates/agent_ui/src/text_thread_editor.rs @@ -1977,7 +1977,9 @@ impl TextThreadEditor { cx.entity().downgrade(), IconButton::new("trigger", IconName::Plus) .icon_size(IconSize::Small) - .icon_color(Color::Muted), + .icon_color(Color::Muted) + .selected_icon_color(Color::Accent) + .selected_style(ButtonStyle::Filled), move |window, cx| { Tooltip::with_meta( "Add Context", @@ -2052,30 +2054,27 @@ impl TextThreadEditor { }; let focus_handle = self.editor().focus_handle(cx); + let (color, icon) = if self.language_model_selector_menu_handle.is_deployed() { + (Color::Accent, IconName::ChevronUp) + } else { + (Color::Muted, IconName::ChevronDown) + }; PickerPopoverMenu::new( self.language_model_selector.clone(), ButtonLike::new("active-model") - .style(ButtonStyle::Subtle) + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .child( h_flex() .gap_0p5() - .child( - Icon::new(provider_icon) - .color(Color::Muted) - .size(IconSize::XSmall), - ) + .child(Icon::new(provider_icon).color(color).size(IconSize::XSmall)) .child( Label::new(model_name) - .color(Color::Muted) + .color(color) .size(LabelSize::Small) .ml_0p5(), ) - .child( - Icon::new(IconName::ChevronDown) - .color(Color::Muted) - .size(IconSize::XSmall), - ), + .child(Icon::new(icon).color(color).size(IconSize::XSmall)), ), move |window, cx| { Tooltip::for_action_in( @@ -2086,7 +2085,7 @@ impl TextThreadEditor { cx, ) }, - gpui::Corner::BottomLeft, + gpui::Corner::BottomRight, cx, ) .with_handle(self.language_model_selector_menu_handle.clone()) diff --git a/crates/picker/src/popover_menu.rs b/crates/picker/src/popover_menu.rs index baf0918fd6..42eedb2492 100644 --- a/crates/picker/src/popover_menu.rs +++ b/crates/picker/src/popover_menu.rs @@ -1,9 +1,9 @@ use gpui::{ - AnyView, Corner, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Subscription, + AnyView, Corner, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Pixels, Point, + Subscription, }; use ui::{ - App, ButtonCommon, FluentBuilder as _, IntoElement, PopoverMenu, PopoverMenuHandle, - PopoverTrigger, RenderOnce, Window, px, + FluentBuilder as _, IntoElement, PopoverMenu, PopoverMenuHandle, PopoverTrigger, prelude::*, }; use crate::{Picker, PickerDelegate}; @@ -19,6 +19,7 @@ where tooltip: TT, handle: Option>>, anchor: Corner, + offset: Option>, _subscriptions: Vec, } @@ -43,6 +44,10 @@ where trigger, tooltip, handle: None, + offset: Some(Point { + x: px(0.0), + y: px(-2.0), + }), anchor, } } @@ -51,6 +56,11 @@ where self.handle = Some(handle); self } + + pub fn offset(mut self, offset: Point) -> Self { + self.offset = Some(offset); + self + } } impl EventEmitter for PickerPopoverMenu @@ -86,9 +96,6 @@ where .trigger_with_tooltip(self.trigger, self.tooltip) .anchor(self.anchor) .when_some(self.handle, |menu, handle| menu.with_handle(handle)) - .offset(gpui::Point { - x: px(0.0), - y: px(-2.0), - }) + .when_some(self.offset, |menu, offset| menu.offset(offset)) } }