From 0d161519e402982dded19a7b1d78bd5dc0faf4b7 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 12 Sep 2023 11:34:27 -0400 Subject: [PATCH 01/22] Checkpoint --- crates/storybook/src/components.rs | 6 +- crates/storybook/src/components/avatar.rs | 39 +++++ .../storybook/src/components/icon_button.rs | 36 ++-- .../storybook/src/components/tool_divider.rs | 19 +++ crates/storybook/src/modules.rs | 4 + crates/storybook/src/modules/chat_panel.rs | 74 +++++++++ crates/storybook/src/modules/tab_bar.rs | 29 +++- crates/storybook/src/modules/title_bar.rs | 154 ++++++++++++++++++ crates/storybook/src/prelude.rs | 26 +++ crates/storybook/src/storybook.rs | 1 + crates/storybook/src/workspace.rs | 10 +- 11 files changed, 373 insertions(+), 25 deletions(-) create mode 100644 crates/storybook/src/components/avatar.rs create mode 100644 crates/storybook/src/components/tool_divider.rs create mode 100644 crates/storybook/src/modules/chat_panel.rs create mode 100644 crates/storybook/src/modules/title_bar.rs create mode 100644 crates/storybook/src/prelude.rs diff --git a/crates/storybook/src/components.rs b/crates/storybook/src/components.rs index d07c2651a0..e0ba73b866 100644 --- a/crates/storybook/src/components.rs +++ b/crates/storybook/src/components.rs @@ -4,11 +4,15 @@ use gpui2::{ }; use std::{marker::PhantomData, rc::Rc}; +mod avatar; mod icon_button; mod tab; +mod tool_divider; -pub(crate) use icon_button::{icon_button, ButtonVariant}; +pub(crate) use avatar::avatar; +pub(crate) use icon_button::icon_button; pub(crate) use tab::tab; +pub(crate) use tool_divider::tool_divider; struct ButtonHandlers { click: Option)>>, diff --git a/crates/storybook/src/components/avatar.rs b/crates/storybook/src/components/avatar.rs new file mode 100644 index 0000000000..8eff055d75 --- /dev/null +++ b/crates/storybook/src/components/avatar.rs @@ -0,0 +1,39 @@ +use crate::prelude::Shape; +use crate::theme::theme; +use gpui2::elements::img; +use gpui2::style::StyleHelpers; +use gpui2::{ArcCow, IntoElement}; +use gpui2::{Element, ViewContext}; + +pub type UnknownString = ArcCow<'static, str>; + +#[derive(Element)] +pub(crate) struct Avatar { + src: ArcCow<'static, str>, + shape: Shape, +} + +pub fn avatar(src: impl Into>, shape: Shape) -> impl Element { + Avatar { + src: src.into(), + shape, + } +} + +impl Avatar { + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { + let theme = theme(cx); + + let mut img = img(); + + if self.shape == Shape::Circle { + img = img.rounded_full(); + } else { + img = img.rounded_md(); + } + + img.uri(self.src.clone()) + .size_4() + .fill(theme.middle.warning.default.foreground) + } +} diff --git a/crates/storybook/src/components/icon_button.rs b/crates/storybook/src/components/icon_button.rs index 0a9b2ca285..cecb6ccfc3 100644 --- a/crates/storybook/src/components/icon_button.rs +++ b/crates/storybook/src/components/icon_button.rs @@ -1,3 +1,4 @@ +use crate::prelude::{ButtonVariant, UIState}; use crate::theme::theme; use gpui2::elements::svg; use gpui2::style::{StyleHelpers, Styleable}; @@ -8,22 +9,33 @@ use gpui2::{Element, ParentElement, ViewContext}; pub(crate) struct IconButton { path: &'static str, variant: ButtonVariant, + state: UIState, } -#[derive(PartialEq)] -pub enum ButtonVariant { - Ghost, - Filled, -} - -pub fn icon_button(path: &'static str, variant: ButtonVariant) -> impl Element { - IconButton { path, variant } +pub fn icon_button( + path: &'static str, + variant: ButtonVariant, + state: UIState, +) -> impl Element { + IconButton { + path, + variant, + state, + } } impl IconButton { fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { let theme = theme(cx); + let icon_color; + + if self.state == UIState::Disabled { + icon_color = theme.highest.base.disabled.foreground; + } else { + icon_color = theme.highest.base.default.foreground; + } + let mut div = div(); if self.variant == ButtonVariant::Filled { div = div.fill(theme.highest.on.default.background); @@ -39,12 +51,6 @@ impl IconButton { .fill(theme.highest.base.hovered.background) .active() .fill(theme.highest.base.pressed.background) - .child( - svg() - .path(self.path) - .w_4() - .h_4() - .fill(theme.highest.variant.default.foreground), - ) + .child(svg().path(self.path).w_4().h_4().fill(icon_color)) } } diff --git a/crates/storybook/src/components/tool_divider.rs b/crates/storybook/src/components/tool_divider.rs new file mode 100644 index 0000000000..c07d11dfe2 --- /dev/null +++ b/crates/storybook/src/components/tool_divider.rs @@ -0,0 +1,19 @@ +use crate::theme::theme; +use gpui2::style::StyleHelpers; +use gpui2::{elements::div, IntoElement}; +use gpui2::{Element, ViewContext}; + +#[derive(Element)] +pub(crate) struct ToolDivider {} + +pub fn tool_divider() -> impl Element { + ToolDivider {} +} + +impl ToolDivider { + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { + let theme = theme(cx); + + div().w_px().h_3().fill(theme.lowest.base.default.border) + } +} diff --git a/crates/storybook/src/modules.rs b/crates/storybook/src/modules.rs index bc8ba73b08..00b323fc5d 100644 --- a/crates/storybook/src/modules.rs +++ b/crates/storybook/src/modules.rs @@ -1,3 +1,7 @@ +mod chat_panel; mod tab_bar; +mod title_bar; +pub(crate) use chat_panel::chat_panel; pub(crate) use tab_bar::tab_bar; +pub(crate) use title_bar::title_bar; diff --git a/crates/storybook/src/modules/chat_panel.rs b/crates/storybook/src/modules/chat_panel.rs new file mode 100644 index 0000000000..772bb908e0 --- /dev/null +++ b/crates/storybook/src/modules/chat_panel.rs @@ -0,0 +1,74 @@ +use std::marker::PhantomData; + +use crate::components::icon_button; +use crate::prelude::{ButtonVariant, UIState}; +use crate::theme::theme; +use gpui2::elements::div::ScrollState; +use gpui2::style::StyleHelpers; +use gpui2::{elements::div, IntoElement}; +use gpui2::{Element, ParentElement, ViewContext}; + +#[derive(Element)] +pub struct ChatPanel { + view_type: PhantomData, + scroll_state: ScrollState, +} + +pub fn chat_panel(scroll_state: ScrollState) -> ChatPanel { + ChatPanel { + view_type: PhantomData, + scroll_state, + } +} + +impl ChatPanel { + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { + let theme = theme(cx); + + div() + .h_full() + .flex() + // Header + .child( + div() + .px_2() + .flex() + .gap_2() + // Nav Buttons + .child("#gpui2"), + ) + // Chat Body + .child( + div() + .w_full() + .flex() + .flex_col() + .overflow_y_scroll(self.scroll_state.clone()) + .child("body"), + ) + // Composer + .child( + div() + .px_2() + .flex() + .gap_2() + // Nav Buttons + .child( + div() + .flex() + .items_center() + .gap_px() + .child(icon_button( + "icons/plus.svg", + ButtonVariant::Ghost, + UIState::Default, + )) + .child(icon_button( + "icons/split.svg", + ButtonVariant::Ghost, + UIState::Default, + )), + ), + ) + } +} diff --git a/crates/storybook/src/modules/tab_bar.rs b/crates/storybook/src/modules/tab_bar.rs index 06029c5dc2..5a3358588e 100644 --- a/crates/storybook/src/modules/tab_bar.rs +++ b/crates/storybook/src/modules/tab_bar.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; -use crate::components::{icon_button, tab, ButtonVariant}; +use crate::components::{icon_button, tab}; +use crate::prelude::{ButtonVariant, UIState}; use crate::theme::theme; use gpui2::elements::div::ScrollState; use gpui2::style::StyleHelpers; @@ -40,15 +41,23 @@ impl TabBar { .flex() .items_center() .gap_px() - .child(icon_button("icons/arrow_left.svg", ButtonVariant::Filled)) - .child(icon_button("icons/arrow_right.svg", ButtonVariant::Ghost)), + .child(icon_button( + "icons/arrow_left.svg", + ButtonVariant::Ghost, + UIState::Default, + )) + .child(icon_button( + "icons/arrow_right.svg", + ButtonVariant::Ghost, + UIState::Disabled, + )), ), ) .child( div().w_0().flex_1().h_full().child( div() .flex() - .gap_px() + .gap_8() .overflow_x_scroll(self.scroll_state.clone()) .child(tab("Cargo.toml", false)) .child(tab("Channels Panel", true)) @@ -74,8 +83,16 @@ impl TabBar { .flex() .items_center() .gap_px() - .child(icon_button("icons/plus.svg", ButtonVariant::Ghost)) - .child(icon_button("icons/split.svg", ButtonVariant::Ghost)), + .child(icon_button( + "icons/plus.svg", + ButtonVariant::Ghost, + UIState::Default, + )) + .child(icon_button( + "icons/split.svg", + ButtonVariant::Ghost, + UIState::Default, + )), ), ) } diff --git a/crates/storybook/src/modules/title_bar.rs b/crates/storybook/src/modules/title_bar.rs new file mode 100644 index 0000000000..dfd4e4490e --- /dev/null +++ b/crates/storybook/src/modules/title_bar.rs @@ -0,0 +1,154 @@ +use std::marker::PhantomData; + +use crate::components::{avatar, icon_button, tool_divider}; +use crate::prelude::{ButtonVariant, Shape, UIState}; +use crate::theme::theme; +use gpui2::style::{StyleHelpers, Styleable}; +use gpui2::{elements::div, IntoElement}; +use gpui2::{Element, ParentElement, ViewContext}; + +#[derive(Element)] +pub struct TitleBar { + view_type: PhantomData, +} + +pub fn title_bar() -> TitleBar { + TitleBar { + view_type: PhantomData, + } +} + +impl TitleBar { + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { + let theme = theme(cx); + + div() + .flex() + .items_center() + .justify_between() + .w_full() + .h_8() + .fill(theme.lowest.base.default.background) + .child( + div() + .flex() + .items_center() + .h_full() + .gap_4() + .px_2() + // === Traffic Lights === // + .child( + div() + .flex() + .items_center() + .gap_2() + .child( + div() + .w_3() + .h_3() + .rounded_full() + .fill(theme.lowest.positive.default.foreground), + ) + .child( + div() + .w_3() + .h_3() + .rounded_full() + .fill(theme.lowest.warning.default.foreground), + ) + .child( + div() + .w_3() + .h_3() + .rounded_full() + .fill(theme.lowest.negative.default.foreground), + ), + ) + // === Project Info === // + .child( + div() + .flex() + .items_center() + .gap_1() + .child( + div() + .h_full() + .flex() + .items_center() + .justify_center() + .px_2() + .rounded_md() + .hover() + .fill(theme.lowest.base.hovered.background) + .active() + .fill(theme.lowest.base.pressed.background) + .child(div().text_sm().child("project")), + ) + .child( + div() + .h_full() + .flex() + .items_center() + .justify_center() + .px_2() + .rounded_md() + .text_color(theme.lowest.variant.default.foreground) + .hover() + .fill(theme.lowest.base.hovered.background) + .active() + .fill(theme.lowest.base.pressed.background) + .child(div().text_sm().child("branch")), + ), + ), + ) + .child( + div() + .flex() + .items_center() + .child( + div() + .px_2() + .flex() + .items_center() + .gap_1() + .child(icon_button( + "icons/stop_sharing.svg", + ButtonVariant::Ghost, + UIState::Default, + )) + .child(icon_button( + "icons/exit.svg", + ButtonVariant::Ghost, + UIState::Default, + )), + ) + .child(tool_divider()) + .child( + div() + .px_2() + .flex() + .items_center() + .gap_1() + .child(icon_button( + "icons/radix/mic.svg", + ButtonVariant::Ghost, + UIState::Default, + )) + .child(icon_button( + "icons/radix/speaker-loud.svg", + ButtonVariant::Ghost, + UIState::Default, + )) + .child(icon_button( + "icons/radix/desktop.svg", + ButtonVariant::Ghost, + UIState::Default, + )), + ) + .child(div().px_2().flex().items_center().child(avatar( + "https://avatars.githubusercontent.com/u/1714999?v=4", + Shape::Squircle, + ))), + ) + } +} diff --git a/crates/storybook/src/prelude.rs b/crates/storybook/src/prelude.rs new file mode 100644 index 0000000000..442567424a --- /dev/null +++ b/crates/storybook/src/prelude.rs @@ -0,0 +1,26 @@ +#[derive(PartialEq)] +pub enum ButtonVariant { + Ghost, + Filled, +} + +#[derive(PartialEq)] +pub enum Shape { + Circle, + Squircle, +} + +#[derive(PartialEq)] +pub enum UIState { + Default, + Hovered, + Active, + Focused, + Disabled, +} + +#[derive(PartialEq)] +pub enum UIToggleState { + Default, + Enabled, +} diff --git a/crates/storybook/src/storybook.rs b/crates/storybook/src/storybook.rs index 1b40bc2dc4..fc7f861e80 100644 --- a/crates/storybook/src/storybook.rs +++ b/crates/storybook/src/storybook.rs @@ -13,6 +13,7 @@ mod collab_panel; mod components; mod element_ext; mod modules; +mod prelude; mod theme; mod workspace; diff --git a/crates/storybook/src/workspace.rs b/crates/storybook/src/workspace.rs index c37b3f16ea..4772552647 100644 --- a/crates/storybook/src/workspace.rs +++ b/crates/storybook/src/workspace.rs @@ -1,4 +1,8 @@ -use crate::{collab_panel::collab_panel, modules::tab_bar, theme::theme}; +use crate::{ + collab_panel::collab_panel, + modules::{chat_panel, tab_bar, title_bar}, + theme::theme, +}; use gpui2::{ elements::{div, div::ScrollState, img, svg}, style::{StyleHelpers, Styleable}, @@ -30,7 +34,7 @@ impl WorkspaceElement { .items_start() .text_color(theme.lowest.base.default.foreground) .fill(theme.middle.base.default.background) - .child(titlebar()) + .child(title_bar()) .child( div() .flex_1() @@ -52,7 +56,7 @@ impl WorkspaceElement { .child(tab_bar(self.tab_bar_scroll_state.clone())), ), ) - .child(collab_panel(self.right_scroll_state.clone())), + .child(chat_panel(self.right_scroll_state.clone())), ) .child(statusbar()) } From bbc4673f178a2adc4759c077b328049aa38380ff Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 12 Sep 2023 15:18:13 -0400 Subject: [PATCH 02/22] Checkpoint --- crates/storybook/src/modules/title_bar.rs | 2 +- crates/storybook/src/prelude.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/storybook/src/modules/title_bar.rs b/crates/storybook/src/modules/title_bar.rs index dfd4e4490e..9e1e0b3533 100644 --- a/crates/storybook/src/modules/title_bar.rs +++ b/crates/storybook/src/modules/title_bar.rs @@ -147,7 +147,7 @@ impl TitleBar { ) .child(div().px_2().flex().items_center().child(avatar( "https://avatars.githubusercontent.com/u/1714999?v=4", - Shape::Squircle, + Shape::RoundedRectangle, ))), ) } diff --git a/crates/storybook/src/prelude.rs b/crates/storybook/src/prelude.rs index 442567424a..c925c64620 100644 --- a/crates/storybook/src/prelude.rs +++ b/crates/storybook/src/prelude.rs @@ -7,7 +7,7 @@ pub enum ButtonVariant { #[derive(PartialEq)] pub enum Shape { Circle, - Squircle, + RoundedRectangle, } #[derive(PartialEq)] From f54f2c52e9c7a3a4e93f22019daac845c55fec55 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 13 Sep 2023 12:40:28 -0400 Subject: [PATCH 03/22] Checkpoint --- .../storybook/src/components/icon_button.rs | 28 +++++++----- crates/storybook/src/modules/chat_panel.rs | 14 ++---- crates/storybook/src/modules/tab_bar.rs | 37 +++++++--------- crates/storybook/src/modules/title_bar.rs | 33 +++----------- crates/storybook/src/prelude.rs | 34 +++++++++++---- docs/ui/states.md | 43 +++++++++++++++++++ 6 files changed, 110 insertions(+), 79 deletions(-) create mode 100644 docs/ui/states.md diff --git a/crates/storybook/src/components/icon_button.rs b/crates/storybook/src/components/icon_button.rs index cecb6ccfc3..32ef1d0ce2 100644 --- a/crates/storybook/src/components/icon_button.rs +++ b/crates/storybook/src/components/icon_button.rs @@ -1,4 +1,4 @@ -use crate::prelude::{ButtonVariant, UIState}; +use crate::prelude::{ButtonVariant, InteractionState}; use crate::theme::theme; use gpui2::elements::svg; use gpui2::style::{StyleHelpers, Styleable}; @@ -6,31 +6,37 @@ use gpui2::{elements::div, IntoElement}; use gpui2::{Element, ParentElement, ViewContext}; #[derive(Element)] -pub(crate) struct IconButton { +pub struct IconButton { path: &'static str, variant: ButtonVariant, - state: UIState, + state: InteractionState, } -pub fn icon_button( - path: &'static str, - variant: ButtonVariant, - state: UIState, -) -> impl Element { +pub fn icon_button(path: &'static str) -> IconButton { IconButton { path, - variant, - state, + variant: ButtonVariant::default(), + state: InteractionState::default(), } } impl IconButton { + pub fn variant(mut self, variant: ButtonVariant) -> Self { + self.variant = variant; + self + } + + pub fn state(mut self, state: InteractionState) -> Self { + self.state = state; + self + } + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { let theme = theme(cx); let icon_color; - if self.state == UIState::Disabled { + if self.state == InteractionState::Disabled { icon_color = theme.highest.base.disabled.foreground; } else { icon_color = theme.highest.base.default.foreground; diff --git a/crates/storybook/src/modules/chat_panel.rs b/crates/storybook/src/modules/chat_panel.rs index 772bb908e0..25bd9debe3 100644 --- a/crates/storybook/src/modules/chat_panel.rs +++ b/crates/storybook/src/modules/chat_panel.rs @@ -1,12 +1,12 @@ use std::marker::PhantomData; use crate::components::icon_button; -use crate::prelude::{ButtonVariant, UIState}; use crate::theme::theme; use gpui2::elements::div::ScrollState; use gpui2::style::StyleHelpers; use gpui2::{elements::div, IntoElement}; use gpui2::{Element, ParentElement, ViewContext}; +use theme::IconButton; #[derive(Element)] pub struct ChatPanel { @@ -58,16 +58,8 @@ impl ChatPanel { .flex() .items_center() .gap_px() - .child(icon_button( - "icons/plus.svg", - ButtonVariant::Ghost, - UIState::Default, - )) - .child(icon_button( - "icons/split.svg", - ButtonVariant::Ghost, - UIState::Default, - )), + .child(icon_button::("icons/plus.svg")) + .child(icon_button::("icons/split.svg")), ), ) } diff --git a/crates/storybook/src/modules/tab_bar.rs b/crates/storybook/src/modules/tab_bar.rs index 5a3358588e..8cc7ab9433 100644 --- a/crates/storybook/src/modules/tab_bar.rs +++ b/crates/storybook/src/modules/tab_bar.rs @@ -1,12 +1,13 @@ use std::marker::PhantomData; use crate::components::{icon_button, tab}; -use crate::prelude::{ButtonVariant, UIState}; +use crate::prelude::InteractionState; use crate::theme::theme; use gpui2::elements::div::ScrollState; use gpui2::style::StyleHelpers; use gpui2::{elements::div, IntoElement}; use gpui2::{Element, ParentElement, ViewContext}; +use theme::IconButton; #[derive(Element)] pub struct TabBar { @@ -24,7 +25,8 @@ pub fn tab_bar(scroll_state: ScrollState) -> TabBar { impl TabBar { fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { let theme = theme(cx); - + let can_navigate_back = true; + let can_navigate_forward = false; div() .w_full() .flex() @@ -41,16 +43,15 @@ impl TabBar { .flex() .items_center() .gap_px() - .child(icon_button( - "icons/arrow_left.svg", - ButtonVariant::Ghost, - UIState::Default, - )) - .child(icon_button( - "icons/arrow_right.svg", - ButtonVariant::Ghost, - UIState::Disabled, - )), + .child( + icon_button::("icons/arrow_left.svg") + .state(InteractionState::Enabled.if_enabled(can_navigate_back)), + ) + .child( + icon_button::("icons/arrow_right.svg").state( + InteractionState::Enabled.if_enabled(can_navigate_forward), + ), + ), ), ) .child( @@ -83,16 +84,8 @@ impl TabBar { .flex() .items_center() .gap_px() - .child(icon_button( - "icons/plus.svg", - ButtonVariant::Ghost, - UIState::Default, - )) - .child(icon_button( - "icons/split.svg", - ButtonVariant::Ghost, - UIState::Default, - )), + .child(icon_button::("icons/plus.svg")) + .child(icon_button::("icons/split.svg")), ), ) } diff --git a/crates/storybook/src/modules/title_bar.rs b/crates/storybook/src/modules/title_bar.rs index 9e1e0b3533..ead95c2009 100644 --- a/crates/storybook/src/modules/title_bar.rs +++ b/crates/storybook/src/modules/title_bar.rs @@ -1,11 +1,12 @@ use std::marker::PhantomData; use crate::components::{avatar, icon_button, tool_divider}; -use crate::prelude::{ButtonVariant, Shape, UIState}; +use crate::prelude::Shape; use crate::theme::theme; use gpui2::style::{StyleHelpers, Styleable}; use gpui2::{elements::div, IntoElement}; use gpui2::{Element, ParentElement, ViewContext}; +use theme::IconButton; #[derive(Element)] pub struct TitleBar { @@ -111,16 +112,8 @@ impl TitleBar { .flex() .items_center() .gap_1() - .child(icon_button( - "icons/stop_sharing.svg", - ButtonVariant::Ghost, - UIState::Default, - )) - .child(icon_button( - "icons/exit.svg", - ButtonVariant::Ghost, - UIState::Default, - )), + .child(icon_button::("icons/stop_sharing.svg")) + .child(icon_button::("icons/exit.svg")), ) .child(tool_divider()) .child( @@ -129,21 +122,9 @@ impl TitleBar { .flex() .items_center() .gap_1() - .child(icon_button( - "icons/radix/mic.svg", - ButtonVariant::Ghost, - UIState::Default, - )) - .child(icon_button( - "icons/radix/speaker-loud.svg", - ButtonVariant::Ghost, - UIState::Default, - )) - .child(icon_button( - "icons/radix/desktop.svg", - ButtonVariant::Ghost, - UIState::Default, - )), + .child(icon_button::("icons/radix/mic.svg")) + .child(icon_button::("icons/radix/speaker-loud.svg")) + .child(icon_button::("icons/radix/desktop.svg")), ) .child(div().px_2().flex().items_center().child(avatar( "https://avatars.githubusercontent.com/u/1714999?v=4", diff --git a/crates/storybook/src/prelude.rs b/crates/storybook/src/prelude.rs index c925c64620..50ab042cfe 100644 --- a/crates/storybook/src/prelude.rs +++ b/crates/storybook/src/prelude.rs @@ -1,26 +1,42 @@ -#[derive(PartialEq)] +#[derive(Default, PartialEq)] pub enum ButtonVariant { + #[default] Ghost, Filled, } -#[derive(PartialEq)] +#[derive(Default, PartialEq)] pub enum Shape { + #[default] Circle, RoundedRectangle, } -#[derive(PartialEq)] -pub enum UIState { - Default, +#[derive(Default, PartialEq, Clone, Copy)] +pub enum InteractionState { + #[default] + Enabled, Hovered, Active, Focused, + Dragged, Disabled, } -#[derive(PartialEq)] -pub enum UIToggleState { - Default, - Enabled, +impl InteractionState { + pub fn if_enabled(&self, enabled: bool) -> Self { + if enabled { + *self + } else { + InteractionState::Disabled + } + } +} + +#[derive(Default, PartialEq)] +pub enum SelectedState { + #[default] + Unselected, + PartiallySelected, + Selected, } diff --git a/docs/ui/states.md b/docs/ui/states.md new file mode 100644 index 0000000000..7dc3110ced --- /dev/null +++ b/docs/ui/states.md @@ -0,0 +1,43 @@ +## Interaction State + +**Enabled** + +An enabled state communicates an interactive component or element. + +**Disabled** + +A disabled state communicates a inoperable component or element. + +**Hover** + +A hover state communicates when a user has placed a cursor above an interactive element. + +**Focused** + +A focused state communicates when a user has highlighted an element, using an input method such as a keyboard or voice. + +**Activated** + +An activated state communicates a highlighted destination, whether initiated by the user or by default. + +**Pressed** + +A pressed state communicates a user tap. + +**Dragged** + +A dragged state communicates when a user presses and moves an element. + +## Selected State + +**Unselected** + +dfa + +**Partially Selected** + +daf + +**Selected** + +dfa From a316e2503435b19b6cc3b5ea3a12b383e5a45d2e Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 13 Sep 2023 12:50:01 -0400 Subject: [PATCH 04/22] Checkpoint --- crates/storybook/src/components.rs | 12 +- crates/storybook/src/components/avatar.rs | 11 +- crates/storybook/src/components/icon_button2 | 123 ++++++++++++++++++ crates/storybook/src/components/tab.rs | 2 +- .../storybook/src/components/tool_divider.rs | 2 +- crates/storybook/src/modules/chat_panel.rs | 3 +- crates/storybook/src/modules/tab_bar.rs | 3 +- crates/storybook/src/modules/title_bar.rs | 13 +- 8 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 crates/storybook/src/components/icon_button2 diff --git a/crates/storybook/src/components.rs b/crates/storybook/src/components.rs index e0ba73b866..36ac1575f5 100644 --- a/crates/storybook/src/components.rs +++ b/crates/storybook/src/components.rs @@ -9,10 +9,14 @@ mod icon_button; mod tab; mod tool_divider; -pub(crate) use avatar::avatar; -pub(crate) use icon_button::icon_button; -pub(crate) use tab::tab; -pub(crate) use tool_divider::tool_divider; +pub use avatar::avatar; +pub use avatar::Avatar; +pub use icon_button::icon_button; +pub use icon_button::IconButton; +pub use tab::tab; +pub use tab::Tab; +pub use tool_divider::tool_divider; +pub use tool_divider::ToolDivider; struct ButtonHandlers { click: Option)>>, diff --git a/crates/storybook/src/components/avatar.rs b/crates/storybook/src/components/avatar.rs index 8eff055d75..6e136977c8 100644 --- a/crates/storybook/src/components/avatar.rs +++ b/crates/storybook/src/components/avatar.rs @@ -8,19 +8,24 @@ use gpui2::{Element, ViewContext}; pub type UnknownString = ArcCow<'static, str>; #[derive(Element)] -pub(crate) struct Avatar { +pub struct Avatar { src: ArcCow<'static, str>, shape: Shape, } -pub fn avatar(src: impl Into>, shape: Shape) -> impl Element { +pub fn avatar(src: impl Into>) -> Avatar { Avatar { src: src.into(), - shape, + shape: Shape::Circle, } } impl Avatar { + pub fn shape(mut self, shape: Shape) -> Self { + self.shape = shape; + self + } + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { let theme = theme(cx); diff --git a/crates/storybook/src/components/icon_button2 b/crates/storybook/src/components/icon_button2 new file mode 100644 index 0000000000..9fe738d5ac --- /dev/null +++ b/crates/storybook/src/components/icon_button2 @@ -0,0 +1,123 @@ +// use crate::prelude::{ButtonVariant, UIState}; +// use crate::theme::theme; +// use gpui2::elements::svg; +// use gpui2::style::{StyleHelpers, Styleable}; +// use gpui2::{elements::div, IntoElement}; +// use gpui2::{Element, ParentElement, ViewContext}; + +// #[derive(Element)] +// pub(crate) struct IconButton { +// path: &'static str, +// variant: ButtonVariant, +// state: UIState, +// } + +// pub fn icon_button(path: &'static str) -> IconButton { +// IconButton { +// path, +// variant: ButtonVariant::Filled, +// state: UIState::Default, +// } +// } + +// impl IconButton { +// fn variant(mut self, variant: ButtonVariant) -> Self { +// self.variant = variant; + +// // Example of more interesting setter behavior +// // FilledButtons must be disabled +// if self.variant == ButtonVariant::Filled { +// self.state = UIState::Disabled; +// } + +// self +// } + +// fn state(mut self, state: UIState) -> Self { +// // Example of more interesting setter behavior: +// // GhostButtons Cannot be disabled +// // Debug asserts are compiled out when we make a new release. +// // Useful for making sure developers develop correctly without breaking +// // everything +// debug_assert!(self.variant != ButtonVariant::Ghost && state != UIState::Disabled); + +// self.state = state; +// self +// } + +// // const state = { +// // foo: "foo", +// // bar: "bar" +// // } as const +// // +// // type State = typeof state[keyof typeof something] +// // +// // type Button { +// // style: State +// // } +// // +// //