init `tab_bar`

Nate Butler created

Change summary

crates/storybook/src/component/icon_button.rs | 20 +--
crates/storybook/src/component/mod.rs         |  1 
crates/storybook/src/component/tab.rs         | 56 +++++++++++++
crates/storybook/src/module/mod.rs            |  1 
crates/storybook/src/module/tab_bar.rs        | 89 +++++++++++++++++++++
crates/storybook/src/storybook.rs             |  1 
crates/storybook/src/workspace.rs             | 30 +++---
7 files changed, 171 insertions(+), 27 deletions(-)

Detailed changes

crates/storybook/src/component/icon_button.rs 🔗

@@ -7,16 +7,16 @@ use gpui2::{Element, ParentElement, ViewContext};
 #[derive(Element)]
 struct IconButton {
     path: &'static str,
-    variant: Variant,
+    variant: ButtonVariant,
 }
 
 #[derive(PartialEq)]
-pub enum Variant {
+pub enum ButtonVariant {
     Ghost,
     Filled,
 }
 
-pub fn icon_button<V: 'static>(path: &'static str, variant: Variant) -> impl Element<V> {
+pub fn icon_button<V: 'static>(path: &'static str, variant: ButtonVariant) -> impl Element<V> {
     IconButton { path, variant }
 }
 
@@ -25,8 +25,8 @@ impl IconButton {
         let theme = theme(cx);
         let mut div = div();
 
-        if self.variant == Variant::Filled {
-            div = div.fill(theme.middle.base.default.background);
+        if self.variant == ButtonVariant::Filled {
+            div = div.fill(theme.highest.base.default.background);
         }
 
         div.w_7()
@@ -35,20 +35,16 @@ impl IconButton {
             .items_center()
             .justify_center()
             .rounded_md()
-            .border()
-            .border_color(theme.middle.base.default.background)
             .hover()
-            .fill(theme.middle.base.hovered.background)
-            .border_color(theme.middle.variant.hovered.border)
+            .fill(theme.highest.base.hovered.background)
             .active()
-            .fill(theme.middle.base.pressed.background)
-            .border_color(theme.middle.variant.pressed.border)
+            .fill(theme.highest.base.pressed.background)
             .child(
                 svg()
                     .path(self.path)
                     .w_4()
                     .h_4()
-                    .fill(theme.middle.variant.default.foreground),
+                    .fill(theme.highest.variant.default.foreground),
             )
     }
 }

crates/storybook/src/component/tab.rs 🔗

@@ -0,0 +1,56 @@
+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)]
+struct Tab {
+    title: &'static str,
+    active: bool,
+}
+
+pub fn tab<V: 'static>(title: &'static str, active: bool) -> impl Element<V> {
+    Tab { title, active }
+}
+
+impl Tab {
+    fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+        let theme = theme(cx);
+
+        div()
+            .px_2()
+            .py_0p5()
+            .flex()
+            .items_center()
+            .justify_center()
+            .rounded_lg()
+            .fill(if self.active {
+                theme.highest.on.default.background
+            } else {
+                theme.highest.base.default.background
+            })
+            .hover()
+            .fill(if self.active {
+                theme.highest.on.hovered.background
+            } else {
+                theme.highest.base.hovered.background
+            })
+            .active()
+            .fill(if self.active {
+                theme.highest.on.pressed.background
+            } else {
+                theme.highest.base.pressed.background
+            })
+            .child(
+                div()
+                    .text_sm()
+                    .text_color(if self.active {
+                        theme.highest.base.default.foreground
+                    } else {
+                        theme.highest.variant.default.foreground
+                    })
+                    .child(self.title),
+            )
+    }
+}

crates/storybook/src/module/tab_bar.rs 🔗

