Add ProjectPanel
component
This commit is contained in:
parent
208d5df106
commit
56c2ac048d
10 changed files with 379 additions and 1 deletions
|
@ -1,3 +1,4 @@
|
||||||
pub mod assistant_panel;
|
pub mod assistant_panel;
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
pub mod panel;
|
pub mod panel;
|
||||||
|
pub mod project_panel;
|
||||||
|
|
30
crates/storybook2/src/stories/components/project_panel.rs
Normal file
30
crates/storybook2/src/stories/components/project_panel.rs
Normal file
|
@ -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 avatar;
|
||||||
pub mod icon;
|
pub mod icon;
|
||||||
|
pub mod input;
|
||||||
pub mod label;
|
pub mod label;
|
||||||
|
|
26
crates/storybook2/src/stories/elements/input.rs
Normal file
26
crates/storybook2/src/stories/elements/input.rs
Normal file
|
@ -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 {
|
pub enum ElementStory {
|
||||||
Avatar,
|
Avatar,
|
||||||
Icon,
|
Icon,
|
||||||
|
Input,
|
||||||
Label,
|
Label,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ impl ElementStory {
|
||||||
match self {
|
match self {
|
||||||
Self::Avatar => elements::avatar::AvatarStory::new().into_any(),
|
Self::Avatar => elements::avatar::AvatarStory::new().into_any(),
|
||||||
Self::Icon => elements::icon::IconStory::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(),
|
Self::Label => elements::label::LabelStory::new().into_any(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +37,7 @@ pub enum ComponentStory {
|
||||||
AssistantPanel,
|
AssistantPanel,
|
||||||
Buffer,
|
Buffer,
|
||||||
Panel,
|
Panel,
|
||||||
|
ProjectPanel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentStory {
|
impl ComponentStory {
|
||||||
|
@ -47,6 +50,7 @@ impl ComponentStory {
|
||||||
}
|
}
|
||||||
Self::Buffer => components::buffer::BufferStory::new().into_any(),
|
Self::Buffer => components::buffer::BufferStory::new().into_any(),
|
||||||
Self::Panel => components::panel::PanelStory::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 icon_button;
|
||||||
mod list;
|
mod list;
|
||||||
mod panel;
|
mod panel;
|
||||||
|
mod project_panel;
|
||||||
|
|
||||||
pub use assistant_panel::*;
|
pub use assistant_panel::*;
|
||||||
pub use buffer::*;
|
pub use buffer::*;
|
||||||
pub use icon_button::*;
|
pub use icon_button::*;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
pub use panel::*;
|
pub use panel::*;
|
||||||
|
pub use project_panel::*;
|
||||||
|
|
58
crates/ui2/src/components/project_panel.rs
Normal file
58
crates/ui2/src/components/project_panel.rs
Normal file
|
@ -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 avatar;
|
||||||
mod button;
|
mod button;
|
||||||
mod icon;
|
mod icon;
|
||||||
|
mod input;
|
||||||
mod label;
|
mod label;
|
||||||
mod stack;
|
mod stack;
|
||||||
|
|
||||||
pub use avatar::*;
|
pub use avatar::*;
|
||||||
pub use button::*;
|
pub use button::*;
|
||||||
pub use icon::*;
|
pub use icon::*;
|
||||||
|
pub use input::*;
|
||||||
pub use label::*;
|
pub use label::*;
|
||||||
pub use stack::*;
|
pub use stack::*;
|
||||||
|
|
110
crates/ui2/src/elements/input.rs
Normal file
110
crates/ui2/src/elements/input.rs
Normal file
|
@ -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::{
|
use crate::{
|
||||||
Buffer, BufferRow, BufferRows, GitStatus, HighlightColor, HighlightedLine, HighlightedText,
|
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> {
|
pub fn empty_buffer_example<S: 'static + Send + Sync + Clone>() -> Buffer<S> {
|
||||||
Buffer::new().set_rows(Some(BufferRows::default()))
|
Buffer::new().set_rows(Some(BufferRows::default()))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue