Jason Lee 2024-07-12 17:33:05 +08:00 committed by GitHub
parent ff8d39d4a9
commit 7c99584862
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 219 additions and 109 deletions

1
Cargo.lock generated
View file

@ -5427,7 +5427,6 @@ dependencies = [
"taffy", "taffy",
"unicode-segmentation", "unicode-segmentation",
"usvg", "usvg",
"uuid",
"windows", "windows",
"wry", "wry",
] ]

View file

@ -37,6 +37,7 @@ This is an example of build app by using GPUI.
- [x] Button with Icon - [x] Button with Icon
- [x] IconButton - [x] IconButton
- [x] Glost / Outline Button - [x] Glost / Outline Button
- [x] Loading
- [x] Label - [x] Label
- [x] Icon - [x] Icon
- [x] Checkbox - [x] Checkbox
@ -58,8 +59,8 @@ This is an example of build app by using GPUI.
- [x] Dockpanel - [x] Dockpanel
- [x] Resizable - [x] Resizable
- [x] Progress - [x] Progress
- [ ] ProgressBar - [x] ProgressBar
- [ ] Loading - [x] Indicator
- [ ] Skeleton - [ ] Skeleton
- [ ] DatePicker - [ ] DatePicker
- [ ] DateTimePicker - [ ] DateTimePicker

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-loader-circle">
<path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>

After

Width:  |  Height:  |  Size: 266 B

10
assets/icons/loader.svg Normal file
View file

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-loader">
<path d="M12 2v4"/>
<path d="m16.2 7.8 2.9-2.9"/>
<path d="M18 12h4"/>
<path d="m16.2 16.2 2.9 2.9"/>
<path d="M12 18v4"/>
<path d="m4.9 19.1 2.9-2.9"/>
<path d="M2 12h4"/>
<path d="m4.9 4.9 2.9 2.9"/>
</svg>

After

Width:  |  Height:  |  Size: 435 B

View file

