crates/storybook2/src/stories/components.rs 🔗
@@ -1,3 +1,4 @@
pub mod assistant_panel;
pub mod buffer;
pub mod panel;
+pub mod project_panel;
Marshall Bowers created
crates/storybook2/src/stories/components.rs | 1
crates/storybook2/src/stories/components/project_panel.rs | 30 +
crates/storybook2/src/stories/elements.rs | 1
crates/storybook2/src/stories/elements/input.rs | 26 +
crates/storybook2/src/story_selector.rs | 4
crates/ui2/src/components.rs | 2
crates/ui2/src/components/project_panel.rs | 58 +++
crates/ui2/src/elements.rs | 2
crates/ui2/src/elements/input.rs | 110 ++++++
crates/ui2/src/static_data.rs | 146 ++++++++
10 files changed, 379 insertions(+), 1 deletion(-)
@@ -1,3 +1,4 @@
pub mod assistant_panel;
pub mod buffer;
pub mod panel;
+pub mod project_panel;
@@ -0,0 +1,30 @@
+use std::marker::PhantomData;
+
+use ui::prelude::*;
+use ui::{Panel, ProjectPanel};
+
+use crate::story::Story;
+
+#[derive(Element)]
+pub struct ProjectPanelStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+}
+
+impl<S: 'static + Send + Sync + Clone> ProjectPanelStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ Story::container(cx)
+ .child(Story::title_for::<_, ProjectPanel<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Panel::new(
+ ScrollState::default(),
+ |_, _| vec![ProjectPanel::new(ScrollState::default()).into_any()],
+ Box::new(()),
+ ))
+ }
+}
@@ -1,3 +1,4 @@
pub mod avatar;
pub mod icon;
+pub mod input;
pub mod label;
@@ -0,0 +1,26 @@
+use std::marker::PhantomData;
+
+use ui::prelude::*;
+use ui::Input;
+
+use crate::story::Story;
+
+#[derive(Element)]
+pub struct InputStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+}
+
+impl<S: 'static + Send + Sync + Clone> InputStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ Story::container(cx)
+ .child(Story::title_for::<_, Input<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(div().flex().child(Input::new("Search")))
+ }
+}
@@ -14,6 +14,7 @@ use ui::prelude::*;
pub enum ElementStory {
Avatar,
Icon,
+ Input,
Label,
}
@@ -24,6 +25,7 @@ impl ElementStory {
match self {
Self::Avatar => elements::avatar::AvatarStory::new().into_any(),
Self::Icon => elements::icon::IconStory::new().into_any(),
+ Self::Input => elements::input::InputStory::new().into_any(),
Self::Label => elements::label::LabelStory::new().into_any(),
}
}
@@ -35,6 +37,7 @@ pub enum ComponentStory {
AssistantPanel,
Buffer,
Panel,
+ ProjectPanel,
}
impl ComponentStory {
@@ -47,6 +50,7 @@ impl ComponentStory {
}
Self::Buffer => components::buffer::BufferStory::new().into_any(),
Self::Panel => components::panel::PanelStory::new().into_any(),
+ Self::ProjectPanel => components::project_panel::ProjectPanelStory::new().into_any(),
}
}
}
@@ -3,9 +3,11 @@ mod buffer;
mod icon_button;
mod list;
mod panel;
+mod project_panel;
pub use assistant_panel::*;
pub use buffer::*;
pub use icon_button::*;
pub use list::*;
pub use panel::*;
+pub use project_panel::*;
@@ -0,0 +1,58 @@
+use std::marker::PhantomData;
+
+use crate::prelude::*;
+use crate::{
+ static_project_panel_project_items, static_project_panel_single_items, theme, Input, List,
+ ListHeader,
+};
+
+#[derive(Element)]
+pub struct ProjectPanel<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ scroll_state: ScrollState,
+}
+
+impl<S: 'static + Send + Sync + Clone> ProjectPanel<S> {
+ pub fn new(scroll_state: ScrollState) -> Self {
+ Self {
+ state_type: PhantomData,
+ scroll_state,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let theme = theme(cx);
+
+ div()
+ .flex()
+ .flex_col()
+ .w_full()
+ .h_full()
+ .px_2()
+ .fill(theme.middle.base.default.background)
+ .child(
+ div()
+ .w_56()
+ .flex()
+ .flex_col()
+ .overflow_y_scroll(ScrollState::default())
+ .child(
+ List::new(static_project_panel_single_items())
+ .header(ListHeader::new("FILES").set_toggle(ToggleState::Toggled))
+ .empty_message("No files in directory")
+ .set_toggle(ToggleState::Toggled),
+ )
+ .child(
+ List::new(static_project_panel_project_items())
+ .header(ListHeader::new("PROJECT").set_toggle(ToggleState::Toggled))
+ .empty_message("No folders in directory")
+ .set_toggle(ToggleState::Toggled),
+ ),
+ )
+ .child(
+ Input::new("Find something...")
+ .value("buffe".to_string())
+ .state(InteractionState::Focused),
+ )
+ }
+}
@@ -1,11 +1,13 @@
mod avatar;
mod button;
mod icon;
+mod input;
mod label;
mod stack;
pub use avatar::*;
pub use button::*;
pub use icon::*;
+pub use input::*;
pub use label::*;
pub use stack::*;
@@ -0,0 +1,110 @@
+use std::marker::PhantomData;
+
+use crate::prelude::*;
+use crate::theme;
+
+#[derive(Default, PartialEq)]
+pub enum InputVariant {
+ #[default]
+ Ghost,
+ Filled,
+}
+
+#[derive(Element)]
+pub struct Input<S: 'static + Send + Sync> {
+ state_type: PhantomData<S>,
+ placeholder: &'static str,
+ value: String,
+ state: InteractionState,
+ variant: InputVariant,
+}
+
+impl<S: 'static + Send + Sync> Input<S> {
+ pub fn new(placeholder: &'static str) -> Self {
+ Self {
+ state_type: PhantomData,
+ placeholder,
+ value: "".to_string(),
+ state: InteractionState::default(),
+ variant: InputVariant::default(),
+ }
+ }
+
+ 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, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ 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()
+ .w_full()
+ .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("|")),
+ )
+ }
+}
@@ -1,8 +1,152 @@
use crate::{
Buffer, BufferRow, BufferRows, GitStatus, HighlightColor, HighlightedLine, HighlightedText,
- Theme,
+ Icon, Label, LabelColor, ListEntry, ListItem, Theme, ToggleState,
};
+pub fn static_project_panel_project_items<S: 'static + Send + Sync + Clone>() -> Vec<ListItem<S>> {
+ vec![
+ ListEntry::new(Label::new("zed"))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(0)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new(".cargo"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1),
+ ListEntry::new(Label::new(".config"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1),
+ ListEntry::new(Label::new(".git").color(LabelColor::Hidden))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1),
+ ListEntry::new(Label::new(".cargo"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1),
+ ListEntry::new(Label::new(".idea").color(LabelColor::Hidden))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1),
+ ListEntry::new(Label::new("assets"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("cargo-target").color(LabelColor::Hidden))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1),
+ ListEntry::new(Label::new("crates"))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(1)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("activity_indicator"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2),
+ ListEntry::new(Label::new("ai"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2),
+ ListEntry::new(Label::new("audio"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2),
+ ListEntry::new(Label::new("auto_update"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2),
+ ListEntry::new(Label::new("breadcrumbs"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2),
+ ListEntry::new(Label::new("call"))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2),
+ ListEntry::new(Label::new("sqlez").color(LabelColor::Modified))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2)
+ .set_toggle(ToggleState::NotToggled),
+ ListEntry::new(Label::new("gpui2"))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(2)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("src"))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(3)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("derive_element.rs"))
+ .left_icon(Icon::FileRust.into())
+ .indent_level(4),
+ ListEntry::new(Label::new("storybook").color(LabelColor::Modified))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(1)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("docs").color(LabelColor::Default))
+ .left_icon(Icon::Folder.into())
+ .indent_level(2)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("src").color(LabelColor::Modified))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(3)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("ui").color(LabelColor::Modified))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(4)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("component").color(LabelColor::Created))
+ .left_icon(Icon::FolderOpen.into())
+ .indent_level(5)
+ .set_toggle(ToggleState::Toggled),
+ ListEntry::new(Label::new("facepile.rs").color(LabelColor::Default))
+ .left_icon(Icon::FileRust.into())
+ .indent_level(6),
+ ListEntry::new(Label::new("follow_group.rs").color(LabelColor::Default))
+ .left_icon(Icon::FileRust.into())
+ .indent_level(6),
+ ListEntry::new(Label::new("list_item.rs").color(LabelColor::Created))
+ .left_icon(Icon::FileRust.into())
+ .indent_level(6),
+ ListEntry::new(Label::new("tab.rs").color(LabelColor::Default))
+ .left_icon(Icon::FileRust.into())
+ .indent_level(6),
+ ListEntry::new(Label::new("target").color(LabelColor::Hidden))
+ .left_icon(Icon::Folder.into())
+ .indent_level(1),
+ ListEntry::new(Label::new(".dockerignore"))
+ .left_icon(Icon::FileGeneric.into())
+ .indent_level(1),
+ ListEntry::new(Label::new(".DS_Store").color(LabelColor::Hidden))
+ .left_icon(Icon::FileGeneric.into())
+ .indent_level(1),
+ ListEntry::new(Label::new("Cargo.lock"))
+ .left_icon(Icon::FileLock.into())
+ .indent_level(1),
+ ListEntry::new(Label::new("Cargo.toml"))
+ .left_icon(Icon::FileToml.into())
+ .indent_level(1),
+ ListEntry::new(Label::new("Dockerfile"))
+ .left_icon(Icon::FileGeneric.into())
+ .indent_level(1),
+ ListEntry::new(Label::new("Procfile"))
+ .left_icon(Icon::FileGeneric.into())
+ .indent_level(1),
+ ListEntry::new(Label::new("README.md"))
+ .left_icon(Icon::FileDoc.into())
+ .indent_level(1),
+ ]
+ .into_iter()
+ .map(From::from)
+ .collect()
+}
+
+pub fn static_project_panel_single_items<S: 'static + Send + Sync + Clone>() -> Vec<ListItem<S>> {
+ vec![
+ ListEntry::new(Label::new("todo.md"))
+ .left_icon(Icon::FileDoc.into())
+ .indent_level(0),
+ ListEntry::new(Label::new("README.md"))
+ .left_icon(Icon::FileDoc.into())
+ .indent_level(0),
+ ListEntry::new(Label::new("config.json"))
+ .left_icon(Icon::FileGeneric.into())
+ .indent_level(0),
+ ]
+ .into_iter()
+ .map(From::from)
+ .collect()
+}
+
pub fn empty_buffer_example<S: 'static + Send + Sync + Clone>() -> Buffer<S> {
Buffer::new().set_rows(Some(BufferRows::default()))
}