diff --git a/crates/storybook/src/prelude.rs b/crates/storybook/src/prelude.rs index e53514a5a8..8f01357406 100644 --- a/crates/storybook/src/prelude.rs +++ b/crates/storybook/src/prelude.rs @@ -5,6 +5,13 @@ pub enum ButtonVariant { Filled, } +#[derive(Default, PartialEq)] +pub enum InputVariant { + #[default] + Ghost, + Filled, +} + #[derive(Default, PartialEq, Clone, Copy)] pub enum Shape { #[default] diff --git a/crates/storybook/src/ui.rs b/crates/storybook/src/ui.rs index 9597db2cde..f2b020882d 100644 --- a/crates/storybook/src/ui.rs +++ b/crates/storybook/src/ui.rs @@ -7,6 +7,7 @@ pub use component::follow_group::*; pub use component::tab::*; pub use module::chat_panel::*; +pub use module::project_panel::*; pub use module::status_bar::*; pub use module::tab_bar::*; pub use module::title_bar::*; @@ -14,5 +15,7 @@ pub use module::title_bar::*; pub use element::avatar::*; pub use element::icon_button::*; pub use element::indicator::*; +pub use element::input::*; +pub use element::label::*; pub use element::text_button::*; pub use element::tool_divider::*; diff --git a/crates/storybook/src/ui/element.rs b/crates/storybook/src/ui/element.rs index dde718c40b..145c4d1ecb 100644 --- a/crates/storybook/src/ui/element.rs +++ b/crates/storybook/src/ui/element.rs @@ -1,5 +1,7 @@ pub(crate) mod avatar; pub(crate) mod icon_button; pub(crate) mod indicator; +pub(crate) mod input; +pub(crate) mod label; pub(crate) mod text_button; pub(crate) mod tool_divider; diff --git a/crates/storybook/src/ui/element/input.rs b/crates/storybook/src/ui/element/input.rs new file mode 100644 index 0000000000..310287797c --- /dev/null +++ b/crates/storybook/src/ui/element/input.rs @@ -0,0 +1,99 @@ +use crate::prelude::{InputVariant, InteractionState}; +use crate::theme::theme; +use gpui2::style::{StyleHelpers, Styleable}; +use gpui2::{elements::div, IntoElement}; +use gpui2::{Element, ParentElement, ViewContext}; + +#[derive(Element)] +pub struct Input { + placeholder: &'static str, + value: String, + state: InteractionState, + variant: InputVariant, +} + +pub fn input(placeholder: &'static str) -> Input { + Input { + placeholder, + value: "".to_string(), + state: InteractionState::default(), + variant: InputVariant::default(), + } +} + +impl Input { + pub fn value(mut self, value: String) -> Self { + self.value = value; + self + } + pub fn state(mut self, state: InteractionState) -> Self { + self.state = state; + self + } + pub fn variant(mut self, variant: InputVariant) -> Self { + self.variant = variant; + self + } + + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { + let theme = theme(cx); + + let text_el; + let text_color; + let background_color_default; + let background_color_active; + + let mut border_color_default = theme.middle.base.default.border; + let mut border_color_hover = theme.middle.base.hovered.border; + let mut border_color_active = theme.middle.base.pressed.border; + let border_color_focus = theme.middle.base.pressed.background; + + match self.variant { + InputVariant::Ghost => { + background_color_default = theme.middle.base.default.background; + background_color_active = theme.middle.base.active.background; + } + InputVariant::Filled => { + background_color_default = theme.middle.on.default.background; + background_color_active = theme.middle.on.active.background; + } + }; + + if self.state == InteractionState::Focused { + border_color_default = theme.players[0].cursor; + border_color_hover = theme.players[0].cursor; + border_color_active = theme.players[0].cursor; + } + + if self.state == InteractionState::Focused || self.state == InteractionState::Active { + text_el = self.value.clone(); + text_color = theme.lowest.base.default.foreground; + } else { + text_el = self.placeholder.to_string().clone(); + text_color = theme.lowest.base.disabled.foreground; + } + + div() + .h_7() + .px_2() + .border() + .border_color(border_color_default) + .fill(background_color_default) + .hover() + .border_color(border_color_hover) + .active() + .border_color(border_color_active) + .fill(background_color_active) + .flex() + .items_center() + .child( + div() + .flex() + .items_center() + .text_sm() + .text_color(text_color) + .child(text_el) + .child(div().text_color(theme.players[0].cursor).child("|")), + ) + } +} diff --git a/crates/storybook/src/ui/element/label.rs b/crates/storybook/src/ui/element/label.rs new file mode 100644 index 0000000000..6ebe38b90b --- /dev/null +++ b/crates/storybook/src/ui/element/label.rs @@ -0,0 +1,49 @@ +use crate::theme::theme; +use gpui2::elements::div; +use gpui2::style::StyleHelpers; +use gpui2::{Element, ViewContext}; +use gpui2::{IntoElement, ParentElement}; + +#[derive(Default, PartialEq, Copy, Clone)] +pub enum LabelColor { + #[default] + Default, + Created, + Modified, + Deleted, + Hidden, +} + +#[derive(Element, Clone)] +pub struct Label { + label: &'static str, + color: LabelColor, +} + +pub fn label(label: &'static str) -> Label { + Label { + label: "Label", + color: LabelColor::Default, + } +} + +impl Label { + pub fn color(mut self, color: LabelColor) -> Self { + self.color = color; + self + } + + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { + let theme = theme(cx); + + let color = match self.color { + LabelColor::Default => theme.lowest.base.default.foreground, + LabelColor::Created => theme.lowest.positive.default.foreground, + LabelColor::Modified => theme.lowest.warning.default.foreground, + LabelColor::Deleted => theme.lowest.negative.default.foreground, + LabelColor::Hidden => theme.lowest.variant.default.foreground, + }; + + div().text_sm().text_color(color).child(self.label.clone()) + } +} diff --git a/crates/storybook/src/ui/module.rs b/crates/storybook/src/ui/module.rs index a84bd67165..a261fffcd6 100644 --- a/crates/storybook/src/ui/module.rs +++ b/crates/storybook/src/ui/module.rs @@ -1,4 +1,5 @@ pub(crate) mod chat_panel; +pub(crate) mod project_panel; pub(crate) mod status_bar; pub(crate) mod tab_bar; pub(crate) mod title_bar; diff --git a/crates/storybook/src/ui/module/project_panel.rs b/crates/storybook/src/ui/module/project_panel.rs new file mode 100644 index 0000000000..d954b9e6ce --- /dev/null +++ b/crates/storybook/src/ui/module/project_panel.rs @@ -0,0 +1,65 @@ +use crate::{ + prelude::InteractionState, + theme::theme, + ui::{input, label, LabelColor}, +}; +use gpui2::{ + elements::{div, div::ScrollState}, + style::StyleHelpers, + ParentElement, ViewContext, +}; +use gpui2::{Element, IntoElement}; +use std::marker::PhantomData; + +#[derive(Element)] +pub struct ProjectPanel { + view_type: PhantomData, + scroll_state: ScrollState, +} + +pub fn project_panel(scroll_state: ScrollState) -> ProjectPanel { + ProjectPanel { + view_type: PhantomData, + scroll_state, + } +} + +impl ProjectPanel { + fn render(&mut self, _: &mut V, cx: &mut ViewContext) -> impl IntoElement { + let theme = theme(cx); + + div() + .w_64() + .h_full() + .flex() + .flex_col() + .fill(theme.middle.base.default.background) + .child( + div() + .w_full() + .flex() + .flex_col() + .overflow_y_scroll(self.scroll_state.clone()) + .child( + div().py_2().flex().flex_col().children( + std::iter::repeat_with(|| { + vec![ + label("File"), + label("Modified File").color(LabelColor::Modified), + label("Created File").color(LabelColor::Created), + label("Deleted File").color(LabelColor::Deleted), + label("Hidden File").color(LabelColor::Hidden), + ] + }) + .take(60) + .flatten(), + ), + ), + ) + .child( + input("Find something...") + .value("buffe".to_string()) + .state(InteractionState::Focused), + ) + } +} diff --git a/crates/storybook/src/workspace.rs b/crates/storybook/src/workspace.rs index 5aae506832..3127bcf837 100644 --- a/crates/storybook/src/workspace.rs +++ b/crates/storybook/src/workspace.rs @@ -1,7 +1,6 @@ use crate::{ - collab_panel::collab_panel, theme::theme, - ui::{chat_panel, status_bar, tab_bar, title_bar}, + ui::{chat_panel, project_panel, status_bar, tab_bar, title_bar}, }; use gpui2::{ elements::{div, div::ScrollState}, @@ -42,7 +41,7 @@ impl WorkspaceElement { .flex() .flex_row() .overflow_hidden() - .child(collab_panel(self.left_scroll_state.clone())) + .child(project_panel(self.left_scroll_state.clone())) .child( div() .h_full()