Add icon support to Button.

This commit is contained in:
Jason Lee 2024-06-29 02:37:22 +08:00
parent a5aea36f75
commit 3c4891cb69
4 changed files with 71 additions and 29 deletions

View file

@ -5,12 +5,12 @@ use gpui::{
use ui::{ use ui::{
button::{Button, ButtonSize, ButtonStyle}, button::{Button, ButtonSize, ButtonStyle},
h_flex, v_flex, Clickable, Disableable as _, h_flex, v_flex, Clickable, Disableable as _, Icon, IconName,
}; };
use super::story_case; use super::story_case;
pub struct ButtonStory; pub struct ButtonStory {}
impl ButtonStory { impl ButtonStory {
fn on_click(ev: &ClickEvent, _: &mut WindowContext) { fn on_click(ev: &ClickEvent, _: &mut WindowContext) {
@ -26,6 +26,7 @@ impl Render for ButtonStory {
) )
.child( .child(
v_flex() v_flex()
.w_full()
.justify_start() .justify_start()
.gap_6() .gap_6()
.child( .child(
@ -48,6 +49,28 @@ impl Render for ButtonStory {
.on_click(Self::on_click), .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( .child(
h_flex() h_flex()
.items_center() .items_center()

View file

@ -1,13 +1,13 @@
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, px, ClickEvent, DefiniteLength, Div, ElementId, Hsla, div, prelude::FluentBuilder as _, px, AnyElement, ClickEvent, DefiniteLength, Div, ElementId,
InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce, SharedString, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce, SharedString,
StatefulInteractiveElement as _, Styled, WindowContext, StatefulInteractiveElement as _, Styled, WindowContext,
}; };
use crate::{ use crate::{
span, h_flex, span,
theme::{ActiveTheme, Colorize as _, ThemeMode}, theme::{ActiveTheme, Colorize as _, ThemeMode},
Clickable, Disableable, Selectable, Clickable, Disableable, Icon, IconName, Selectable,
}; };
pub enum ButtonRounded { pub enum ButtonRounded {
@ -17,11 +17,13 @@ pub enum ButtonRounded {
Large, Large,
} }
#[derive(Clone, Copy)]
pub enum ButtonSize { pub enum ButtonSize {
Small, Small,
Medium, Medium,
} }
#[derive(Clone, Copy)]
pub enum ButtonStyle { pub enum ButtonStyle {
Primary, Primary,
Secondary, Secondary,
@ -32,6 +34,7 @@ pub enum ButtonStyle {
pub struct Button { pub struct Button {
pub base: Div, pub base: Div,
id: ElementId, id: ElementId,
icon: Option<Icon>,
label: SharedString, label: SharedString,
disabled: bool, disabled: bool,
selected: bool, selected: bool,
@ -49,6 +52,7 @@ impl Button {
Self { Self {
base: div(), base: div(),
id: id.into(), id: id.into(),
icon: None,
label: label.into(), label: label.into(),
disabled: false, disabled: false,
selected: false, selected: false,
@ -82,6 +86,11 @@ impl Button {
self self
} }
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn tooltip(mut self, tooltip: impl Into<SharedString>) -> Self { pub fn tooltip(mut self, tooltip: impl Into<SharedString>) -> Self {
self.tooltip = Some(tooltip.into()); self.tooltip = Some(tooltip.into());
self self
@ -175,9 +184,15 @@ impl RenderOnce for Button {
normal_style.fg normal_style.fg
}; };
span() h_flex()
.child(self.label) .items_center()
.justify_center()
.gap_2()
.text_color(text_color) .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 { .map(|this| match self.size {
ButtonSize::Small => this.text_sm(), ButtonSize::Small => this.text_sm(),
ButtonSize::Medium => this.text_base(), ButtonSize::Medium => this.text_base(),

View file

@ -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; use crate::theme::ActiveTheme;
@ -30,6 +33,12 @@ impl IconName {
} }
} }
impl Into<Icon> for IconName {
fn into(self) -> Icon {
Icon::new(self)
}
}
impl RenderOnce for IconName { impl RenderOnce for IconName {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement { fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
Icon::new(self) Icon::new(self)
@ -42,16 +51,10 @@ pub struct Icon {
path: SharedString, path: SharedString,
} }
impl Styled for Icon {
fn style(&mut self) -> &mut gpui::StyleRefinement {
self.base.style()
}
}
impl Icon { impl Icon {
pub fn new(name: IconName) -> Self { pub fn new(name: IconName) -> Self {
Self { Self {
base: svg().flex_none().size_4(), base: svg().flex_none().size_4().text_color(rgb(0x000000)),
path: name.path(), path: name.path(),
} }
} }
@ -65,8 +68,14 @@ impl Icon {
} }
} }
impl Styled for Icon {
fn style(&mut self) -> &mut StyleRefinement {
self.base.style()
}
}
impl RenderOnce for Icon { impl RenderOnce for Icon {
fn render(self, cx: &mut WindowContext) -> impl IntoElement { fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
self.base.text_color(cx.theme().foreground).path(self.path) self.base.path(self.path)
} }
} }

View file

@ -3,12 +3,7 @@ use gpui::{
SharedString, Styled, ViewContext, VisualContext, WindowContext, SharedString, Styled, ViewContext, VisualContext, WindowContext,
}; };
use crate::{ use crate::{h_flex, styled_ext::ElevationIndex, theme::ActiveTheme, v_flex};
h_flex,
styled_ext::ElevationIndex,
theme::{ActiveTheme, Colorize},
v_flex,
};
pub struct Tooltip { pub struct Tooltip {
title: SharedString, title: SharedString,
@ -64,13 +59,13 @@ pub fn tooltip_container<V>(
// padding to avoid tooltip appearing right below the mouse cursor // padding to avoid tooltip appearing right below the mouse cursor
div().pl_2().pt_2p5().child( div().pl_2().pt_2p5().child(
v_flex() v_flex()
.bg(cx.theme().popover.invert_l()) .bg(cx.theme().popover)
.rounded(px(8.)) .rounded(px(8.))
.border_1() .border_1()
.border_color(cx.theme().border.invert_l()) .border_color(cx.theme().border)
.shadow(ElevationIndex::ElevatedSurface.shadow()) .shadow(ElevationIndex::ElevatedSurface.shadow())
.text_color(cx.theme().background) .text_color(cx.theme().popover_foreground)
.py_1() .py_1p5()
.px_2() .px_2()
.map(|el| f(el, cx)), .map(|el| f(el, cx)),
) )