@ -9,9 +9,9 @@ use workspace::{dock::DockPosition, TitleBar, Workspace};
use std::sync::Arc; use std::sync::Arc;
use ui::{ use ui::{
button::ButtonSize,
switch::{LabelSide, Switch}, switch::{LabelSide, Switch},
theme::{ActiveTheme, Theme}, theme::{ActiveTheme, Theme},
Size,
}; };
use crate::app_state::AppState; use crate::app_state::AppState;
@ -173,7 +173,7 @@ impl StoryWorkspace {
appears_transparent: true, appears_transparent: true,
traffic_light_position: Some(point(px(9.0), px(9.0))), traffic_light_position: Some(point(px(9.0), px(9.0))),
}), }),
window_min_size: Some(Size { window_min_size: Some(gpui::Size {
width: px(640.), width: px(640.),
height: px(480.), height: px(480.),
}), }),
@ -255,7 +255,7 @@ impl Render for StoryWorkspace {
.mr_3() .mr_3()
.child( .child(
Switch::new("theme-mode") Switch::new("theme-mode")
.size(ButtonSize::Small) .size(Size::Small)
.checked(cx.theme().mode.is_dark()) .checked(cx.theme().mode.is_dark())
.label_side(LabelSide::Left) .label_side(LabelSide::Left)
.label("Dark Mode") .label("Dark Mode")

View file

@ -4,8 +4,8 @@ use gpui::{
}; };
use ui::{ use ui::{
button::{Button, ButtonSize, ButtonStyle}, button::{Button, ButtonStyle},
h_flex, v_flex, Clickable, Disableable as _, Icon, IconName, Selectable, h_flex, v_flex, Clickable, Disableable as _, Icon, IconName, Selectable, Size,
}; };
use crate::section; use crate::section;
@ -96,21 +96,22 @@ impl Render for ButtonStory {
Button::new("button-6", cx) Button::new("button-6", cx)
.label("Primary Button") .label("Primary Button")
.style(ButtonStyle::Primary) .style(ButtonStyle::Primary)
.size(ButtonSize::Small) .size(Size::Small)
.loading(true)
.on_click(Self::on_click), .on_click(Self::on_click),
) )
.child( .child(
Button::new("button-7", cx) Button::new("button-7", cx)
.label("Secondary Button") .label("Secondary Button")
.style(ButtonStyle::Secondary) .style(ButtonStyle::Secondary)
.size(ButtonSize::Small) .size(Size::Small)
.on_click(Self::on_click), .on_click(Self::on_click),
) )
.child( .child(
Button::new("button-8", cx) Button::new("button-8", cx)
.label("Danger Button") .label("Danger Button")
.style(ButtonStyle::Danger) .style(ButtonStyle::Danger)
.size(ButtonSize::Small) .size(Size::Small)
.on_click(Self::on_click), .on_click(Self::on_click),
), ),
) )
@ -120,21 +121,22 @@ impl Render for ButtonStory {
Button::new("button-xs-1", cx) Button::new("button-xs-1", cx)
.label("Primary Button") .label("Primary Button")
.style(ButtonStyle::Primary) .style(ButtonStyle::Primary)
.size(ButtonSize::XSmall) .size(Size::XSmall)
.on_click(Self::on_click), .on_click(Self::on_click),
) )
.child( .child(
Button::new("button-xs-2", cx) Button::new("button-xs-2", cx)
.label("Secondary Button") .label("Secondary Button")
.style(ButtonStyle::Secondary) .style(ButtonStyle::Secondary)
.size(ButtonSize::XSmall) .size(Size::XSmall)
.loading(true)
.on_click(Self::on_click), .on_click(Self::on_click),
) )
.child( .child(
Button::new("button-xs-3", cx) Button::new("button-xs-3", cx)
.label("Danger Button") .label("Danger Button")
.style(ButtonStyle::Danger) .style(ButtonStyle::Danger)
.size(ButtonSize::XSmall) .size(Size::XSmall)
.on_click(Self::on_click), .on_click(Self::on_click),
), ),
), ),
@ -163,7 +165,8 @@ impl Render for ButtonStory {
.label("Disabled Button") .label("Disabled Button")
.style(ButtonStyle::Danger) .style(ButtonStyle::Danger)
.on_click(Self::on_click) .on_click(Self::on_click)
.disabled(true), .disabled(true)
.loading(true),
), ),
) )
.child( .child(
@ -195,7 +198,11 @@ impl Render for ButtonStory {
.icon(IconName::Search) .icon(IconName::Search)
.style(ButtonStyle::Primary), .style(ButtonStyle::Primary),
) )
.child(Button::new("icon-button-1", cx).icon(IconName::Info)) .child(
Button::new("icon-button-1", cx)
.icon(IconName::Info)
.loading(true),
)
.child( .child(
Button::new("icon-button-2", cx) Button::new("icon-button-2", cx)
.icon(IconName::Close) .icon(IconName::Close)
@ -204,7 +211,7 @@ impl Render for ButtonStory {
.child( .child(
Button::new("icon-button-3", cx) Button::new("icon-button-3", cx)
.icon(IconName::Search) .icon(IconName::Search)
.size(ButtonSize::Small) .size(Size::Small)
.style(ButtonStyle::Primary), .style(ButtonStyle::Primary),
) )
.child( .child(
@ -223,29 +230,29 @@ impl Render for ButtonStory {
.child( .child(
Button::new("icon-button-4", cx) Button::new("icon-button-4", cx)
.icon(IconName::Info) .icon(IconName::Info)
.size(ButtonSize::Small), .size(Size::Small),
) )
.child( .child(
Button::new("icon-button-5", cx) Button::new("icon-button-5", cx)
.icon(IconName::Close) .icon(IconName::Close)
.size(ButtonSize::Small) .size(Size::Small)
.style(ButtonStyle::Danger), .style(ButtonStyle::Danger),
) )
.child( .child(
Button::new("icon-button-6", cx) Button::new("icon-button-6", cx)
.icon(IconName::Search) .icon(IconName::Search)
.size(ButtonSize::XSmall) .size(Size::XSmall)
.style(ButtonStyle::Primary), .style(ButtonStyle::Primary),
) )
.child( .child(
Button::new("icon-button-7", cx) Button::new("icon-button-7", cx)
.icon(IconName::Info) .icon(IconName::Info)
.size(ButtonSize::XSmall), .size(Size::XSmall),
) )
.child( .child(
Button::new("icon-button-8", cx) Button::new("icon-button-8", cx)
.icon(IconName::Close) .icon(IconName::Close)
.size(ButtonSize::XSmall) .size(Size::XSmall)
.style(ButtonStyle::Danger), .style(ButtonStyle::Danger),
), ),
) )

View file

@ -4,7 +4,7 @@ use gpui::{
ParentElement as _, Render, Styled as _, View, ViewContext, VisualContext, WindowContext, ParentElement as _, Render, Styled as _, View, ViewContext, VisualContext, WindowContext,
}; };
use ui::{ use ui::{
button::{Button, ButtonSize}, button::Button,
divider::Divider, divider::Divider,
h_flex, h_flex,
input::TextInput, input::TextInput,
@ -12,7 +12,7 @@ use ui::{
popup_menu::PopupMenu, popup_menu::PopupMenu,
prelude::FluentBuilder, prelude::FluentBuilder,
switch::Switch, switch::Switch,
v_flex, Clickable, IconName, v_flex, Clickable, IconName, Size,
}; };
actions!(popover_story, [Copy, Paste, Cut, SearchAll]); actions!(popover_story, [Copy, Paste, Cut, SearchAll]);
@ -141,7 +141,7 @@ impl Render for PopoverStory {
Button::new("info1", cx) Button::new("info1", cx)
.label("Yes") .label("Yes")
.width(px(80.)) .width(px(80.))
.size(ButtonSize::Small), .size(Size::Small),
) )
.into_any() .into_any()
}) })
@ -164,7 +164,7 @@ impl Render for PopoverStory {
Button::new("info1", cx) Button::new("info1", cx)
.label("Yes") .label("Yes")
.width(px(80.)) .width(px(80.))
.size(ButtonSize::Small), .size(Size::Small),
) )
.into_any() .into_any()
}) })
@ -234,7 +234,7 @@ impl Render for PopoverStory {
Button::new("info1", cx) Button::new("info1", cx)
.label("Yes") .label("Yes")
.width(px(80.)) .width(px(80.))
.size(ButtonSize::Small), .size(Size::Small),
) )
.into_any() .into_any()
}) })

View file

@ -1,8 +1,11 @@
use gpui::{ use gpui::{
div, IntoElement, ParentElement, Render, Styled, View, ViewContext, VisualContext, div, px, IntoElement, ParentElement, Render, Styled, View, ViewContext, VisualContext,
WindowContext, WindowContext,
}; };
use ui::{button::Button, h_flex, progress::Progress, v_flex, Clickable, IconName}; use ui::{
button::Button, h_flex, indicator::Indicator, progress::Progress, v_flex, Clickable, IconName,
Size,
};
pub struct ProgressStory { pub struct ProgressStory {
value: f32, value: f32,
@ -74,5 +77,19 @@ impl Render for ProgressStory {
})), })),
), ),
) )
.child(
h_flex()
.gap_x_2()
.child(Indicator::new().size(Size::XSmall))
.child(Indicator::new().size(Size::Small))
.child(Indicator::new())
.child(
Indicator::new()
.size(Size::Large)
.icon(IconName::LoaderCircle)
.color(ui::blue_500()),
)
.child(Indicator::new().size(px(64.))),
)
} }
} }

View file

@ -4,12 +4,11 @@ use gpui::{
}; };
use ui::{ use ui::{
button::ButtonSize,
h_flex, h_flex,
label::Label, label::Label,
switch::{LabelSide, Switch}, switch::{LabelSide, Switch},
theme::ActiveTheme, theme::ActiveTheme,
v_flex, Disableable as _, StyledExt, v_flex, Disableable as _, Size, StyledExt,
}; };
#[derive(Default)] #[derive(Default)]
@ -116,7 +115,7 @@ impl Render for SwitchStory {
.items_start().child(title("Disabled Switchs")).child( .items_start().child(title("Disabled Switchs")).child(
h_flex().items_center() h_flex().items_center()
.gap_6() .gap_6()
.child(Switch::new("switch3").checked(self.switch3).label("Small Size").size(ButtonSize::Small).on_click(cx.listener(move |view, checked, cx| { .child(Switch::new("switch3").checked(self.switch3).label("Small Size").size(Size::Small).on_click(cx.listener(move |view, checked, cx| {
view.switch3 = *checked; view.switch3 = *checked;
cx.notify(); cx.notify();
})), })),

View file

@ -24,7 +24,6 @@ usvg = { version = "0.41.0", default-features = false }
taffy = "0.4.3" taffy = "0.4.3"
paste = "1" paste = "1"
once_cell = "1.19.0" once_cell = "1.19.0"
uuid = "1.10.0"
[lints] [lints]
workspace = true workspace = true

View file

@ -1,7 +1,8 @@
use crate::{ use crate::{
h_flex, h_flex,
indicator::Indicator,
theme::{ActiveTheme, Colorize as _}, theme::{ActiveTheme, Colorize as _},
Clickable, Disableable, Icon, Selectable, StyledExt, Clickable, Disableable, Icon, Selectable, Size, StyledExt,
}; };
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, px, ClickEvent, DefiniteLength, Div, ElementId, FocusHandle, div, prelude::FluentBuilder as _, px, ClickEvent, DefiniteLength, Div, ElementId, FocusHandle,
@ -16,13 +17,6 @@ pub enum ButtonRounded {
Large, Large,
} }
#[derive(Clone, Copy)]
pub enum ButtonSize {
XSmall,
Small,
Medium,
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ButtonStyle { pub enum ButtonStyle {
Primary, Primary,
@ -45,9 +39,10 @@ pub struct Button {
height: Option<DefiniteLength>, height: Option<DefiniteLength>,
style: ButtonStyle, style: ButtonStyle,
rounded: ButtonRounded, rounded: ButtonRounded,
size: ButtonSize, size: Size,
tooltip: Option<SharedString>, tooltip: Option<SharedString>,
on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>, on_click: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
loading: bool,
} }
impl Button { impl Button {
@ -64,9 +59,10 @@ impl Button {
width: None, width: None,
height: None, height: None,
rounded: ButtonRounded::Medium, rounded: ButtonRounded::Medium,
size: ButtonSize::Medium, size: Size::Medium,
tooltip: None, tooltip: None,
on_click: None, on_click: None,
loading: false,
} }
} }
@ -91,7 +87,7 @@ impl Button {
label: impl Into<SharedString>, label: impl Into<SharedString>,
cx: &mut WindowContext, cx: &mut WindowContext,
) -> Self { ) -> Self {
Self::new(id, cx).label(label).size(ButtonSize::Small) Self::new(id, cx).label(label).size(Size::Small)
} }
pub fn width(mut self, width: impl Into<DefiniteLength>) -> Self { pub fn width(mut self, width: impl Into<DefiniteLength>) -> Self {
@ -109,8 +105,8 @@ impl Button {
self self
} }
pub fn size(mut self, size: ButtonSize) -> Self { pub fn size(mut self, size: impl Into<Size>) -> Self {
self.size = size; self.size = size.into();
self self
} }
@ -134,6 +130,11 @@ impl Button {
self.style = style; self.style = style;
self self
} }
pub fn loading(mut self, loading: bool) -> Self {
self.loading = loading;
self
}
} }
impl Disableable for Button { impl Disableable for Button {
@ -180,15 +181,16 @@ impl RenderOnce for Button {
.map(|this| { .map(|this| {
if self.label.is_none() { if self.label.is_none() {
match self.size { match self.size {
ButtonSize::XSmall => this.size_5(), Size::Size(px) => this.size(px),
ButtonSize::Small => this.size_6(), Size::XSmall => this.size_5(),
ButtonSize::Medium => this.size_8(), Size::Small => this.size_6(),
Size::Large | Size::Medium => this.size_8(),
} }
} else { } else {
match self.size { match self.size {
ButtonSize::XSmall => this.px_1().py_1().h_5(), Size::XSmall => this.px_1().py_1().h_5(),
ButtonSize::Small => this.px_3().py_2().h_6(), Size::Small => this.px_3().py_2().h_6(),
ButtonSize::Medium => this.px_4().py_2().h_8(), _ => this.px_4().py_2().h_8(),
} }
} }
}) })
@ -247,14 +249,19 @@ impl RenderOnce for Button {
.justify_center() .justify_center()
.gap_2() .gap_2()
.text_color(text_color) .text_color(text_color)
.when_some(self.icon, |this, icon| { .when(!self.loading, |this| {
this.child(icon.size(self.size).text_color(text_color)) this.when_some(self.icon, |this, icon| {
this.child(icon.size(self.size).text_color(text_color))
})
})
.when(self.loading, |this| {
this.child(Indicator::new().size(self.size).color(text_color))
}) })
.when_some(self.label, |this, label| this.child(label)) .when_some(self.label, |this, label| this.child(label))
.map(|this| match self.size { .map(|this| match self.size {
ButtonSize::XSmall => this.text_xs(), Size::XSmall => this.text_xs(),
ButtonSize::Small => this.text_sm(), Size::Small => this.text_sm(),
ButtonSize::Medium => this.text_base(), _ => this.text_base(),
}) })
}) })
} }

