From 3c4891cb695d1ff3e352c5480ead94434374c963 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Sat, 29 Jun 2024 02:37:22 +0800 Subject: [PATCH] Add icon support to Button. --- crates/ui-story/src/button_story.rs | 27 +++++++++++++++++++++++-- crates/ui/src/button.rs | 27 +++++++++++++++++++------ crates/ui/src/icon.rs | 31 +++++++++++++++++++---------- crates/ui/src/tooltip.rs | 15 +++++--------- 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/crates/ui-story/src/button_story.rs b/crates/ui-story/src/button_story.rs index 64a6afc9..83d00cf2 100644 --- a/crates/ui-story/src/button_story.rs +++ b/crates/ui-story/src/button_story.rs @@ -5,12 +5,12 @@ use gpui::{ use ui::{ button::{Button, ButtonSize, ButtonStyle}, - h_flex, v_flex, Clickable, Disableable as _, + h_flex, v_flex, Clickable, Disableable as _, Icon, IconName, }; use super::story_case; -pub struct ButtonStory; +pub struct ButtonStory {} impl ButtonStory { fn on_click(ev: &ClickEvent, _: &mut WindowContext) { @@ -26,6 +26,7 @@ impl Render for ButtonStory { ) .child( v_flex() + .w_full() .justify_start() .gap_6() .child( @@ -48,6 +49,28 @@ impl Render for ButtonStory { .on_click(Self::on_click), ), ) + .child( + h_flex() + .gap_6() + .child( + Button::new("button-icon-1", "Confirm") + .icon(IconName::Check) + .style(ButtonStyle::Primary) + .on_click(Self::on_click), + ) + .child( + Button::new("button-icon-2", "Abort") + .icon(IconName::Close) + .style(ButtonStyle::Secondary) + .on_click(Self::on_click), + ) + .child( + Button::new("button-icon-3", "Maximize") + .icon(Icon::new(IconName::Maximize)) + .style(ButtonStyle::Secondary) + .on_click(Self::on_click), + ), + ) .child( h_flex() .items_center() diff --git a/crates/ui/src/button.rs b/crates/ui/src/button.rs index fbd18bd6..80dd22a8 100644 --- a/crates/ui/src/button.rs +++ b/crates/ui/src/button.rs @@ -1,13 +1,13 @@ use gpui::{ - div, prelude::FluentBuilder as _, px, ClickEvent, DefiniteLength, Div, ElementId, Hsla, - InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce, SharedString, + div, prelude::FluentBuilder as _, px, AnyElement, ClickEvent, DefiniteLength, Div, ElementId, + Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, WindowContext, }; use crate::{ - span, + h_flex, span, theme::{ActiveTheme, Colorize as _, ThemeMode}, - Clickable, Disableable, Selectable, + Clickable, Disableable, Icon, IconName, Selectable, }; pub enum ButtonRounded { @@ -17,11 +17,13 @@ pub enum ButtonRounded { Large, } +#[derive(Clone, Copy)] pub enum ButtonSize { Small, Medium, } +#[derive(Clone, Copy)] pub enum ButtonStyle { Primary, Secondary, @@ -32,6 +34,7 @@ pub enum ButtonStyle { pub struct Button { pub base: Div, id: ElementId, + icon: Option, label: SharedString, disabled: bool, selected: bool, @@ -49,6 +52,7 @@ impl Button { Self { base: div(), id: id.into(), + icon: None, label: label.into(), disabled: false, selected: false, @@ -82,6 +86,11 @@ impl Button { self } + pub fn icon(mut self, icon: impl Into) -> Self { + self.icon = Some(icon.into()); + self + } + pub fn tooltip(mut self, tooltip: impl Into) -> Self { self.tooltip = Some(tooltip.into()); self @@ -175,9 +184,15 @@ impl RenderOnce for Button { normal_style.fg }; - span() - .child(self.label) + h_flex() + .items_center() + .justify_center() + .gap_2() .text_color(text_color) + .when_some(self.icon, |this, icon| { + this.child(icon.text_color(text_color)) + }) + .child(self.label) .map(|this| match self.size { ButtonSize::Small => this.text_sm(), ButtonSize::Medium => this.text_base(), diff --git a/crates/ui/src/icon.rs b/crates/ui/src/icon.rs index ed7de399..e323877c 100644 --- a/crates/ui/src/icon.rs +++ b/crates/ui/src/icon.rs @@ -1,4 +1,7 @@ -use gpui::{svg, IntoElement, RenderOnce, SharedString, Styled, Svg, WindowContext}; +use gpui::{ + div, rgb, svg, Div, InteractiveElement, IntoElement, ParentElement as _, RenderOnce, + SharedString, StyleRefinement, Styled, Svg, TextStyle, TextStyleRefinement, WindowContext, +}; use crate::theme::ActiveTheme; @@ -30,6 +33,12 @@ impl IconName { } } +impl Into for IconName { + fn into(self) -> Icon { + Icon::new(self) + } +} + impl RenderOnce for IconName { fn render(self, _cx: &mut WindowContext) -> impl IntoElement { Icon::new(self) @@ -42,16 +51,10 @@ pub struct Icon { path: SharedString, } -impl Styled for Icon { - fn style(&mut self) -> &mut gpui::StyleRefinement { - self.base.style() - } -} - impl Icon { pub fn new(name: IconName) -> Self { Self { - base: svg().flex_none().size_4(), + base: svg().flex_none().size_4().text_color(rgb(0x000000)), path: name.path(), } } @@ -65,8 +68,14 @@ impl Icon { } } -impl RenderOnce for Icon { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { - self.base.text_color(cx.theme().foreground).path(self.path) +impl Styled for Icon { + fn style(&mut self) -> &mut StyleRefinement { + self.base.style() + } +} + +impl RenderOnce for Icon { + fn render(self, _cx: &mut WindowContext) -> impl IntoElement { + self.base.path(self.path) } } diff --git a/crates/ui/src/tooltip.rs b/crates/ui/src/tooltip.rs index 3559ed18..aebe6e55 100644 --- a/crates/ui/src/tooltip.rs +++ b/crates/ui/src/tooltip.rs @@ -3,12 +3,7 @@ use gpui::{ SharedString, Styled, ViewContext, VisualContext, WindowContext, }; -use crate::{ - h_flex, - styled_ext::ElevationIndex, - theme::{ActiveTheme, Colorize}, - v_flex, -}; +use crate::{h_flex, styled_ext::ElevationIndex, theme::ActiveTheme, v_flex}; pub struct Tooltip { title: SharedString, @@ -64,13 +59,13 @@ pub fn tooltip_container( // padding to avoid tooltip appearing right below the mouse cursor div().pl_2().pt_2p5().child( v_flex() - .bg(cx.theme().popover.invert_l()) + .bg(cx.theme().popover) .rounded(px(8.)) .border_1() - .border_color(cx.theme().border.invert_l()) + .border_color(cx.theme().border) .shadow(ElevationIndex::ElevatedSurface.shadow()) - .text_color(cx.theme().background) - .py_1() + .text_color(cx.theme().popover_foreground) + .py_1p5() .px_2() .map(|el| f(el, cx)), )