@@ -0,0 +1,89 @@
+use std::marker::PhantomData;
+
+use crate::component::icon_button::{icon_button, ButtonVariant};
+use crate::component::tab::tab;
+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 TabBar<V: 'static> {
+    view_type: PhantomData<V>,
+    scroll_state: ScrollState,
+}
+
+pub fn tab_bar<V: 'static>(scroll_state: ScrollState) -> TabBar<V> {
+    TabBar {
+        view_type: PhantomData,
+        scroll_state,
+    }
+}
+
+impl<V: 'static> TabBar<V> {
+    fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+        let theme = theme(cx);
+
+        div()
+            .w_full()
+            .flex()
+            .items_center()
+            .fill(theme.highest.base.default.background)
+            // Left Side
+            .child(
+                div()
+                    .px_1()
+                    .flex()
+                    // Nate
+                    // This isn't what I wanted, but I wanted to try to get at least SOME x overflow scroll working
+                    // Ideally this should be on the "Tabs" div below
+                    // So only the tabs scroll, and the nav buttons stay pinned left, and the other controls stay pinned right
+                    .overflow_x_scroll(self.scroll_state.clone())
+                    .gap_2()
+                    // Nav Buttons
+                    .child(
+                        div()
+                            .flex()
+                            .items_center()
+                            .gap_px()
+                            .child(icon_button("icons/arrow_left.svg", ButtonVariant::Ghost))
+                            .child(icon_button("icons/arrow_right.svg", ButtonVariant::Ghost)),
+                    )
+                    // Tabs
+                    .child(
+                        div()
+                            .py_1()
+                            .flex()
+                            .items_center()
+                            .gap_px()
+                            .child(tab("Cargo.toml", false))
+                            .child(tab("Channels Panel", true))
+                            .child(tab("channels_panel.rs", false))
+                            .child(tab("workspace.rs", false))
+                            .child(tab("icon_button.rs", false))
+                            .child(tab("storybook.rs", false))
+                            .child(tab("theme.rs", false))
+                            .child(tab("theme_registry.rs", false))
+                            .child(tab("styleable_helpers.rs", false)),
+                    ),
+            )
+            // Right Side
+            .child(
+                div()
+                    .px_1()
+                    .flex()
+                    .flex_initial()
+                    .gap_2()
+                    // Nav Buttons
+                    .child(
+                        div()
+                            .flex()
+                            .items_center()
+                            .gap_px()
+                            .child(icon_button("icons/plus.svg", ButtonVariant::Ghost))
+                            .child(icon_button("icons/split.svg", ButtonVariant::Ghost)),
+                    ),
+            )
+    }
+}

crates/storybook/src/workspace.rs 🔗

@@ -1,8 +1,4 @@
-use crate::{
-    collab_panel::collab_panel,
-    component::icon_button::{icon_button, Variant},
-    theme::theme,
-};
+use crate::{collab_panel::collab_panel, module::tab_bar::tab_bar, theme::theme};
 use gpui2::{
     elements::{div, div::ScrollState, img, svg},
     style::{StyleHelpers, Styleable},
@@ -13,6 +9,7 @@ use gpui2::{
 struct WorkspaceElement {
     left_scroll_state: ScrollState,
     right_scroll_state: ScrollState,
+    tab_bar_scroll_state: ScrollState,
 }
 
 pub fn workspace<V: 'static>() -> impl Element<V> {
@@ -41,17 +38,20 @@ impl WorkspaceElement {
                     .flex()
                     .flex_row()
                     .overflow_hidden()
-                    .child(collab_panel(self.left_scroll_state.clone()))
+                    // .child(collab_panel(self.left_scroll_state.clone()))
                     .child(
-                        div().h_full().flex_1().child(
-                            div()
-                                .w_24()
-                                .h_24()
-                                .child(icon_button("icons/plus.svg", Variant::Ghost))
-                                .child(icon_button("icons/x.svg", Variant::Filled)),
-                        ),
-                    )
-                    .child(collab_panel(self.right_scroll_state.clone())),
+                        div()
+                            .h_full()
+                            .flex_1()
+                            .fill(theme.highest.base.default.background)
+                            .child(
+                                div()
+                                    .flex()
+                                    .flex_col()
+                                    .flex_1()
+                                    .child(tab_bar(self.tab_bar_scroll_state.clone())),
+                            ),
+                    ), // .child(collab_panel(self.right_scroll_state.clone())),
             )
             .child(statusbar())
     }