View file

@ -1,6 +1,6 @@
use crate::{button::ButtonSize, theme::ActiveTheme}; use crate::{theme::ActiveTheme, Size};
use gpui::{ use gpui::{
prelude::FluentBuilder as _, svg, AnyElement, Hsla, IntoElement, Pixels, Render, RenderOnce, prelude::FluentBuilder as _, svg, AnyElement, Hsla, IntoElement, Render, RenderOnce,
SharedString, StyleRefinement, Styled, Svg, View, VisualContext, WindowContext, SharedString, StyleRefinement, Styled, Svg, View, VisualContext, WindowContext,
}; };
@ -21,6 +21,8 @@ pub enum IconName {
Search, Search,
Delete, Delete,
CircleX, CircleX,
Loader,
LoaderCircle,
} }
impl IconName { impl IconName {
@ -41,6 +43,8 @@ impl IconName {
IconName::Search => "icons/search.svg", IconName::Search => "icons/search.svg",
IconName::Delete => "icons/delete.svg", IconName::Delete => "icons/delete.svg",
IconName::CircleX => "icons/circle-x.svg", IconName::CircleX => "icons/circle-x.svg",
IconName::Loader => "icons/loader.svg",
IconName::LoaderCircle => "icons/loader-circle.svg",
} }
.into() .into()
} }
@ -69,36 +73,12 @@ impl RenderOnce for IconName {
} }
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum IconSize {
XSmall,
Small,
Medium,
Size(Pixels),
}
impl From<ButtonSize> for IconSize {
fn from(size: ButtonSize) -> Self {
match size {
ButtonSize::XSmall => IconSize::XSmall,
ButtonSize::Small => IconSize::Small,
ButtonSize::Medium => IconSize::Medium,
}
}
}
impl From<Pixels> for IconSize {
fn from(size: Pixels) -> Self {
IconSize::Size(size)
}
}
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct Icon { pub struct Icon {
base: Svg, base: Svg,
path: SharedString, path: SharedString,
text_color: Option<Hsla>, text_color: Option<Hsla>,
size: IconSize, size: Size,
} }
impl Default for Icon { impl Default for Icon {
@ -107,7 +87,7 @@ impl Default for Icon {
base: svg().flex_none().size_4(), base: svg().flex_none().size_4(),
path: "".into(), path: "".into(),
text_color: None, text_color: None,
size: IconSize::Medium, size: Size::Medium,
} }
} }
} }
@ -135,7 +115,7 @@ impl Icon {
/// ///
/// Also can receive a `ButtonSize` to convert to `IconSize`, /// Also can receive a `ButtonSize` to convert to `IconSize`,
/// Or a `Pixels` to set a custom size: `px(30.)` /// Or a `Pixels` to set a custom size: `px(30.)`
pub fn size(mut self, size: impl Into<IconSize>) -> Self { pub fn size(mut self, size: impl Into<Size>) -> Self {
self.size = size.into(); self.size = size.into();
self self
@ -145,6 +125,11 @@ impl Icon {
pub fn view(self, cx: &mut WindowContext) -> View<Icon> { pub fn view(self, cx: &mut WindowContext) -> View<Icon> {
cx.new_view(|_| self) cx.new_view(|_| self)
} }
pub fn transform(mut self, transformation: gpui::Transformation) -> Self {
self.base = self.base.with_transformation(transformation);
self
}
} }
impl Styled for Icon { impl Styled for Icon {
@ -165,10 +150,11 @@ impl RenderOnce for Icon {
self.base self.base
.text_color(text_color) .text_color(text_color)
.map(|this| match self.size { .map(|this| match self.size {
IconSize::Size(px) => this.size(px), Size::Size(px) => this.size(px),
IconSize::XSmall => this.size_3(), Size::XSmall => this.size_3(),
IconSize::Small => this.size_3p5(), Size::Small => this.size_3p5(),
IconSize::Medium => this.size_4(), Size::Medium => this.size_4(),
Size::Large => this.size_6(),
}) })
.path(self.path) .path(self.path)
} }
@ -189,10 +175,11 @@ impl Render for Icon {
.size_4() .size_4()
.text_color(text_color) .text_color(text_color)
.map(|this| match self.size { .map(|this| match self.size {
IconSize::Size(px) => this.size(px), Size::Size(px) => this.size(px),
IconSize::XSmall => this.size_3(), Size::XSmall => this.size_3(),
IconSize::Small => this.size_3p5(), Size::Small => this.size_3p5(),
IconSize::Medium => this.size_4(), Size::Medium => this.size_4(),
Size::Large => this.size_6(),
}) })
.path(self.path.clone()) .path(self.path.clone())
} }

View file

@ -0,0 +1,59 @@
use std::time::Duration;
use crate::{theme::ActiveTheme, Icon, IconName, Size};
use gpui::{
div, ease_in_out, percentage, Animation, AnimationExt as _, Hsla, IntoElement, ParentElement,
RenderOnce, Styled as _, Transformation,
};
#[derive(IntoElement)]
pub struct Indicator {
size: Size,
icon: IconName,
speed: Duration,
color: Option<Hsla>,
}
impl Indicator {
pub fn new() -> Self {
Self {
size: Size::Medium,
speed: Duration::from_secs_f64(0.8),
icon: IconName::Loader,
color: None,
}
}
pub fn size(mut self, size: impl Into<Size>) -> Self {
self.size = size.into();
self
}
pub fn icon(mut self, icon: IconName) -> Self {
self.icon = icon;
self
}
pub fn color(mut self, color: Hsla) -> Self {
self.color = Some(color);
self
}
}
impl RenderOnce for Indicator {
fn render(self, cx: &mut gpui::WindowContext) -> impl IntoElement {
let color = self.color.unwrap_or_else(|| cx.theme().indicator);
div()
.child(
Icon::new(self.icon)
.size(self.size)
.text_color(color)
.with_animation(
"circle",
Animation::new(self.speed).repeat().with_easing(ease_in_out),
|this, delta| this.transform(Transformation::rotate(percentage(delta))),
),
)
.into_element()
}
}

View file

@ -4,6 +4,7 @@ mod disableable;
mod event; mod event;
mod focusable; mod focusable;
mod icon; mod icon;
mod scroll; mod scroll;
mod scrollbar; mod scrollbar;
mod selectable; mod selectable;
@ -15,6 +16,7 @@ pub mod button;
pub mod checkbox; pub mod checkbox;
pub mod divider; pub mod divider;
pub mod dropdown; pub mod dropdown;
pub mod indicator;
pub mod input; pub mod input;
pub mod label; pub mod label;
pub mod list; pub mod list;
@ -35,7 +37,7 @@ pub use disableable::Disableable;
pub use event::InterativeElementExt; pub use event::InterativeElementExt;
pub use focusable::FocusableCycle; pub use focusable::FocusableCycle;
pub use selectable::{Selectable, Selection}; pub use selectable::{Selectable, Selection};
pub use styled_ext::StyledExt; pub use styled_ext::{Size, StyledExt};
pub use colors::*; pub use colors::*;
pub use icon::*; pub use icon::*;

View file

@ -47,7 +47,7 @@ impl RenderOnce for Progress {
}) })
.h_full() .h_full()
.w(relative_w) .w(relative_w)
.bg(cx.theme().primary), .bg(cx.theme().progress_bar),
) )
.child( .child(
div() div()
@ -57,7 +57,7 @@ impl RenderOnce for Progress {
}) })
.h_full() .h_full()
.flex_1() .flex_1()
.bg(cx.theme().primary.opacity(0.2)), .bg(cx.theme().progress_bar.opacity(0.2)),
) )
} }
} }

