diff --git a/README.md b/README.md index 1aa0bf2e..0003550f 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ This is an example of build app by using GPUI. https://github.com/huacnlee/gpui-app/assets/5518/ad103f02-697a-40ed-a876-8b13e4242a72 +https://github.com/huacnlee/gpui-app/assets/5518/5316f9f0-58c8-4b99-bd79-eafffb38c3fc + ## TODO - [x] Theming diff --git a/crates/ui-story/src/picker_story.rs b/crates/ui-story/src/picker_story.rs index a7647625..843eda83 100644 --- a/crates/ui-story/src/picker_story.rs +++ b/crates/ui-story/src/picker_story.rs @@ -48,12 +48,12 @@ impl PickerDelegate for ListItemDeletegate { .py_1() .px_3() .when(!selected, |this| { - this.hover(|this| this.bg(cx.theme().card)) + this.hover(|this| this.bg(cx.theme().accent)) }) .child(item.clone()) .text_base() .text_color(cx.theme().foreground) - .when(selected, |this| this.bg(cx.theme().card.lighten(0.1))); + .when(selected, |this| this.bg(cx.theme().accent)); Some(list_item) } else { None diff --git a/crates/ui-story/src/switch_story.rs b/crates/ui-story/src/switch_story.rs index e0f53099..77f2b1e1 100644 --- a/crates/ui-story/src/switch_story.rs +++ b/crates/ui-story/src/switch_story.rs @@ -3,6 +3,7 @@ use gpui::{ }; use ui::{ + button::ButtonSize, h_flex, label::Label, switch::{LabelSide, Switch}, @@ -16,6 +17,7 @@ use super::story_case; pub struct SwitchStory { switch1: bool, switch2: bool, + switch3: bool, } impl SwitchStory { @@ -23,6 +25,7 @@ impl SwitchStory { Self { switch1: false, switch2: true, + switch3: true, } } } @@ -106,7 +109,18 @@ impl Render for SwitchStory { println!("Switch value changed: {:?}", ev); }), )) + ) + .child( + card(cx).v_flex() .items_start().child(title("Disabled Switchs")).child( + h_flex().items_center() + .gap_6() + .child(Switch::new("switch3").checked(self.switch3).label("Small Size").size(ButtonSize::Small).on_click(cx.listener(move |view, _, cx| { + view.switch3 = !view.switch3; + cx.notify(); + })), + ) ), + ) ) } } diff --git a/crates/ui/src/divider.rs b/crates/ui/src/divider.rs index 010a8a95..75a29798 100644 --- a/crates/ui/src/divider.rs +++ b/crates/ui/src/divider.rs @@ -37,7 +37,7 @@ impl RenderOnce for Divider { Orientation::Vertical => this.v_flex().w_0().h_full(), Orientation::Horizontal => this.h_flex().h_0().w_full(), }) - .border_1() + .border_b_1() .border_color(theme.border) } } diff --git a/crates/ui/src/picker.rs b/crates/ui/src/picker.rs index fe92a74f..2c578ff7 100644 --- a/crates/ui/src/picker.rs +++ b/crates/ui/src/picker.rs @@ -463,6 +463,7 @@ impl Render for Picker { // .on_action(cx.listener(Self::secondary_confirm)) .on_action(cx.listener(Self::use_selected_query)) // .on_action(cx.listener(Self::confirm_input)) + // Render Query Input header .child(match self.query_input { Some(ref input) => self.delegate.render_query(input, cx), None => div().child(self.head.clone()), diff --git a/crates/ui/src/switch.rs b/crates/ui/src/switch.rs index bf14c7f4..d2348761 100644 --- a/crates/ui/src/switch.rs +++ b/crates/ui/src/switch.rs @@ -1,11 +1,12 @@ use crate::{ + button::ButtonSize, label::Label, stock::h_flex, theme::{ActiveTheme, Colorize}, Disableable, }; use gpui::{ - div, prelude::FluentBuilder as _, ClickEvent, Div, InteractiveElement, IntoElement, + div, prelude::FluentBuilder as _, px, ClickEvent, Div, InteractiveElement, IntoElement, ParentElement as _, RenderOnce, SharedString, Stateful, StatefulInteractiveElement, Styled as _, WindowContext, }; @@ -32,6 +33,7 @@ pub struct Switch { label: Option, label_side: LabelSide, on_click: Option, + size: ButtonSize, } impl Switch { @@ -46,6 +48,7 @@ impl Switch { label: None, on_click: None, label_side: LabelSide::Right, + size: ButtonSize::Medium, } } @@ -59,6 +62,11 @@ impl Switch { self } + pub fn size(mut self, size: ButtonSize) -> Self { + self.size = size; + self + } + pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self { self.on_click = Some(Box::new(handler)); self @@ -100,11 +108,12 @@ impl RenderOnce for Switch { .when(self.label_side.left(), |this| this.flex_row_reverse()) .child( self.base - .w_11() - .h_6() + .map(|this| match self.size { + ButtonSize::Medium => this.w_11().h_6().rounded_xl(), + ButtonSize::Small => this.w_8().h_4().rounded_lg(), + }) .flex() .items_center() - .rounded_xl() .border_2() .border_color(theme.transparent) .bg(bg) @@ -113,9 +122,22 @@ impl RenderOnce for Switch { true => this.flex_row_reverse(), false => this, }) - .child(div().h_4().w_4().rounded_full().bg(toggle_bg)), + .child( + div() + .rounded_full() + .bg(toggle_bg) + .map(|this| match self.size { + ButtonSize::Medium => this.w_5().h_5(), + ButtonSize::Small => this.w_3().h_3(), + }), + ), ) - .when_some(self.label, |this, label| this.child(Label::new(label))) + .when_some(self.label, |this, label| { + this.child(Label::new(label).map(|this| match self.size { + ButtonSize::Medium => this.text_base(), + ButtonSize::Small => this.text_sm(), + })) + }) .when_some( self.on_click.filter(|_| !self.disabled), |this, on_click| this.on_click(move |ev, cx| on_click(ev, cx)), diff --git a/crates/ui/src/theme.rs b/crates/ui/src/theme.rs index 143a7009..0b16049b 100644 --- a/crates/ui/src/theme.rs +++ b/crates/ui/src/theme.rs @@ -163,7 +163,7 @@ impl Colors { secondary_foreground: hsl(240.0, 0.059, 0.1), muted: hsl(240.0, 0.048, 0.959), muted_foreground: hsl(240.0, 0.038, 0.461), - accent: hsl(240.0, 0.048, 0.959), + accent: hsl(240.0, 0.05, 0.96), accent_foreground: hsl(240.0, 0.059, 0.1), destructive: hsl(0.0, 0.842, 0.602), destructive_foreground: hsl(0.0, 0.0, 0.98), @@ -269,12 +269,18 @@ impl From for Theme { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, PartialOrd, Eq)] pub enum ThemeMode { Light, Dark, } +impl ThemeMode { + pub fn is_dark(&self) -> bool { + matches!(self, Self::Dark) + } +} + impl Theme { fn new() -> Self { Self::from(Colors::dark()) diff --git a/crates/workspace/src/lib.rs b/crates/workspace/src/lib.rs index 9e14f858..d8a9df4b 100644 --- a/crates/workspace/src/lib.rs +++ b/crates/workspace/src/lib.rs @@ -3,8 +3,9 @@ use prelude::FluentBuilder as _; use std::sync::Arc; use ui::{ - button::Button, + button::{Button, ButtonSize}, label::Label, + switch::{LabelSide, Switch}, theme::{ActiveTheme, Theme}, title_bar::TitleBar, Clickable as _, StyledExt as _, @@ -126,25 +127,21 @@ impl Render for Workspace { // left side .child(div().flex().items_center().child(Label::new("GPUI App"))) .child( - div() - .flex() - .items_center() - .justify_end() - .px_2() - .child( - Button::new("btn-light", "Light") - .size(ui::button::ButtonSize::Small) - .on_click(|_e, cx| { - Theme::change(ui::theme::ThemeMode::Light, cx) - }), - ) - .child( - Button::new("btn-dark", "Dark") - .size(ui::button::ButtonSize::Small) - .on_click(|_e, cx| { - Theme::change(ui::theme::ThemeMode::Dark, cx) - }), - ), + div().flex().items_center().justify_end().px_2().child( + Switch::new("theme-mode") + .size(ButtonSize::Small) + .checked(cx.theme().mode.is_dark()) + .label_side(LabelSide::Left) + .label("Dark Mode") + .on_click(cx.listener(|v, _, cx| { + let mode = match cx.theme().mode { + ui::theme::ThemeMode::Light => ui::theme::ThemeMode::Dark, + ui::theme::ThemeMode::Dark => ui::theme::ThemeMode::Light, + }; + + Theme::change(mode, cx); + })), + ), ), ) .child(div().flex().px_4().gap_2().child(self.stories.clone()))