ui: Refactor the Button component icon methods (#51496)
Previously, if you wanted to have a button that contains icons on both
edges, you'd need to use a `ButtonLike` component, which takes any
children. Meanwhile, the `Button` would only take one icon, where you
could control its position through the `IconPosition` enum. This has
always felt unnecessarily limiting. So, this PR removes this limitation
by adding two new methods to the button: `start_icon` and `end_icon`.
In the meantime, I have also been bothered by the unnecessary
indirection in the `IconButton` due to the existence of the `ButtonIcon`
component. So I figured I could also completely eliminate that by adding
some of its methods directly to the `IconButton` and in the Button, just
using a regular `Icon` component.
---
## Before
```rust
Button::new("id", "Label")
.icon(IconName::Plus)
.icon_position(IconPosition::Start)
.icon_size(IconSize::Small)
.icon_color(Color::Muted)
```
## After
```rust
Button::new("id", "Label")
.start_icon(Icon::new(IconName::Check))
.end_icon(Icon::new(IconName::ChevronDown).size(IconSize::XSmall))
```
This should have no visual impact to the UI.
Release Notes:
- N/A
This commit is contained in:
1 parent
a623dc3d1a
commit
4e8937b62d
64 files changed
+584
-847
No files matched your search
@@ -332,10 +332,11 @@ impl AgentConfiguration {
|
||||
.full_width()
|
||||
.style(ButtonStyle::Outlined)
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon(IconName::Thread)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Thread)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.on_click(cx.listener({
|
||||
let provider = provider.clone();
|
||||
@@ -357,10 +358,11 @@ impl AgentConfiguration {
|
||||
)
|
||||
.full_width()
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon(IconName::Trash)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Trash)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.on_click(cx.listener({
|
||||
let provider = provider.clone();
|
||||
@@ -426,10 +428,11 @@ impl AgentConfiguration {
|
||||
.trigger(
|
||||
Button::new("add-provider", "Add Provider")
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon(IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Plus)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small),
|
||||
)
|
||||
.menu({
|
||||
@@ -525,10 +528,11 @@ impl AgentConfiguration {
|
||||
.trigger(
|
||||
Button::new("add-server", "Add Server")
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon(IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Plus)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small),
|
||||
)
|
||||
.menu({
|
||||
@@ -970,10 +974,11 @@ impl AgentConfiguration {
|
||||
.trigger(
|
||||
Button::new("add-agent", "Add Agent")
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon(IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Plus)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small),
|
||||
)
|
||||
.menu({
|
||||
|
||||
@@ -340,10 +340,11 @@ impl AddLlmProviderModal {
|
||||
.child(Label::new("Models").size(LabelSize::Small))
|
||||
.child(
|
||||
Button::new("add-model", "Add Model")
|
||||
.icon(IconName::Plus)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Plus)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.input.add_model(window, cx);
|
||||
@@ -446,10 +447,11 @@ impl AddLlmProviderModal {
|
||||
.when(has_more_than_one_model, |this| {
|
||||
this.child(
|
||||
Button::new(("remove-model", ix), "Remove Model")
|
||||
.icon(IconName::Trash)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Trash)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.full_width()
|
||||
|
||||
@@ -693,9 +693,11 @@ impl ConfigureContextServerModal {
|
||||
{
|
||||
Some(
|
||||
Button::new("open-repository", "Open Repository")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.tooltip({
|
||||
let repository_url = repository_url.clone();
|
||||
move |_window, cx| {
|
||||
|
||||
@@ -686,10 +686,11 @@ impl Render for AgentDiffPane {
|
||||
.child(
|
||||
Button::new("continue-iterating", "Continue Iterating")
|
||||
.style(ButtonStyle::Filled)
|
||||
.icon(IconName::ForwardArrow)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::ForwardArrow)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.full_width()
|
||||
.key_binding(KeyBinding::for_action_in(
|
||||
&ToggleFocus,
|
||||
|
||||
@@ -9,7 +9,7 @@ use language_model::IconOrSvg;
|
||||
use picker::popover_menu::PickerPopoverMenu;
|
||||
use settings::update_settings_file;
|
||||
use std::sync::Arc;
|
||||
use ui::{ButtonLike, PopoverMenuHandle, TintColor, Tooltip, prelude::*};
|
||||
use ui::{PopoverMenuHandle, Tooltip, prelude::*};
|
||||
|
||||
pub struct AgentModelSelector {
|
||||
selector: Entity<LanguageModelSelector>,
|
||||
@@ -112,9 +112,11 @@ impl Render for AgentModelSelector {
|
||||
|
||||
PickerPopoverMenu::new(
|
||||
self.selector.clone(),
|
||||
ButtonLike::new("active-model")
|
||||
Button::new("active-model", model_name)
|
||||
.label_size(LabelSize::Small)
|
||||
.color(color)
|
||||
.when_some(provider_icon, |this, icon| {
|
||||
this.child(
|
||||
this.start_icon(
|
||||
match icon {
|
||||
IconOrSvg::Svg(path) => Icon::from_external_svg(path),
|
||||
IconOrSvg::Icon(name) => Icon::new(name),
|
||||
@@ -123,14 +125,7 @@ impl Render for AgentModelSelector {
|
||||
.size(IconSize::XSmall),
|
||||
)
|
||||
})
|
||||
.selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.child(
|
||||
Label::new(model_name)
|
||||
.color(color)
|
||||
.size(LabelSize::Small)
|
||||
.ml_0p5(),
|
||||
)
|
||||
.child(
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.color(color)
|
||||
.size(IconSize::XSmall),
|
||||
|
||||
@@ -80,9 +80,8 @@ use search::{BufferSearchBar, buffer_search};
|
||||
use settings::{Settings, update_settings_file};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
Button, ButtonLike, Callout, ContextMenu, ContextMenuEntry, DocumentationSide, Indicator,
|
||||
KeyBinding, PopoverMenu, PopoverMenuHandle, SpinnerLabel, Tab, TintColor, Tooltip, prelude::*,
|
||||
utils::WithRemSize,
|
||||
Button, Callout, ContextMenu, ContextMenuEntry, DocumentationSide, Indicator, KeyBinding,
|
||||
PopoverMenu, PopoverMenuHandle, SpinnerLabel, Tab, Tooltip, prelude::*, utils::WithRemSize,
|
||||
};
|
||||
use util::{ResultExt as _, debug_panic};
|
||||
use workspace::{
|
||||
@@ -3632,11 +3631,7 @@ impl AgentPanel {
|
||||
};
|
||||
|
||||
let trigger_button = Button::new("thread-target-trigger", trigger_label)
|
||||
.icon(icon)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
|
||||
.disabled(is_creating);
|
||||
|
||||
let dock_position = AgentSettings::get_global(cx).dock;
|
||||
@@ -4290,32 +4285,22 @@ impl AgentPanel {
|
||||
(IconName::ChevronDown, Color::Muted, Color::Default)
|
||||
};
|
||||
|
||||
let agent_icon_element: AnyElement =
|
||||
if let Some(icon_path) = selected_agent_custom_icon_for_button {
|
||||
Icon::from_external_svg(icon_path)
|
||||
.size(IconSize::Small)
|
||||
.color(icon_color)
|
||||
.into_any_element()
|
||||
} else {
|
||||
let icon_name = selected_agent_builtin_icon.unwrap_or(IconName::ZedAgent);
|
||||
Icon::new(icon_name)
|
||||
.size(IconSize::Small)
|
||||
.color(icon_color)
|
||||
.into_any_element()
|
||||
};
|
||||
let agent_icon = if let Some(icon_path) = selected_agent_custom_icon_for_button {
|
||||
Icon::from_external_svg(icon_path)
|
||||
.size(IconSize::Small)
|
||||
.color(icon_color)
|
||||
} else {
|
||||
let icon_name = selected_agent_builtin_icon.unwrap_or(IconName::ZedAgent);
|
||||
Icon::new(icon_name).size(IconSize::Small).color(icon_color)
|
||||
};
|
||||
|
||||
let agent_selector_button = ButtonLike::new("agent-selector-trigger")
|
||||
.selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(agent_icon_element)
|
||||
.child(Label::new(selected_agent_label).color(label_color).ml_0p5())
|
||||
.child(
|
||||
Icon::new(chevron_icon)
|
||||
.color(icon_color)
|
||||
.size(IconSize::XSmall),
|
||||
),
|
||||
let agent_selector_button = Button::new("agent-selector-trigger", selected_agent_label)
|
||||
.start_icon(agent_icon)
|
||||
.color(label_color)
|
||||
.end_icon(
|
||||
Icon::new(chevron_icon)
|
||||
.color(icon_color)
|
||||
.size(IconSize::XSmall),
|
||||
);
|
||||
|
||||
let agent_selector_menu = PopoverMenu::new("new_thread_menu")
|
||||
|
||||
@@ -467,10 +467,11 @@ impl AgentRegistryPage {
|
||||
let agent_id = agent.id().to_string();
|
||||
Button::new(button_id, "Install")
|
||||
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.icon(IconName::Download)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Download)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _, cx| {
|
||||
let agent_id = agent_id.clone();
|
||||
update_settings_file(fs.clone(), cx, move |settings, _| {
|
||||
@@ -541,9 +542,11 @@ impl Render for AgentRegistryPage {
|
||||
Button::new("learn-more", "Learn More")
|
||||
.style(ButtonStyle::Outlined)
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _, cx| {
|
||||
cx.open_url(&zed_urls::acp_registry_blog(cx))
|
||||
}),
|
||||
|
||||
@@ -350,10 +350,7 @@ impl ConfigOptionSelector {
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.icon(icon)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
|
||||
.disabled(self.setting_value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3826,11 +3826,8 @@ impl ThreadView {
|
||||
.child(Divider::horizontal())
|
||||
.child(
|
||||
Button::new("restore-checkpoint", "Restore Checkpoint")
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Undo).size(IconSize::XSmall).color(Color::Muted))
|
||||
.label_size(LabelSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.color(Color::Muted)
|
||||
.tooltip(Tooltip::text("Restores all files in the project to the content they had at this point in the conversation."))
|
||||
.on_click(cx.listener(move |this, _, _window, cx| {
|
||||
@@ -5783,10 +5780,11 @@ impl ThreadView {
|
||||
.gap_0p5()
|
||||
.child(
|
||||
Button::new(("allow-btn", entry_ix), "Allow")
|
||||
.icon(IconName::Check)
|
||||
.icon_color(Color::Success)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Check)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Success),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.when(is_first, |this| {
|
||||
this.key_binding(
|
||||
@@ -5817,10 +5815,11 @@ impl ThreadView {
|
||||
)
|
||||
.child(
|
||||
Button::new(("deny-btn", entry_ix), "Deny")
|
||||
.icon(IconName::Close)
|
||||
.icon_color(Color::Error)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Close)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Error),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.when(is_first, |this| {
|
||||
this.key_binding(
|
||||
@@ -5887,9 +5886,11 @@ impl ThreadView {
|
||||
.with_handle(permission_dropdown_handle)
|
||||
.trigger(
|
||||
Button::new(("granularity-trigger", entry_ix), current_label)
|
||||
.icon(IconName::ChevronDown)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.when(is_first, |this| {
|
||||
this.key_binding(
|
||||
@@ -5962,24 +5963,35 @@ impl ThreadView {
|
||||
let option_id = SharedString::from(option.option_id.0.clone());
|
||||
Button::new((option_id, entry_ix), option.name.clone())
|
||||
.map(|this| {
|
||||
let (this, action) = match option.kind {
|
||||
let (icon, action) = match option.kind {
|
||||
acp::PermissionOptionKind::AllowOnce => (
|
||||
this.icon(IconName::Check).icon_color(Color::Success),
|
||||
Icon::new(IconName::Check)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Success),
|
||||
Some(&AllowOnce as &dyn Action),
|
||||
),
|
||||
acp::PermissionOptionKind::AllowAlways => (
|
||||
this.icon(IconName::CheckDouble).icon_color(Color::Success),
|
||||
Icon::new(IconName::CheckDouble)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Success),
|
||||
Some(&AllowAlways as &dyn Action),
|
||||
),
|
||||
acp::PermissionOptionKind::RejectOnce => (
|
||||
this.icon(IconName::Close).icon_color(Color::Error),
|
||||
Icon::new(IconName::Close)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Error),
|
||||
Some(&RejectOnce as &dyn Action),
|
||||
),
|
||||
acp::PermissionOptionKind::RejectAlways | _ => {
|
||||
(this.icon(IconName::Close).icon_color(Color::Error), None)
|
||||
}
|
||||
acp::PermissionOptionKind::RejectAlways | _ => (
|
||||
Icon::new(IconName::Close)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Error),
|
||||
None,
|
||||
),
|
||||
};
|
||||
|
||||
let this = this.start_icon(icon);
|
||||
|
||||
let Some(action) = action else {
|
||||
return this;
|
||||
};
|
||||
@@ -5995,8 +6007,6 @@ impl ThreadView {
|
||||
.map(|kb| kb.size(rems_from_px(10.))),
|
||||
)
|
||||
})
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.label_size(LabelSize::Small)
|
||||
.on_click(cx.listener({
|
||||
let session_id = session_id.clone();
|
||||
@@ -6373,9 +6383,11 @@ impl ThreadView {
|
||||
.color(Color::Muted)
|
||||
.truncate(true)
|
||||
.when(is_file.is_none(), |this| {
|
||||
this.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
this.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
})
|
||||
.on_click(cx.listener({
|
||||
let workspace = self.workspace.clone();
|
||||
@@ -7470,19 +7482,16 @@ impl ThreadView {
|
||||
.title("Codex on Windows")
|
||||
.description("For best performance, run Codex in Windows Subsystem for Linux (WSL2)")
|
||||
.actions_slot(
|
||||
Button::new("open-wsl-modal", "Open in WSL")
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.on_click(cx.listener({
|
||||
move |_, _, _window, cx| {
|
||||
#[cfg(windows)]
|
||||
_window.dispatch_action(
|
||||
zed_actions::wsl_actions::OpenWsl::default().boxed_clone(),
|
||||
cx,
|
||||
);
|
||||
cx.notify();
|
||||
}
|
||||
})),
|
||||
Button::new("open-wsl-modal", "Open in WSL").on_click(cx.listener({
|
||||
move |_, _, _window, cx| {
|
||||
#[cfg(windows)]
|
||||
_window.dispatch_action(
|
||||
zed_actions::wsl_actions::OpenWsl::default().boxed_clone(),
|
||||
cx,
|
||||
);
|
||||
cx.notify();
|
||||
}
|
||||
})),
|
||||
)
|
||||
.dismiss_action(
|
||||
IconButton::new("dismiss", IconName::Close)
|
||||
|
||||
@@ -796,9 +796,11 @@ impl<T: 'static> PromptEditor<T> {
|
||||
vec![
|
||||
Button::new("start", mode.start_label())
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Return)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::Return)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(
|
||||
cx.listener(|_, _, _, cx| cx.emit(PromptEditorEvent::StartRequested)),
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@ use rope::Point;
|
||||
use settings::Settings;
|
||||
use std::{cell::RefCell, fmt::Write, ops::Range, rc::Rc, sync::Arc};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{ButtonLike, ButtonStyle, ContextMenu, Disclosure, ElevationIndex, prelude::*};
|
||||
use ui::{ContextMenu, Disclosure, ElevationIndex, prelude::*};
|
||||
use util::paths::PathStyle;
|
||||
use util::{ResultExt, debug_panic};
|
||||
use workspace::{CollaboratorId, Workspace};
|
||||
@@ -1161,11 +1161,9 @@ impl MessageEditor {
|
||||
render: Arc::new({
|
||||
let title = title.clone();
|
||||
move |_fold_id, _fold_range, _cx| {
|
||||
ButtonLike::new("crease")
|
||||
.style(ButtonStyle::Filled)
|
||||
Button::new("crease", title.clone())
|
||||
.layer(ElevationIndex::ElevatedSurface)
|
||||
.child(Icon::new(icon))
|
||||
.child(Label::new(title.clone()).single_line())
|
||||
.start_icon(Icon::new(icon))
|
||||
.into_any_element()
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -169,10 +169,7 @@ impl Render for ModeSelector {
|
||||
let trigger_button = Button::new("mode-selector-trigger", current_mode_name)
|
||||
.label_size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.icon(icon)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
|
||||
.disabled(self.setting_mode);
|
||||
|
||||
PopoverMenu::new("mode-selector")
|
||||
|
||||
@@ -5,7 +5,7 @@ use acp_thread::{AgentModelIcon, AgentModelInfo, AgentModelSelector};
|
||||
use fs::Fs;
|
||||
use gpui::{AnyView, Entity, FocusHandle};
|
||||
use picker::popover_menu::PickerPopoverMenu;
|
||||
use ui::{ButtonLike, PopoverMenuHandle, TintColor, Tooltip, prelude::*};
|
||||
use ui::{PopoverMenuHandle, Tooltip, prelude::*};
|
||||
|
||||
use crate::ui::ModelSelectorTooltip;
|
||||
use crate::{ModelSelector, model_selector::acp_model_selector};
|
||||
@@ -96,11 +96,12 @@ impl Render for ModelSelectorPopover {
|
||||
|
||||
PickerPopoverMenu::new(
|
||||
self.selector.clone(),
|
||||
ButtonLike::new("active-model")
|
||||
Button::new("active-model", model_name)
|
||||
.label_size(LabelSize::Small)
|
||||
.color(color)
|
||||
.disabled(self.disabled)
|
||||
.selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.when_some(model_icon, |this, icon| {
|
||||
this.child(
|
||||
this.start_icon(
|
||||
match icon {
|
||||
AgentModelIcon::Path(path) => Icon::from_external_svg(path),
|
||||
AgentModelIcon::Named(icon_name) => Icon::new(icon_name),
|
||||
@@ -109,13 +110,7 @@ impl Render for ModelSelectorPopover {
|
||||
.size(IconSize::XSmall),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
Label::new(model_name)
|
||||
.color(color)
|
||||
.size(LabelSize::Small)
|
||||
.ml_0p5(),
|
||||
)
|
||||
.child(
|
||||
.end_icon(
|
||||
Icon::new(icon)
|
||||
.map(|this| {
|
||||
if self.disabled {
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::{
|
||||
};
|
||||
use ui::{
|
||||
DocumentationAside, DocumentationSide, HighlightedLabel, KeyBinding, LabelSize, ListItem,
|
||||
ListItemSpacing, PopoverMenuHandle, TintColor, Tooltip, prelude::*,
|
||||
ListItemSpacing, PopoverMenuHandle, Tooltip, prelude::*,
|
||||
};
|
||||
|
||||
/// Trait for types that can provide and manage agent profiles
|
||||
@@ -192,11 +192,7 @@ impl Render for ProfileSelector {
|
||||
.disabled(self.disabled)
|
||||
.label_size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.icon(icon)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.selected_style(ButtonStyle::Tinted(TintColor::Accent));
|
||||
.end_icon(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted));
|
||||
|
||||
let disabled = self.disabled;
|
||||
|
||||
|
||||
@@ -1775,10 +1775,11 @@ impl Sidebar {
|
||||
)
|
||||
.full_width()
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon(IconName::Plus)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Plus)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.toggle_state(is_selected)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.selection = None;
|
||||
@@ -1833,10 +1834,11 @@ impl Sidebar {
|
||||
.full_width()
|
||||
.label_size(LabelSize::Small)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon(IconName::Archive)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Archive)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.show_archive(window, cx);
|
||||
})),
|
||||
|
||||
@@ -1191,11 +1191,11 @@ impl TextThreadEditor {
|
||||
Button::new("show-error", "Error")
|
||||
.color(Color::Error)
|
||||
.selected_label_color(Color::Error)
|
||||
.selected_icon_color(Color::Error)
|
||||
.icon(IconName::XCircle)
|
||||
.icon_color(Color::Error)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::XCircle)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Error),
|
||||
)
|
||||
.tooltip(Tooltip::text("View Details"))
|
||||
.on_click({
|
||||
let text_thread = text_thread.clone();
|
||||
@@ -2287,20 +2287,11 @@ impl TextThreadEditor {
|
||||
|
||||
PickerPopoverMenu::new(
|
||||
self.language_model_selector.clone(),
|
||||
ButtonLike::new("active-model")
|
||||
.selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_0p5()
|
||||
.child(provider_icon_element)
|
||||
.child(
|
||||
Label::new(model_name)
|
||||
.color(color)
|
||||
.size(LabelSize::Small)
|
||||
.ml_0p5(),
|
||||
)
|
||||
.child(Icon::new(icon).color(color).size(IconSize::XSmall)),
|
||||
),
|
||||
Button::new("active-model", model_name)
|
||||
.color(color)
|
||||
.label_size(LabelSize::Small)
|
||||
.start_icon(provider_icon_element)
|
||||
.end_icon(Icon::new(icon).color(color).size(IconSize::XSmall)),
|
||||
tooltip,
|
||||
gpui::Corner::BottomRight,
|
||||
cx,
|
||||
|
||||
@@ -193,15 +193,16 @@ impl Render for AcpOnboardingModal {
|
||||
let copy = "Bring the agent of your choice to Zed via our new Agent Client Protocol (ACP), starting with Google's Gemini CLI integration.";
|
||||
|
||||
let open_panel_button = Button::new("open-panel", "Start with Gemini CLI")
|
||||
.icon_size(IconSize::Indicator)
|
||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.full_width()
|
||||
.on_click(cx.listener(Self::open_panel));
|
||||
|
||||
let docs_button = Button::new("add-other-agents", "Add Other Agents")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Indicator)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Indicator)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.full_width()
|
||||
.on_click(cx.listener(Self::open_agent_registry));
|
||||
|
||||
|
||||
@@ -201,15 +201,16 @@ impl Render for ClaudeCodeOnboardingModal {
|
||||
let copy = "Powered by the Agent Client Protocol, you can now run Claude Agent as\na first-class citizen in Zed's agent panel.";
|
||||
|
||||
let open_panel_button = Button::new("open-panel", "Start with Claude Agent")
|
||||
.icon_size(IconSize::Indicator)
|
||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.full_width()
|
||||
.on_click(cx.listener(Self::open_panel));
|
||||
|
||||
let docs_button = Button::new("add-other-agents", "Add Other Agents")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Indicator)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Indicator)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.full_width()
|
||||
.on_click(cx.listener(Self::view_docs));
|
||||
|
||||
|
||||
@@ -2347,9 +2347,7 @@ impl CollabPanel {
|
||||
.gap_2()
|
||||
.child(
|
||||
Button::new("sign_in", button_label)
|
||||
.icon_color(Color::Muted)
|
||||
.icon(IconName::Github)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Github).color(Color::Muted))
|
||||
.style(ButtonStyle::Filled)
|
||||
.full_width()
|
||||
.disabled(is_signing_in)
|
||||
@@ -2597,9 +2595,9 @@ impl CollabPanel {
|
||||
Section::Channels => {
|
||||
Some(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
IconButton::new("filter-active-channels", IconName::ListFilter)
|
||||
.icon_size(IconSize::Small)
|
||||
.toggle_state(self.filter_active_channels)
|
||||
.when(!self.filter_active_channels, |button| {
|
||||
button.visible_on_hover("section-header")
|
||||
|
||||
@@ -544,9 +544,7 @@ impl Render for NotificationPanel {
|
||||
.p_4()
|
||||
.child(
|
||||
Button::new("connect_prompt_button", "Connect")
|
||||
.icon_color(Color::Muted)
|
||||
.icon(IconName::Github)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Github).color(Color::Muted))
|
||||
.style(ButtonStyle::Filled)
|
||||
.full_width()
|
||||
.on_click({
|
||||
|
||||
@@ -387,10 +387,11 @@ impl CopilotCodeVerification {
|
||||
.full_width()
|
||||
.style(ButtonStyle::Outlined)
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(IconName::Download)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Download)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, window, cx| {
|
||||
reinstall_and_sign_in(copilot.clone(), window, cx)
|
||||
}),
|
||||
@@ -570,10 +571,11 @@ impl ConfigurationView {
|
||||
}
|
||||
})
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon(IconName::Github)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Github)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.when(edit_prediction, |this| this.tab_index(0isize))
|
||||
.on_click(|_, window, cx| {
|
||||
if let Some(app_state) = AppState::global(cx).upgrade()
|
||||
@@ -600,10 +602,11 @@ impl ConfigurationView {
|
||||
}
|
||||
})
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon(IconName::Download)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Download)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(|_, window, cx| {
|
||||
if let Some(app_state) = AppState::global(cx).upgrade()
|
||||
&& let Some(copilot) = GlobalCopilotAuth::try_get_or_init(app_state, cx)
|
||||
|
||||
@@ -1821,20 +1821,22 @@ impl Render for DebugPanel {
|
||||
.gap_2()
|
||||
.child(
|
||||
Button::new("spawn-new-session-empty-state", "New Session")
|
||||
.icon(IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Plus)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(crate::Start.boxed_clone(), cx);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("edit-debug-settings", "Edit debug.json")
|
||||
.icon(IconName::Code)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Code)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(
|
||||
zed_actions::OpenProjectDebugTasks.boxed_clone(),
|
||||
@@ -1844,10 +1846,11 @@ impl Render for DebugPanel {
|
||||
)
|
||||
.child(
|
||||
Button::new("open-debugger-docs", "Debugger Docs")
|
||||
.icon(IconName::Book)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Book)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(|_, _, cx| cx.open_url("https://zed.dev/docs/debugger")),
|
||||
)
|
||||
.child(
|
||||
@@ -1855,10 +1858,11 @@ impl Render for DebugPanel {
|
||||
"spawn-new-session-install-extensions",
|
||||
"Debugger Extensions",
|
||||
)
|
||||
.icon(IconName::Blocks)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Blocks)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(
|
||||
zed_actions::Extensions {
|
||||
|
||||
@@ -765,9 +765,7 @@ impl RatePredictionsModal {
|
||||
.gap_1()
|
||||
.child(
|
||||
Button::new("bad", "Bad Prediction")
|
||||
.icon(IconName::ThumbsDown)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::ThumbsDown).size(IconSize::Small))
|
||||
.disabled(rated || feedback_empty)
|
||||
.when(feedback_empty, |this| {
|
||||
this.tooltip(Tooltip::text(
|
||||
@@ -791,9 +789,7 @@ impl RatePredictionsModal {
|
||||
)
|
||||
.child(
|
||||
Button::new("good", "Good Prediction")
|
||||
.icon(IconName::ThumbsUp)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::ThumbsUp).size(IconSize::Small))
|
||||
.disabled(rated)
|
||||
.key_binding(KeyBinding::for_action_in(
|
||||
&ThumbsUpActivePrediction,
|
||||
|
||||
@@ -1056,10 +1056,11 @@ impl ExtensionsPage {
|
||||
"Install",
|
||||
)
|
||||
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.icon(IconName::Download)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Download)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click({
|
||||
let extension_id = extension.id.clone();
|
||||
move |_, _, cx| {
|
||||
@@ -1078,10 +1079,11 @@ impl ExtensionsPage {
|
||||
"Install",
|
||||
)
|
||||
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.icon(IconName::Download)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Download)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.disabled(true),
|
||||
configure: None,
|
||||
upgrade: None,
|
||||
@@ -1479,10 +1481,11 @@ impl ExtensionsPage {
|
||||
}
|
||||
});
|
||||
let open_registry_button = Button::new("open_registry", "Learn More")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click({
|
||||
move |_event, _window, cx| {
|
||||
telemetry::event!(
|
||||
@@ -1520,9 +1523,7 @@ impl ExtensionsPage {
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let docs_url_button = Button::new("open_docs", "View Documentation")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::End)
|
||||
.end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::Small))
|
||||
.on_click({
|
||||
move |_event, _window, cx| {
|
||||
telemetry::event!(
|
||||
|
||||
@@ -1494,10 +1494,9 @@ impl GitGraph {
|
||||
|
||||
this.child(
|
||||
Button::new("author-email-copy", author_email.clone())
|
||||
.icon(icon)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(icon_color)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(icon).size(IconSize::Small).color(icon_color),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.truncate(true)
|
||||
.color(Color::Muted)
|
||||
@@ -1542,10 +1541,9 @@ impl GitGraph {
|
||||
};
|
||||
|
||||
Button::new("sha-button", &full_sha)
|
||||
.icon(icon)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(icon_color)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(icon).size(IconSize::Small).color(icon_color),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.truncate(true)
|
||||
.color(Color::Muted)
|
||||
@@ -1602,10 +1600,9 @@ impl GitGraph {
|
||||
"view-on-provider",
|
||||
format!("View on {}", provider_name),
|
||||
)
|
||||
.icon(icon)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(icon).size(IconSize::Small).color(Color::Muted),
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.truncate(true)
|
||||
.color(Color::Muted)
|
||||
|
||||
@@ -322,10 +322,11 @@ impl BlameRenderer for GitBlameRenderer {
|
||||
format!("#{}", pr.number),
|
||||
)
|
||||
.color(Color::Muted)
|
||||
.icon(IconName::PullRequest)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(
|
||||
Icon::new(IconName::PullRequest)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
cx.open_url(pr.url.as_str())
|
||||
@@ -339,10 +340,11 @@ impl BlameRenderer for GitBlameRenderer {
|
||||
short_commit_id.clone(),
|
||||
)
|
||||
.color(Color::Muted)
|
||||
.icon(IconName::FileGit)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(
|
||||
Icon::new(IconName::FileGit)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, window, cx| {
|
||||
CommitView::open(
|
||||
commit_summary.sha.clone().into(),
|
||||
|
||||
@@ -366,11 +366,12 @@ impl CommitModal {
|
||||
.unwrap_or_else(|| "<no branch>".to_owned());
|
||||
|
||||
let branch_picker_button = panel_button(branch)
|
||||
.icon(IconName::GitBranch)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Placeholder)
|
||||
.start_icon(
|
||||
Icon::new(IconName::GitBranch)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Placeholder),
|
||||
)
|
||||
.color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.on_click(cx.listener(|_, _, window, cx| {
|
||||
window.dispatch_action(zed_actions::git::Branch.boxed_clone(), cx);
|
||||
}))
|
||||
|
||||
@@ -336,9 +336,10 @@ impl Render for CommitTooltip {
|
||||
format!("#{}", pr.number),
|
||||
)
|
||||
.color(Color::Muted)
|
||||
.icon(IconName::PullRequest)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::PullRequest)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.on_click(move |_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
@@ -354,9 +355,9 @@ impl Render for CommitTooltip {
|
||||
)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.color(Color::Muted)
|
||||
.icon(IconName::FileGit)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::FileGit).color(Color::Muted),
|
||||
)
|
||||
.on_click(
|
||||
move |_, window, cx| {
|
||||
CommitView::open(
|
||||
|
||||
@@ -524,10 +524,11 @@ impl CommitView {
|
||||
.when(self.stash.is_none(), |this| {
|
||||
this.child(
|
||||
Button::new("sha", "Commit SHA")
|
||||
.icon(copy_icon)
|
||||
.icon_color(copy_icon_color)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(
|
||||
Icon::new(copy_icon)
|
||||
.size(IconSize::Small)
|
||||
.color(copy_icon_color),
|
||||
)
|
||||
.tooltip({
|
||||
let commit_sha = commit_sha.clone();
|
||||
move |_, cx| {
|
||||
|
||||
@@ -453,10 +453,11 @@ fn render_conflict_buttons(
|
||||
this.child(Divider::vertical()).child(
|
||||
Button::new("resolve-with-agent", "Resolve with Agent")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::ZedAssistant)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::ZedAssistant)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click({
|
||||
let conflict = conflict.clone();
|
||||
move |_, window, cx| {
|
||||
|
||||
@@ -429,10 +429,11 @@ impl Render for FileHistoryView {
|
||||
Button::new("load-more", "Load More")
|
||||
.disabled(self.loading_more)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::ArrowCircle)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::ArrowCircle)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.load_more(window, cx);
|
||||
})),
|
||||
|
||||
@@ -872,8 +872,7 @@ impl Render for GitCloneModal {
|
||||
.child(
|
||||
Button::new("learn-more", "Learn More")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::XSmall))
|
||||
.on_click(|_, _, cx| {
|
||||
cx.open_url("https://github.com/git-guides/git-clone");
|
||||
}),
|
||||
|
||||
@@ -1592,8 +1592,11 @@ fn render_send_review_to_agent_button(review_count: usize, focus_handle: &FocusH
|
||||
"send-review",
|
||||
format!("Send Review to Agent ({})", review_count),
|
||||
)
|
||||
.icon(IconName::ZedAssistant)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::ZedAssistant)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
"Send all review comments to the Agent panel",
|
||||
&SendReviewToAgent,
|
||||
@@ -1686,10 +1689,11 @@ impl Render for BranchDiffToolbar {
|
||||
let focus_handle = focus_handle.clone();
|
||||
this.child(Divider::vertical()).child(
|
||||
Button::new("review-diff", "Review Diff")
|
||||
.icon(IconName::ZedAssistant)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::ZedAssistant)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.key_binding(KeyBinding::for_action_in(&ReviewDiff, &focus_handle, cx))
|
||||
.tooltip(move |_, cx| {
|
||||
Tooltip::with_meta_in(
|
||||
|
||||
@@ -2928,9 +2928,11 @@ impl Render for KeybindingEditorModal {
|
||||
.child(
|
||||
Button::new("show_matching", "View")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(cx.listener(
|
||||
|this, _, window, cx| {
|
||||
this.show_matching_bindings(
|
||||
|
||||
@@ -1574,7 +1574,8 @@ impl Render for ConfigurationView {
|
||||
}
|
||||
|
||||
v_flex()
|
||||
.size_full()
|
||||
.min_w_0()
|
||||
.w_full()
|
||||
.track_focus(&self.focus_handle)
|
||||
.on_action(cx.listener(Self::on_tab))
|
||||
.on_action(cx.listener(Self::on_tab_prev))
|
||||
|
||||
@@ -1126,6 +1126,7 @@ impl RenderOnce for ZedAiConfiguration {
|
||||
let manage_subscription_buttons = if is_pro {
|
||||
Button::new("manage_settings", "Manage Subscription")
|
||||
.full_width()
|
||||
.label_size(LabelSize::Small)
|
||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.on_click(|_, _, cx| cx.open_url(&zed_urls::account_url(cx)))
|
||||
.into_any_element()
|
||||
@@ -1149,10 +1150,7 @@ impl RenderOnce for ZedAiConfiguration {
|
||||
.child(Label::new("Sign in to have access to Zed's complete agentic experience with hosted models."))
|
||||
.child(
|
||||
Button::new("sign_in", "Sign In to use Zed AI")
|
||||
.icon_color(Color::Muted)
|
||||
.icon(IconName::Github)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Github).size(IconSize::Small).color(Color::Muted))
|
||||
.full_width()
|
||||
.on_click({
|
||||
let callback = self.sign_in_callback.clone();
|
||||
|
||||
@@ -820,9 +820,7 @@ impl ConfigurationView {
|
||||
.child(
|
||||
Button::new("reset-api-url", "Reset API URL")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.on_click(
|
||||
cx.listener(|this, _, _window, cx| this.reset_api_url(_window, cx)),
|
||||
@@ -918,9 +916,11 @@ impl Render for ConfigurationView {
|
||||
this.child(
|
||||
Button::new("lmstudio-site", "LM Studio")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _window, cx| {
|
||||
cx.open_url(LMSTUDIO_SITE)
|
||||
})
|
||||
@@ -933,9 +933,11 @@ impl Render for ConfigurationView {
|
||||
"Download LM Studio",
|
||||
)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _window, cx| {
|
||||
cx.open_url(LMSTUDIO_DOWNLOAD_URL)
|
||||
})
|
||||
@@ -946,9 +948,11 @@ impl Render for ConfigurationView {
|
||||
.child(
|
||||
Button::new("view-models", "Model Catalog")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _window, cx| {
|
||||
cx.open_url(LMSTUDIO_CATALOG_URL)
|
||||
}),
|
||||
@@ -981,9 +985,9 @@ impl Render for ConfigurationView {
|
||||
} else {
|
||||
this.child(
|
||||
Button::new("retry_lmstudio_models", "Connect")
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon(IconName::PlayFilled)
|
||||
.start_icon(
|
||||
Icon::new(IconName::PlayFilled).size(IconSize::XSmall),
|
||||
)
|
||||
.on_click(cx.listener(move |this, _, _window, cx| {
|
||||
this.retry_connection(_window, cx)
|
||||
})),
|
||||
|
||||
@@ -858,9 +858,7 @@ impl ConfigurationView {
|
||||
.child(
|
||||
Button::new("reset-context-window", "Reset")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.on_click(
|
||||
cx.listener(|this, _, window, cx| {
|
||||
@@ -905,9 +903,7 @@ impl ConfigurationView {
|
||||
.child(
|
||||
Button::new("reset-api-url", "Reset API URL")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.on_click(
|
||||
cx.listener(|this, _, window, cx| this.reset_api_url(window, cx)),
|
||||
@@ -949,9 +945,11 @@ impl Render for ConfigurationView {
|
||||
this.child(
|
||||
Button::new("ollama-site", "Ollama")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _, cx| cx.open_url(OLLAMA_SITE))
|
||||
.into_any_element(),
|
||||
)
|
||||
@@ -959,9 +957,11 @@ impl Render for ConfigurationView {
|
||||
this.child(
|
||||
Button::new("download_ollama_button", "Download Ollama")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _, cx| {
|
||||
cx.open_url(OLLAMA_DOWNLOAD_URL)
|
||||
})
|
||||
@@ -972,9 +972,11 @@ impl Render for ConfigurationView {
|
||||
.child(
|
||||
Button::new("view-models", "View All Models")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _, cx| cx.open_url(OLLAMA_LIBRARY_URL)),
|
||||
),
|
||||
)
|
||||
@@ -1005,9 +1007,9 @@ impl Render for ConfigurationView {
|
||||
} else {
|
||||
this.child(
|
||||
Button::new("retry_ollama_models", "Connect")
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon(IconName::PlayOutlined)
|
||||
.start_icon(
|
||||
Icon::new(IconName::PlayOutlined).size(IconSize::XSmall),
|
||||
)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.retry_connection(window, cx)
|
||||
})),
|
||||
|
||||
@@ -1415,9 +1415,11 @@ impl Render for ConfigurationView {
|
||||
)
|
||||
.child(
|
||||
Button::new("docs", "Learn More")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _window, cx| {
|
||||
cx.open_url("https://zed.dev/docs/ai/llm-providers#openai-api-compatible")
|
||||
}),
|
||||
|
||||
@@ -545,9 +545,7 @@ impl Render for ConfigurationView {
|
||||
.child(
|
||||
Button::new("reset-api-key", "Reset API Key")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::Undo).size(IconSize::Small))
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.when(env_var_set, |this| {
|
||||
this.tooltip(Tooltip::text(format!("To reset your API key, unset the {env_var_name} environment variable.")))
|
||||
|
||||
@@ -56,10 +56,8 @@ impl Render for BasedPyrightBanner {
|
||||
.gap_0p5()
|
||||
.child(
|
||||
Button::new("learn-more", "Learn More")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::XSmall).color(Color::Muted))
|
||||
.on_click(|_, _, cx| {
|
||||
cx.open_url("https://zed.dev/docs/languages/python")
|
||||
}),
|
||||
|
||||
@@ -18,7 +18,7 @@ use project::{
|
||||
};
|
||||
use proto::toggle_lsp_logs::LogType;
|
||||
use std::{any::TypeId, borrow::Cow, sync::Arc};
|
||||
use ui::{Button, Checkbox, ContextMenu, Label, PopoverMenu, ToggleState, prelude::*};
|
||||
use ui::{Checkbox, ContextMenu, PopoverMenu, ToggleState, prelude::*};
|
||||
use util::ResultExt as _;
|
||||
use workspace::{
|
||||
SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceId,
|
||||
@@ -969,9 +969,11 @@ impl Render for LspLogToolbarItemView {
|
||||
})
|
||||
.unwrap_or_else(|| "No server selected".into()),
|
||||
)
|
||||
.icon(IconName::ChevronDown)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted),
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.menu({
|
||||
let log_view = log_view.clone();
|
||||
@@ -1030,10 +1032,11 @@ impl Render for LspLogToolbarItemView {
|
||||
PopoverMenu::new("LspViewSelector")
|
||||
.anchor(Corner::TopLeft)
|
||||
.trigger(
|
||||
Button::new("language_server_menu_header", label)
|
||||
.icon(IconName::ChevronDown)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted),
|
||||
Button::new("language_server_menu_header", label).end_icon(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.menu(move |window, cx| {
|
||||
let log_toolbar_view = log_toolbar_view.upgrade()?;
|
||||
@@ -1125,9 +1128,11 @@ impl Render for LspLogToolbarItemView {
|
||||
"language_server_trace_level_selector",
|
||||
"Trace level",
|
||||
)
|
||||
.icon(IconName::ChevronDown)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted),
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.menu({
|
||||
let log_view = log_view;
|
||||
@@ -1193,9 +1198,11 @@ impl Render for LspLogToolbarItemView {
|
||||
"language_server_log_level_selector",
|
||||
"Log level",
|
||||
)
|
||||
.icon(IconName::ChevronDown)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted),
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.menu({
|
||||
let log_view = log_view;
|
||||
|
||||
@@ -10,9 +10,8 @@ use theme::{
|
||||
ThemeSettings,
|
||||
};
|
||||
use ui::{
|
||||
Divider, ParentElement as _, StatefulInteractiveElement, SwitchField, TintColor,
|
||||
ToggleButtonGroup, ToggleButtonGroupSize, ToggleButtonSimple, ToggleButtonWithIcon, Tooltip,
|
||||
prelude::*, rems_from_px,
|
||||
Divider, StatefulInteractiveElement, SwitchField, TintColor, ToggleButtonGroup,
|
||||
ToggleButtonGroupSize, ToggleButtonSimple, ToggleButtonWithIcon, Tooltip, prelude::*,
|
||||
};
|
||||
use vim_mode_setting::VimModeSetting;
|
||||
|
||||
@@ -477,8 +476,7 @@ fn render_setting_import_button(
|
||||
.toggle_state(imported)
|
||||
.tab_index(tab_index)
|
||||
.when(imported, |this| {
|
||||
this.icon(IconName::Check)
|
||||
.icon_size(IconSize::Small)
|
||||
this.end_icon(Icon::new(IconName::Check).size(IconSize::Small))
|
||||
.color(Color::Success)
|
||||
})
|
||||
.on_click(move |_, window, cx| {
|
||||
|
||||
@@ -158,10 +158,11 @@ impl Render for MultibufferHint {
|
||||
)
|
||||
.child(
|
||||
Button::new("open_docs", "Learn More")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::End)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_event, _, cx| {
|
||||
cx.open_url("https://zed.dev/docs/multibuffers")
|
||||
}),
|
||||
|
||||
@@ -52,7 +52,6 @@ pub fn panel_button(label: impl Into<SharedString>) -> ui::Button {
|
||||
let id = ElementId::Name(label.to_lowercase().replace(' ', "_").into());
|
||||
ui::Button::new(id, label)
|
||||
.label_size(ui::LabelSize::Small)
|
||||
.icon_size(ui::IconSize::Small)
|
||||
// TODO: Change this once we use on_surface_bg in button_like
|
||||
.layer(ui::ElevationIndex::ModalSurface)
|
||||
.size(ui::ButtonSize::Compact)
|
||||
|
||||
@@ -2,11 +2,7 @@ use gpui::{ClickEvent, DismissEvent, EventEmitter, FocusHandle, Focusable, Rende
|
||||
use project::project_settings::ProjectSettings;
|
||||
use remote::RemoteConnectionOptions;
|
||||
use settings::Settings;
|
||||
use ui::{
|
||||
Button, ButtonCommon, ButtonStyle, Clickable, Context, ElevationIndex, FluentBuilder, Headline,
|
||||
HeadlineSize, IconName, IconPosition, InteractiveElement, IntoElement, Label, Modal,
|
||||
ModalFooter, ModalHeader, ParentElement, Section, Styled, StyledExt, Window, div, h_flex, rems,
|
||||
};
|
||||
use ui::{ElevationIndex, Modal, ModalFooter, ModalHeader, Section, prelude::*};
|
||||
use workspace::{
|
||||
ModalView, MultiWorkspace, OpenOptions, Workspace, notifications::DetachAndPromptErr,
|
||||
};
|
||||
@@ -207,8 +203,7 @@ impl Render for DisconnectedOverlay {
|
||||
Button::new("reconnect", "Reconnect")
|
||||
.style(ButtonStyle::Filled)
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.icon(IconName::ArrowCircle)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(Icon::new(IconName::ArrowCircle))
|
||||
.on_click(cx.listener(Self::handle_reconnect)),
|
||||
)
|
||||
}),
|
||||
|
||||
@@ -2117,8 +2117,10 @@ impl RemoteServerProjects {
|
||||
.child(
|
||||
Button::new("learn-more", "Learn More")
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::XSmall),
|
||||
)
|
||||
.on_click(|_, _, cx| {
|
||||
cx.open_url(
|
||||
"https://zed.dev/docs/remote-development",
|
||||
|
||||
@@ -431,10 +431,11 @@ impl PickerDelegate for KernelPickerDelegate {
|
||||
.gap_4()
|
||||
.child(
|
||||
Button::new("kernel-docs", "Kernel Docs")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::End)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(move |_, _, cx| cx.open_url(KERNEL_DOCS_URL)),
|
||||
)
|
||||
.into_any(),
|
||||
|
||||
@@ -1117,10 +1117,11 @@ impl NotebookEditor {
|
||||
worktree_id,
|
||||
Button::new("kernel-selector", kernel_name.clone())
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(status_icon)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(status_color)
|
||||
.icon_position(IconPosition::Start),
|
||||
.start_icon(
|
||||
Icon::new(status_icon)
|
||||
.size(IconSize::Small)
|
||||
.color(status_color),
|
||||
),
|
||||
Tooltip::text(format!(
|
||||
"Kernel: {} ({}). Click to change.",
|
||||
kernel_name,
|
||||
|
||||
@@ -1170,10 +1170,11 @@ impl RulesLibrary {
|
||||
Button::new("new-rule", "New Rule")
|
||||
.full_width()
|
||||
.style(ButtonStyle::Outlined)
|
||||
.icon(IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_color(Color::Muted)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Plus)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(Box::new(NewRule), cx);
|
||||
}),
|
||||
|
||||
@@ -1583,9 +1583,7 @@ impl ProjectSearchView {
|
||||
)
|
||||
.child(
|
||||
Button::new("filter-paths", "Include/exclude specific paths")
|
||||
.icon(IconName::Filter)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(Icon::new(IconName::Filter).size(IconSize::Small))
|
||||
.key_binding(KeyBinding::for_action_in(&ToggleFilters, &focus_handle, cx))
|
||||
.on_click(|_event, window, cx| {
|
||||
window.dispatch_action(ToggleFilters.boxed_clone(), cx)
|
||||
@@ -1593,9 +1591,7 @@ impl ProjectSearchView {
|
||||
)
|
||||
.child(
|
||||
Button::new("find-replace", "Find and replace")
|
||||
.icon(IconName::Replace)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(Icon::new(IconName::Replace).size(IconSize::Small))
|
||||
.key_binding(KeyBinding::for_action_in(&ToggleReplace, &focus_handle, cx))
|
||||
.on_click(|_event, window, cx| {
|
||||
window.dispatch_action(ToggleReplace.boxed_clone(), cx)
|
||||
@@ -1603,9 +1599,7 @@ impl ProjectSearchView {
|
||||
)
|
||||
.child(
|
||||
Button::new("regex", "Match with regex")
|
||||
.icon(IconName::Regex)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(Icon::new(IconName::Regex).size(IconSize::Small))
|
||||
.key_binding(KeyBinding::for_action_in(&ToggleRegex, &focus_handle, cx))
|
||||
.on_click(|_event, window, cx| {
|
||||
window.dispatch_action(ToggleRegex.boxed_clone(), cx)
|
||||
@@ -1613,9 +1607,7 @@ impl ProjectSearchView {
|
||||
)
|
||||
.child(
|
||||
Button::new("match-case", "Match case")
|
||||
.icon(IconName::CaseSensitive)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(Icon::new(IconName::CaseSensitive).size(IconSize::Small))
|
||||
.key_binding(KeyBinding::for_action_in(
|
||||
&ToggleCaseSensitive,
|
||||
&focus_handle,
|
||||
@@ -1627,9 +1619,7 @@ impl ProjectSearchView {
|
||||
)
|
||||
.child(
|
||||
Button::new("match-whole-words", "Match whole words")
|
||||
.icon(IconName::WholeWord)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.start_icon(Icon::new(IconName::WholeWord).size(IconSize::Small))
|
||||
.key_binding(KeyBinding::for_action_in(
|
||||
&ToggleWholeWord,
|
||||
&focus_handle,
|
||||
|
||||
@@ -275,10 +275,11 @@ fn render_tool_list_item(
|
||||
.tab_index(tool_index as isize)
|
||||
.style(ButtonStyle::OutlinedGhost)
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(IconName::ChevronRight)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.push_dynamic_sub_page(
|
||||
tool_name,
|
||||
@@ -1090,9 +1091,7 @@ fn render_global_default_mode_section(current_mode: ToolPermissionMode) -> AnyEl
|
||||
.tab_index(0_isize)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(IconName::ChevronDown)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::Small),
|
||||
.end_icon(Icon::new(IconName::ChevronDown).size(IconSize::Small)),
|
||||
)
|
||||
.menu(move |window, cx| {
|
||||
Some(ContextMenu::build(window, cx, move |menu, _, _| {
|
||||
@@ -1141,9 +1140,7 @@ fn render_default_mode_section(
|
||||
.tab_index(0_isize)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(IconName::ChevronDown)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::Small),
|
||||
.end_icon(Icon::new(IconName::ChevronDown).size(IconSize::Small)),
|
||||
)
|
||||
.menu(move |window, cx| {
|
||||
let tool_id = tool_id_owned.clone();
|
||||
|
||||
@@ -925,9 +925,7 @@ impl SettingsPageItem {
|
||||
Button::new("error-warning", warning)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(Some(IconName::Debug))
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_color(Color::Error)
|
||||
.start_icon(Icon::new(IconName::Debug).color(Color::Error))
|
||||
.tab_index(0_isize)
|
||||
.tooltip(Tooltip::text(setting_item.field.type_name()))
|
||||
.into_any_element(),
|
||||
@@ -992,11 +990,12 @@ impl SettingsPageItem {
|
||||
("sub-page".into(), sub_page_link.title.clone()),
|
||||
"Configure",
|
||||
)
|
||||
.icon(IconName::ChevronRight)
|
||||
.tab_index(0_isize)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.style(ButtonStyle::OutlinedGhost)
|
||||
.size(ButtonSize::Medium)
|
||||
.on_click({
|
||||
@@ -1125,11 +1124,12 @@ impl SettingsPageItem {
|
||||
("action-link".into(), action_link.title.clone()),
|
||||
action_link.button_text.clone(),
|
||||
)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.tab_index(0_isize)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.style(ButtonStyle::OutlinedGhost)
|
||||
.size(ButtonSize::Medium)
|
||||
.on_click({
|
||||
@@ -4174,10 +4174,11 @@ fn render_picker_trigger_button(id: SharedString, label: SharedString) -> Button
|
||||
.tab_index(0_isize)
|
||||
.style(ButtonStyle::Outlined)
|
||||
.size(ButtonSize::Medium)
|
||||
.icon(IconName::ChevronUpDown)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::End)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ChevronUpDown)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_font_picker(
|
||||
|
||||
@@ -311,10 +311,11 @@ impl PickerDelegate for IconThemeSelectorDelegate {
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.child(
|
||||
Button::new("docs", "View Icon Theme Docs")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(|_event, _window, cx| {
|
||||
cx.open_url("https://zed.dev/docs/icon-themes");
|
||||
}),
|
||||
|
||||
@@ -497,10 +497,11 @@ impl PickerDelegate for ThemeSelectorDelegate {
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.child(
|
||||
Button::new("docs", "View Theme Docs")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(cx.listener(|_, _, _, cx| {
|
||||
cx.open_url("https://zed.dev/docs/themes");
|
||||
})),
|
||||
|
||||
@@ -583,10 +583,11 @@ impl TitleBar {
|
||||
.style(ButtonStyle::Tinted(TintColor::Warning))
|
||||
.label_size(LabelSize::Small)
|
||||
.color(Color::Warning)
|
||||
.icon(IconName::Warning)
|
||||
.icon_color(Color::Warning)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Warning)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Warning),
|
||||
)
|
||||
.tooltip(|_, cx| {
|
||||
Tooltip::with_meta(
|
||||
"You're in Restricted Mode",
|
||||
@@ -697,9 +698,11 @@ impl TitleBar {
|
||||
Button::new("project_name_trigger", display_name)
|
||||
.label_size(LabelSize::Small)
|
||||
.when(self.worktree_count(cx) > 1, |this| {
|
||||
this.icon(IconName::ChevronDown)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_size(IconSize::XSmall)
|
||||
this.end_icon(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
})
|
||||
.selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.when(!is_project_selected, |s| s.color(Color::Muted)),
|
||||
@@ -779,11 +782,9 @@ impl TitleBar {
|
||||
.color(Color::Muted)
|
||||
.when(settings.show_branch_icon, |branch_button| {
|
||||
let (icon, icon_color) = icon_info;
|
||||
branch_button
|
||||
.icon(icon)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_color(icon_color)
|
||||
.icon_size(IconSize::Indicator)
|
||||
branch_button.start_icon(
|
||||
Icon::new(icon).size(IconSize::Indicator).color(icon_color),
|
||||
)
|
||||
}),
|
||||
move |_window, cx| {
|
||||
Tooltip::with_meta(
|
||||
|
||||
@@ -133,10 +133,11 @@ impl RenderOnce for ConfiguredApiCard {
|
||||
elem.tab_index(tab_index)
|
||||
})
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
.icon_position(IconPosition::Start)
|
||||
.start_icon(
|
||||
Icon::new(IconName::Undo)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.disabled(self.disabled)
|
||||
.when_some(self.tooltip_label, |this, label| {
|
||||
this.tooltip(Tooltip::text(label))
|
||||
|
||||
@@ -8,16 +8,14 @@ use gpui::{AnyElement, IntoElement, ParentElement, Styled};
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
/// use ui::{Banner, Button, IconName, IconPosition, IconSize, Label, Severity};
|
||||
/// use ui::{Banner, Button, Icon, IconName, IconSize, Label, Severity};
|
||||
///
|
||||
/// Banner::new()
|
||||
/// .severity(Severity::Success)
|
||||
/// .children([Label::new("This is a success message")])
|
||||
/// .action_slot(
|
||||
/// Button::new("learn-more", "Learn More")
|
||||
/// .icon(IconName::ArrowUpRight)
|
||||
/// .icon_size(IconSize::Small)
|
||||
/// .icon_position(IconPosition::End)
|
||||
/// .end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(IntoElement, RegisterComponent)]
|
||||
@@ -151,9 +149,7 @@ impl Component for Banner {
|
||||
.child(Label::new("This is an informational message"))
|
||||
.action_slot(
|
||||
Button::new("learn-more", "Learn More")
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::End),
|
||||
.end_icon(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
|
||||
)
|
||||
.into_any_element(),
|
||||
),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
mod button;
|
||||
mod button_icon;
|
||||
mod button_like;
|
||||
mod button_link;
|
||||
mod copy_button;
|
||||
|
||||
@@ -2,15 +2,12 @@ use crate::component_prelude::*;
|
||||
use gpui::{AnyElement, AnyView, DefiniteLength};
|
||||
use ui_macros::RegisterComponent;
|
||||
|
||||
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, IconName, IconSize, Label};
|
||||
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, Label};
|
||||
use crate::{
|
||||
Color, DynamicSpacing, ElevationIndex, IconPosition, KeyBinding, KeybindingPosition, TintColor,
|
||||
prelude::*,
|
||||
Color, DynamicSpacing, ElevationIndex, KeyBinding, KeybindingPosition, TintColor, prelude::*,
|
||||
};
|
||||
|
||||
use super::button_icon::ButtonIcon;
|
||||
|
||||
/// An element that creates a button with a label and an optional icon.
|
||||
/// An element that creates a button with a label and optional icons.
|
||||
///
|
||||
/// Common buttons:
|
||||
/// - Label, Icon + Label: [`Button`] (this component)
|
||||
@@ -42,7 +39,7 @@ use super::button_icon::ButtonIcon;
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .icon(IconName::Check)
|
||||
/// .start_icon(Icon::new(IconName::Check))
|
||||
/// .toggle_state(true)
|
||||
/// .on_click(|event, window, cx| {
|
||||
/// // Handle click event
|
||||
@@ -85,12 +82,8 @@ pub struct Button {
|
||||
label_size: Option<LabelSize>,
|
||||
selected_label: Option<SharedString>,
|
||||
selected_label_color: Option<Color>,
|
||||
icon: Option<IconName>,
|
||||
icon_position: Option<IconPosition>,
|
||||
icon_size: Option<IconSize>,
|
||||
icon_color: Option<Color>,
|
||||
selected_icon: Option<IconName>,
|
||||
selected_icon_color: Option<Color>,
|
||||
start_icon: Option<Icon>,
|
||||
end_icon: Option<Icon>,
|
||||
key_binding: Option<KeyBinding>,
|
||||
key_binding_position: KeybindingPosition,
|
||||
alpha: Option<f32>,
|
||||
@@ -112,12 +105,8 @@ impl Button {
|
||||
label_size: None,
|
||||
selected_label: None,
|
||||
selected_label_color: None,
|
||||
icon: None,
|
||||
icon_position: None,
|
||||
icon_size: None,
|
||||
icon_color: None,
|
||||
selected_icon: None,
|
||||
selected_icon_color: None,
|
||||
start_icon: None,
|
||||
end_icon: None,
|
||||
key_binding: None,
|
||||
key_binding_position: KeybindingPosition::default(),
|
||||
alpha: None,
|
||||
@@ -149,39 +138,19 @@ impl Button {
|
||||
self
|
||||
}
|
||||
|
||||
/// Assigns an icon to the button.
|
||||
pub fn icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
|
||||
self.icon = icon.into();
|
||||
/// Sets an icon to display at the start (left) of the button label.
|
||||
///
|
||||
/// The icon's color will be overridden to `Color::Disabled` when the button is disabled.
|
||||
pub fn start_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
|
||||
self.start_icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the position of the icon relative to the label.
|
||||
pub fn icon_position(mut self, icon_position: impl Into<Option<IconPosition>>) -> Self {
|
||||
self.icon_position = icon_position.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies the size of the button's icon.
|
||||
pub fn icon_size(mut self, icon_size: impl Into<Option<IconSize>>) -> Self {
|
||||
self.icon_size = icon_size.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the color of the button's icon.
|
||||
pub fn icon_color(mut self, icon_color: impl Into<Option<Color>>) -> Self {
|
||||
self.icon_color = icon_color.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Chooses an icon to display when the button is in a selected state.
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
|
||||
self.selected_icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the icon color used when the button is in a selected state.
|
||||
pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
|
||||
self.selected_icon_color = color.into();
|
||||
/// Sets an icon to display at the end (right) of the button label.
|
||||
///
|
||||
/// The icon's color will be overridden to `Color::Disabled` when the button is disabled.
|
||||
pub fn end_icon(mut self, icon: impl Into<Option<Icon>>) -> Self {
|
||||
self.end_icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
||||
@@ -219,22 +188,24 @@ impl Button {
|
||||
impl Toggleable for Button {
|
||||
/// Sets the selected state of the button.
|
||||
///
|
||||
/// This method allows the selection state of the button to be specified.
|
||||
/// It modifies the button's appearance to reflect its selected state.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a toggleable button that changes appearance when selected:
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
/// use ui::TintColor;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .toggle_state(true)
|
||||
/// let selected = true;
|
||||
///
|
||||
/// Button::new("toggle_button", "Toggle Me")
|
||||
/// .start_icon(Icon::new(IconName::Check))
|
||||
/// .toggle_state(selected)
|
||||
/// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
/// .on_click(|event, window, cx| {
|
||||
/// // Handle click event
|
||||
/// // Toggle the selected state
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Use [`selected_style`](Button::selected_style) to change the style of the button when it is selected.
|
||||
fn toggle_state(mut self, selected: bool) -> Self {
|
||||
self.base = self.base.toggle_state(selected);
|
||||
self
|
||||
@@ -242,22 +213,20 @@ impl Toggleable for Button {
|
||||
}
|
||||
|
||||
impl SelectableButton for Button {
|
||||
/// Sets the style for the button when selected.
|
||||
/// Sets the style for the button in a selected state.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Customize the selected appearance of a button:
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
/// use ui::TintColor;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// Button::new("styled_button", "Styled Button")
|
||||
/// .toggle_state(true)
|
||||
/// .selected_style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
/// .on_click(|event, window, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// .selected_style(ButtonStyle::Tinted(TintColor::Accent));
|
||||
/// ```
|
||||
/// This results in a button with a blue tinted background when selected.
|
||||
fn selected_style(mut self, style: ButtonStyle) -> Self {
|
||||
self.base = self.base.selected_style(style);
|
||||
self
|
||||
@@ -265,36 +234,27 @@ impl SelectableButton for Button {
|
||||
}
|
||||
|
||||
impl Disableable for Button {
|
||||
/// Disables the button.
|
||||
/// Disables the button, preventing interaction and changing its appearance.
|
||||
///
|
||||
/// This method allows the button to be disabled. When a button is disabled,
|
||||
/// it doesn't react to user interactions and its appearance is updated to reflect this.
|
||||
/// When disabled, the button's icon and label will use `Color::Disabled`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a disabled button:
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .disabled(true)
|
||||
/// .on_click(|event, window, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// Button::new("disabled_button", "Can't Click Me")
|
||||
/// .disabled(true);
|
||||
/// ```
|
||||
///
|
||||
/// This results in a button that is disabled and does not respond to click events.
|
||||
fn disabled(mut self, disabled: bool) -> Self {
|
||||
self.base = self.base.disabled(disabled);
|
||||
self.key_binding = self
|
||||
.key_binding
|
||||
.take()
|
||||
.map(|binding| binding.disabled(disabled));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Clickable for Button {
|
||||
/// Sets the click event handler for the button.
|
||||
fn on_click(
|
||||
mut self,
|
||||
handler: impl Fn(&gpui::ClickEvent, &mut Window, &mut App) + 'static,
|
||||
@@ -310,44 +270,35 @@ impl Clickable for Button {
|
||||
}
|
||||
|
||||
impl FixedWidth for Button {
|
||||
/// Sets a fixed width for the button.
|
||||
///
|
||||
/// This function allows a button to have a fixed width instead of automatically growing or shrinking.
|
||||
/// Sets a fixed width for the button.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a button with a fixed width of 100 pixels:
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .width(px(100.))
|
||||
/// .on_click(|event, window, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// Button::new("fixed_width_button", "Fixed Width")
|
||||
/// .width(px(100.0));
|
||||
/// ```
|
||||
///
|
||||
/// This sets the button's width to be exactly 100 pixels.
|
||||
fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
|
||||
self.base = self.base.width(width);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the button to occupy the full width of its container.
|
||||
/// Makes the button take up the full width of its container.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a button that takes up the full width of its container:
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .full_width()
|
||||
/// .on_click(|event, window, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// Button::new("full_width_button", "Full Width")
|
||||
/// .full_width();
|
||||
/// ```
|
||||
///
|
||||
/// This stretches the button to the full width of its container.
|
||||
fn full_width(mut self) -> Self {
|
||||
self.base = self.base.full_width();
|
||||
self
|
||||
@@ -355,43 +306,34 @@ impl FixedWidth for Button {
|
||||
}
|
||||
|
||||
impl ButtonCommon for Button {
|
||||
/// Sets the button's id.
|
||||
fn id(&self) -> &ElementId {
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
/// Sets the visual style of the button using a [`ButtonStyle`].
|
||||
/// Sets the visual style of the button.
|
||||
fn style(mut self, style: ButtonStyle) -> Self {
|
||||
self.base = self.base.style(style);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the button's size using a [`ButtonSize`].
|
||||
/// Sets the size of the button.
|
||||
fn size(mut self, size: ButtonSize) -> Self {
|
||||
self.base = self.base.size(size);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a tooltip for the button.
|
||||
///
|
||||
/// This method allows a tooltip to be set for the button. The tooltip is a function that
|
||||
/// takes a mutable references to [`Window`] and [`App`], and returns an [`AnyView`]. The
|
||||
/// tooltip is displayed when the user hovers over the button.
|
||||
/// Sets a tooltip that appears on hover.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ui::prelude::*;
|
||||
/// use ui::Tooltip;
|
||||
/// Add a tooltip to a button:
|
||||
///
|
||||
/// Button::new("button_id", "Click me!")
|
||||
/// .tooltip(Tooltip::text("This is a tooltip"))
|
||||
/// .on_click(|event, window, cx| {
|
||||
/// // Handle click event
|
||||
/// });
|
||||
/// ```
|
||||
/// use ui::{Tooltip, prelude::*};
|
||||
///
|
||||
/// This will create a button with a tooltip that displays "This is a tooltip" when hovered over.
|
||||
/// Button::new("tooltip_button", "Hover Me")
|
||||
/// .tooltip(Tooltip::text("This is a tooltip"));
|
||||
/// ```
|
||||
fn tooltip(mut self, tooltip: impl Fn(&mut Window, &mut App) -> AnyView + 'static) -> Self {
|
||||
self.base = self.base.tooltip(tooltip);
|
||||
self
|
||||
@@ -436,16 +378,12 @@ impl RenderOnce for Button {
|
||||
h_flex()
|
||||
.when(self.truncate, |this| this.min_w_0().overflow_hidden())
|
||||
.gap(DynamicSpacing::Base04.rems(cx))
|
||||
.when(self.icon_position == Some(IconPosition::Start), |this| {
|
||||
this.children(self.icon.map(|icon| {
|
||||
ButtonIcon::new(icon)
|
||||
.disabled(is_disabled)
|
||||
.toggle_state(is_selected)
|
||||
.selected_icon(self.selected_icon)
|
||||
.selected_icon_color(self.selected_icon_color)
|
||||
.size(self.icon_size)
|
||||
.color(self.icon_color)
|
||||
}))
|
||||
.when_some(self.start_icon, |this, icon| {
|
||||
this.child(if is_disabled {
|
||||
icon.color(Color::Disabled)
|
||||
} else {
|
||||
icon
|
||||
})
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
@@ -465,16 +403,12 @@ impl RenderOnce for Button {
|
||||
)
|
||||
.children(self.key_binding),
|
||||
)
|
||||
.when(self.icon_position != Some(IconPosition::Start), |this| {
|
||||
this.children(self.icon.map(|icon| {
|
||||
ButtonIcon::new(icon)
|
||||
.disabled(is_disabled)
|
||||
.toggle_state(is_selected)
|
||||
.selected_icon(self.selected_icon)
|
||||
.selected_icon_color(self.selected_icon_color)
|
||||
.size(self.icon_size)
|
||||
.color(self.icon_color)
|
||||
}))
|
||||
.when_some(self.end_icon, |this, icon| {
|
||||
this.child(if is_disabled {
|
||||
icon.color(Color::Disabled)
|
||||
} else {
|
||||
icon
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -585,24 +519,28 @@ impl Component for Button {
|
||||
"Buttons with Icons",
|
||||
vec![
|
||||
single_example(
|
||||
"Icon Start",
|
||||
Button::new("icon_start", "Icon Start")
|
||||
.icon(IconName::Check)
|
||||
.icon_position(IconPosition::Start)
|
||||
"Start Icon",
|
||||
Button::new("icon_start", "Start Icon")
|
||||
.start_icon(Icon::new(IconName::Check))
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Icon End",
|
||||
Button::new("icon_end", "Icon End")
|
||||
.icon(IconName::Check)
|
||||
.icon_position(IconPosition::End)
|
||||
"End Icon",
|
||||
Button::new("icon_end", "End Icon")
|
||||
.end_icon(Icon::new(IconName::Check))
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Both Icons",
|
||||
Button::new("both_icons", "Both Icons")
|
||||
.start_icon(Icon::new(IconName::Check))
|
||||
.end_icon(Icon::new(IconName::ChevronDown))
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Icon Color",
|
||||
Button::new("icon_color", "Icon Color")
|
||||
.icon(IconName::Check)
|
||||
.icon_color(Color::Accent)
|
||||
.start_icon(Icon::new(IconName::Check).color(Color::Accent))
|
||||
.into_any_element(),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
use crate::{Icon, IconName, IconSize, IconWithIndicator, Indicator, prelude::*};
|
||||
use gpui::Hsla;
|
||||
|
||||
/// An icon that appears within a button.
|
||||
///
|
||||
/// Can be used as either an icon alongside a label, like in [`Button`](crate::Button),
|
||||
/// or as a standalone icon, like in [`IconButton`](crate::IconButton).
|
||||
#[derive(IntoElement, RegisterComponent)]
|
||||
pub(super) struct ButtonIcon {
|
||||
icon: IconName,
|
||||
size: IconSize,
|
||||
color: Color,
|
||||
disabled: bool,
|
||||
selected: bool,
|
||||
selected_icon: Option<IconName>,
|
||||
selected_icon_color: Option<Color>,
|
||||
selected_style: Option<ButtonStyle>,
|
||||
indicator: Option<Indicator>,
|
||||
indicator_border_color: Option<Hsla>,
|
||||
}
|
||||
|
||||
impl ButtonIcon {
|
||||
pub fn new(icon: IconName) -> Self {
|
||||
Self {
|
||||
icon,
|
||||
size: IconSize::default(),
|
||||
color: Color::default(),
|
||||
disabled: false,
|
||||
selected: false,
|
||||
selected_icon: None,
|
||||
selected_icon_color: None,
|
||||
selected_style: None,
|
||||
indicator: None,
|
||||
indicator_border_color: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(mut self, size: impl Into<Option<IconSize>>) -> Self {
|
||||
if let Some(size) = size.into() {
|
||||
self.size = size;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn color(mut self, color: impl Into<Option<Color>>) -> Self {
|
||||
if let Some(color) = color.into() {
|
||||
self.color = color;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn selected_icon(mut self, icon: impl Into<Option<IconName>>) -> Self {
|
||||
self.selected_icon = icon.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn selected_icon_color(mut self, color: impl Into<Option<Color>>) -> Self {
|
||||
self.selected_icon_color = color.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn indicator(mut self, indicator: Indicator) -> Self {
|
||||
self.indicator = Some(indicator);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn indicator_border_color(mut self, color: Option<Hsla>) -> Self {
|
||||
self.indicator_border_color = color;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Disableable for ButtonIcon {
|
||||
fn disabled(mut self, disabled: bool) -> Self {
|
||||
self.disabled = disabled;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Toggleable for ButtonIcon {
|
||||
fn toggle_state(mut self, selected: bool) -> Self {
|
||||
self.selected = selected;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectableButton for ButtonIcon {
|
||||
fn selected_style(mut self, style: ButtonStyle) -> Self {
|
||||
self.selected_style = Some(style);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for ButtonIcon {
|
||||
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
let icon = self
|
||||
.selected_icon
|
||||
.filter(|_| self.selected)
|
||||
.unwrap_or(self.icon);
|
||||
|
||||
let icon_color = if self.disabled {
|
||||
Color::Disabled
|
||||
} else if self.selected_style.is_some() && self.selected {
|
||||
self.selected_style.unwrap().into()
|
||||
} else if self.selected {
|
||||
self.selected_icon_color.unwrap_or(Color::Selected)
|
||||
} else {
|
||||
self.color
|
||||
};
|
||||
|
||||
let icon = Icon::new(icon).size(self.size).color(icon_color);
|
||||
|
||||
match self.indicator {
|
||||
Some(indicator) => IconWithIndicator::new(icon, Some(indicator))
|
||||
.indicator_border_color(self.indicator_border_color)
|
||||
.into_any_element(),
|
||||
None => icon.into_any_element(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for ButtonIcon {
|
||||
fn scope() -> ComponentScope {
|
||||
ComponentScope::Input
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
"ButtonIcon"
|
||||
}
|
||||
|
||||
fn description() -> Option<&'static str> {
|
||||
Some("An icon component specifically designed for use within buttons.")
|
||||
}
|
||||
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
||||
Some(
|
||||
v_flex()
|
||||
.gap_6()
|
||||
.children(vec![
|
||||
example_group_with_title(
|
||||
"Basic Usage",
|
||||
vec![
|
||||
single_example(
|
||||
"Default",
|
||||
ButtonIcon::new(IconName::Star).into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Custom Size",
|
||||
ButtonIcon::new(IconName::Star)
|
||||
.size(IconSize::Medium)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Custom Color",
|
||||
ButtonIcon::new(IconName::Star)
|
||||
.color(Color::Accent)
|
||||
.into_any_element(),
|
||||
),
|
||||
],
|
||||
),
|
||||
example_group_with_title(
|
||||
"States",
|
||||
vec![
|
||||
single_example(
|
||||
"Selected",
|
||||
ButtonIcon::new(IconName::Star)
|
||||
.toggle_state(true)
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Disabled",
|
||||
ButtonIcon::new(IconName::Star)
|
||||
.disabled(true)
|
||||
.into_any_element(),
|
||||
),
|
||||
],
|
||||
),
|
||||
example_group_with_title(
|
||||
"With Indicator",
|
||||
vec![
|
||||
single_example(
|
||||
"Default Indicator",
|
||||
ButtonIcon::new(IconName::Star)
|
||||
.indicator(Indicator::dot())
|
||||
.into_any_element(),
|
||||
),
|
||||
single_example(
|
||||
"Custom Indicator",
|
||||
ButtonIcon::new(IconName::Star)
|
||||
.indicator(Indicator::dot().color(Color::Error))
|
||||
.into_any_element(),
|
||||
),
|
||||
],
|
||||
),
|
||||
])
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
use gpui::{AnyView, DefiniteLength, Hsla};
|
||||
|
||||
use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle};
|
||||
use crate::{ElevationIndex, Indicator, SelectableButton, TintColor, prelude::*};
|
||||
use crate::{
|
||||
ElevationIndex, Icon, IconWithIndicator, Indicator, SelectableButton, TintColor, prelude::*,
|
||||
};
|
||||
use crate::{IconName, IconSize};
|
||||
|
||||
use super::button_icon::ButtonIcon;
|
||||
|
||||
/// The shape of an [`IconButton`].
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub enum IconButtonShape {
|
||||
@@ -22,6 +22,7 @@ pub struct IconButton {
|
||||
icon_color: Color,
|
||||
selected_icon: Option<IconName>,
|
||||
selected_icon_color: Option<Color>,
|
||||
selected_style: Option<ButtonStyle>,
|
||||
indicator: Option<Indicator>,
|
||||
indicator_border_color: Option<Hsla>,
|
||||
alpha: Option<f32>,
|
||||
@@ -37,6 +38,7 @@ impl IconButton {
|
||||
icon_color: Color::Default,
|
||||
selected_icon: None,
|
||||
selected_icon_color: None,
|
||||
selected_style: None,
|
||||
indicator: None,
|
||||
indicator_border_color: None,
|
||||
alpha: None,
|
||||
@@ -112,6 +114,7 @@ impl Toggleable for IconButton {
|
||||
|
||||
impl SelectableButton for IconButton {
|
||||
fn selected_style(mut self, style: ButtonStyle) -> Self {
|
||||
self.selected_style = Some(style);
|
||||
self.base = self.base.selected_style(style);
|
||||
self
|
||||
}
|
||||
@@ -192,9 +195,25 @@ impl RenderOnce for IconButton {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> ButtonLike {
|
||||
let is_disabled = self.base.disabled;
|
||||
let is_selected = self.base.selected;
|
||||
let selected_style = self.base.selected_style;
|
||||
|
||||
let color = self.icon_color.color(cx).opacity(self.alpha.unwrap_or(1.0));
|
||||
let icon = self
|
||||
.selected_icon
|
||||
.filter(|_| is_selected)
|
||||
.unwrap_or(self.icon);
|
||||
|
||||
let icon_color = if is_disabled {
|
||||
Color::Disabled
|
||||
} else if self.selected_style.is_some() && is_selected {
|
||||
self.selected_style.unwrap().into()
|
||||
} else if is_selected {
|
||||
self.selected_icon_color.unwrap_or(Color::Selected)
|
||||
} else {
|
||||
let base_color = self.icon_color.color(cx);
|
||||
Color::Custom(base_color.opacity(self.alpha.unwrap_or(1.0)))
|
||||
};
|
||||
|
||||
let icon_element = Icon::new(icon).size(self.icon_size).color(icon_color);
|
||||
|
||||
self.base
|
||||
.map(|this| match self.shape {
|
||||
IconButtonShape::Square => {
|
||||
@@ -203,20 +222,12 @@ impl RenderOnce for IconButton {
|
||||
}
|
||||
IconButtonShape::Wide => this,
|
||||
})
|
||||
.child(
|
||||
ButtonIcon::new(self.icon)
|
||||
.disabled(is_disabled)
|
||||
.toggle_state(is_selected)
|
||||
.selected_icon(self.selected_icon)
|
||||
.selected_icon_color(self.selected_icon_color)
|
||||
.when_some(selected_style, |this, style| this.selected_style(style))
|
||||
.when_some(self.indicator, |this, indicator| {
|
||||
this.indicator(indicator)
|
||||
.indicator_border_color(self.indicator_border_color)
|
||||
})
|
||||
.size(self.icon_size)
|
||||
.color(Color::Custom(color)),
|
||||
)
|
||||
.child(match self.indicator {
|
||||
Some(indicator) => IconWithIndicator::new(icon_element, Some(indicator))
|
||||
.indicator_border_color(self.indicator_border_color)
|
||||
.into_any_element(),
|
||||
None => icon_element.into_any_element(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,11 +163,10 @@ impl RenderOnce for DropdownMenu {
|
||||
Some(
|
||||
Button::new(self.id.clone(), text)
|
||||
.style(button_style)
|
||||
.when(self.chevron, |this| {
|
||||
this.icon(self.trigger_icon)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.when_some(self.trigger_icon.filter(|_| self.chevron), |this, icon| {
|
||||
this.end_icon(
|
||||
Icon::new(icon).size(IconSize::XSmall).color(Color::Muted),
|
||||
)
|
||||
})
|
||||
.when(full_width, |this| this.full_width())
|
||||
.size(trigger_size)
|
||||
|
||||
@@ -917,11 +917,11 @@ pub mod simple_message_notification {
|
||||
}));
|
||||
|
||||
if let Some(icon) = self.primary_icon {
|
||||
button = button
|
||||
.icon(icon)
|
||||
.icon_color(self.primary_icon_color.unwrap_or(Color::Muted))
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small);
|
||||
button = button.start_icon(
|
||||
Icon::new(icon)
|
||||
.size(IconSize::Small)
|
||||
.color(self.primary_icon_color.unwrap_or(Color::Muted)),
|
||||
);
|
||||
}
|
||||
|
||||
button
|
||||
@@ -937,11 +937,11 @@ pub mod simple_message_notification {
|
||||
}));
|
||||
|
||||
if let Some(icon) = self.secondary_icon {
|
||||
button = button
|
||||
.icon(icon)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(self.secondary_icon_color.unwrap_or(Color::Muted));
|
||||
button = button.start_icon(
|
||||
Icon::new(icon)
|
||||
.size(IconSize::Small)
|
||||
.color(self.secondary_icon_color.unwrap_or(Color::Muted)),
|
||||
);
|
||||
}
|
||||
|
||||
button
|
||||
@@ -955,9 +955,11 @@ pub mod simple_message_notification {
|
||||
let url = url.clone();
|
||||
Button::new(message.clone(), message.clone())
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Indicator)
|
||||
.icon_color(Color::Muted)
|
||||
.end_icon(
|
||||
Icon::new(IconName::ArrowUpRight)
|
||||
.size(IconSize::Indicator)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.on_click(cx.listener(move |_, _, _, cx| {
|
||||
cx.open_url(&url);
|
||||
}))
|
||||
|
||||
Reference in new issue
Block a user