View file

@ -1,5 +1,5 @@
use crate::theme::ActiveTheme; use crate::theme::ActiveTheme;
use gpui::{hsla, point, px, BoxShadow, FocusHandle, Styled, WindowContext}; use gpui::{hsla, point, px, BoxShadow, FocusHandle, Pixels, Styled, WindowContext};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
pub enum ElevationIndex { pub enum ElevationIndex {
@ -133,3 +133,19 @@ pub trait StyledExt: Styled + Sized {
} }
impl<E: Styled> StyledExt for E {} impl<E: Styled> StyledExt for E {}
/// A size for elements.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Size {
Size(Pixels),
XSmall,
Small,
Medium,
Large,
}
impl From<Pixels> for Size {
fn from(size: Pixels) -> Self {
Size::Size(size)
}
}

View file

@ -1,8 +1,7 @@
use crate::{ use crate::{
button::ButtonSize,
stack::h_flex, stack::h_flex,
theme::{ActiveTheme, Colorize}, theme::{ActiveTheme, Colorize},
Disableable, Disableable, Size,
}; };
use gpui::{ use gpui::{
div, prelude::FluentBuilder as _, Div, InteractiveElement, IntoElement, ParentElement as _, div, prelude::FluentBuilder as _, Div, InteractiveElement, IntoElement, ParentElement as _,
@ -31,7 +30,7 @@ pub struct Switch {
label: Option<SharedString>, label: Option<SharedString>,
label_side: LabelSide, label_side: LabelSide,
on_click: Option<OnClick>, on_click: Option<OnClick>,
size: ButtonSize, size: Size,
} }
impl Switch { impl Switch {
@ -46,7 +45,7 @@ impl Switch {
label: None, label: None,
on_click: None, on_click: None,
label_side: LabelSide::Right, label_side: LabelSide::Right,
size: ButtonSize::Medium, size: Size::Medium,
} }
} }
@ -60,7 +59,8 @@ impl Switch {
self self
} }
pub fn size(mut self, size: ButtonSize) -> Self { /// Only supported XSmall, Small, Medium
pub fn size(mut self, size: Size) -> Self {
self.size = size; self.size = size;
self self
} }
@ -107,8 +107,8 @@ impl RenderOnce for Switch {
.child( .child(
self.base self.base
.map(|this| match self.size { .map(|this| match self.size {
ButtonSize::Medium => this.w_11().h_6().rounded_xl(), Size::XSmall | Size::Small => this.w_8().h_4().rounded_lg(),
ButtonSize::XSmall | ButtonSize::Small => this.w_8().h_4().rounded_lg(), _ => this.w_11().h_6().rounded_xl(),
}) })
.flex() .flex()
.items_center() .items_center()
@ -125,15 +125,15 @@ impl RenderOnce for Switch {
.rounded_full() .rounded_full()
.bg(toggle_bg) .bg(toggle_bg)
.map(|this| match self.size { .map(|this| match self.size {
ButtonSize::Medium => this.w_5().h_5(), Size::XSmall | Size::Small => this.w_3().h_3(),
ButtonSize::XSmall | ButtonSize::Small => this.w_3().h_3(), _ => this.w_5().h_5(),
}), }),
), ),
) )
.when_some(self.label, |this, label| { .when_some(self.label, |this, label| {
this.child(div().child(label).map(|this| match self.size { this.child(div().child(label).map(|this| match self.size {
ButtonSize::Medium => this.text_base(), Size::XSmall | Size::Small => this.text_sm(),
ButtonSize::XSmall | ButtonSize::Small => this.text_sm(), _ => this.text_base(),
})) }))
}) })
.when_some( .when_some(

View file

@ -301,6 +301,8 @@ pub struct Theme {
pub tab_active: Hsla, pub tab_active: Hsla,
pub tab_foreground: Hsla, pub tab_foreground: Hsla,
pub tab_active_foreground: Hsla, pub tab_active_foreground: Hsla,
pub indicator: Hsla,
pub progress_bar: Hsla,
} }
impl Global for Theme {} impl Global for Theme {}
@ -355,6 +357,8 @@ impl From<Colors> for Theme {
tab_active: colors.background, tab_active: colors.background,
tab_foreground: colors.foreground, tab_foreground: colors.foreground,
tab_active_foreground: colors.foreground, tab_active_foreground: colors.foreground,
indicator: colors.secondary_foreground,
progress_bar: colors.primary,
} }
} }
} }