crates/storybook2/src/stories/components.rs 🔗
@@ -3,5 +3,6 @@ pub mod buffer;
pub mod panel;
pub mod project_panel;
pub mod tab;
+pub mod tab_bar;
pub mod terminal;
pub mod workspace;
Marshall Bowers created
crates/storybook2/src/stories/components.rs | 1
crates/storybook2/src/stories/components/tab_bar.rs | 56 +++++++++
crates/storybook2/src/story_selector.rs | 2
crates/ui2/src/components.rs | 2
crates/ui2/src/components/tab_bar.rs | 85 +++++++++++++++
5 files changed, 146 insertions(+)
@@ -3,5 +3,6 @@ pub mod buffer;
pub mod panel;
pub mod project_panel;
pub mod tab;
+pub mod tab_bar;
pub mod terminal;
pub mod workspace;
@@ -0,0 +1,56 @@
+use std::marker::PhantomData;
+
+use ui::prelude::*;
+use ui::{Tab, TabBar};
+
+use crate::story::Story;
+
+#[derive(Element)]
+pub struct TabBarStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+}
+
+impl<S: 'static + Send + Sync + Clone> TabBarStory<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::<_, TabBar<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(TabBar::new(vec![
+ Tab::new()
+ .title("Cargo.toml".to_string())
+ .current(false)
+ .git_status(GitStatus::Modified),
+ Tab::new()
+ .title("Channels Panel".to_string())
+ .current(false),
+ Tab::new()
+ .title("channels_panel.rs".to_string())
+ .current(true)
+ .git_status(GitStatus::Modified),
+ Tab::new()
+ .title("workspace.rs".to_string())
+ .current(false)
+ .git_status(GitStatus::Modified),
+ Tab::new()
+ .title("icon_button.rs".to_string())
+ .current(false),
+ Tab::new()
+ .title("storybook.rs".to_string())
+ .current(false)
+ .git_status(GitStatus::Created),
+ Tab::new().title("theme.rs".to_string()).current(false),
+ Tab::new()
+ .title("theme_registry.rs".to_string())
+ .current(false),
+ Tab::new()
+ .title("styleable_helpers.rs".to_string())
+ .current(false),
+ ]))
+ }
+}
@@ -39,6 +39,7 @@ pub enum ComponentStory {
Panel,
ProjectPanel,
Tab,
+ TabBar,
Terminal,
Workspace,
}
@@ -55,6 +56,7 @@ impl ComponentStory {
Self::Panel => components::panel::PanelStory::new().into_any(),
Self::ProjectPanel => components::project_panel::ProjectPanelStory::new().into_any(),
Self::Tab => components::tab::TabStory::new().into_any(),
+ Self::TabBar => components::tab_bar::TabBarStory::new().into_any(),
Self::Terminal => components::terminal::TerminalStory::new().into_any(),
Self::Workspace => components::workspace::WorkspaceStory::new().into_any(),
}
@@ -7,6 +7,7 @@ mod panes;
mod project_panel;
mod status_bar;
mod tab;
+mod tab_bar;
mod terminal;
mod workspace;
@@ -19,5 +20,6 @@ pub use panes::*;
pub use project_panel::*;
pub use status_bar::*;
pub use tab::*;
+pub use tab_bar::*;
pub use terminal::*;
pub use workspace::*;
@@ -0,0 +1,85 @@
+use std::marker::PhantomData;
+
+use crate::prelude::*;
+use crate::{theme, Icon, IconButton, Tab};
+
+#[derive(Element)]
+pub struct TabBar<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ scroll_state: ScrollState,
+ tabs: Vec<Tab<S>>,
+}
+
+impl<S: 'static + Send + Sync + Clone> TabBar<S> {
+ pub fn new(tabs: Vec<Tab<S>>) -> Self {
+ Self {
+ state_type: PhantomData,
+ scroll_state: ScrollState::default(),
+ tabs,
+ }
+ }
+
+ pub fn bind_scroll_state(&mut self, scroll_state: ScrollState) {
+ self.scroll_state = scroll_state;
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let theme = theme(cx);
+ let can_navigate_back = true;
+ let can_navigate_forward = false;
+
+ div()
+ .w_full()
+ .flex()
+ .fill(theme.middle.base.default.background)
+ // Left Side
+ .child(
+ div()
+ .px_1()
+ .flex()
+ .flex_none()
+ .gap_2()
+ // Nav Buttons
+ .child(
+ div()
+ .flex()
+ .items_center()
+ .gap_px()
+ .child(
+ IconButton::new(Icon::ArrowLeft)
+ .state(InteractionState::Enabled.if_enabled(can_navigate_back)),
+ )
+ .child(
+ IconButton::new(Icon::ArrowRight).state(
+ InteractionState::Enabled.if_enabled(can_navigate_forward),
+ ),
+ ),
+ ),
+ )
+ .child(
+ div().w_0().flex_1().h_full().child(
+ div()
+ .flex()
+ .overflow_x_scroll(self.scroll_state.clone())
+ .children(self.tabs.clone()),
+ ),
+ )
+ // Right Side
+ .child(
+ div()
+ .px_1()
+ .flex()
+ .flex_none()
+ .gap_2()
+ // Nav Buttons
+ .child(
+ div()
+ .flex()
+ .items_center()
+ .gap_px()
+ .child(IconButton::new(Icon::Plus))
+ .child(IconButton::new(Icon::Split)),
+ ),
+ )
+ }
+}