Merge branch 'nate/wip-storybook-workspace' into storybook

Nate Butler created

Change summary

crates/storybook/src/storybook.rs |   6 
crates/storybook/src/workspace.rs | 345 +++++++++++++++++++++++++++++++-
2 files changed, 330 insertions(+), 21 deletions(-)

Detailed changes

crates/storybook/src/storybook.rs 🔗

@@ -2,7 +2,6 @@
 
 use crate::theme::Theme;
 use ::theme as legacy_theme;
-use collab_panel::collab_panel;
 use element_ext::ElementExt;
 use gpui2::{serde_json, vec2f, view, Element, RectF, ViewContext, WindowBounds};
 use legacy_theme::ThemeSettings;
@@ -30,7 +29,7 @@ fn main() {
 
         cx.add_window(
             gpui2::WindowOptions {
-                bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(260., 800.))),
+                bounds: WindowBounds::Fixed(RectF::new(vec2f(0., 0.), vec2f(1400., 900.))),
                 center: true,
                 ..Default::default()
             },
@@ -41,7 +40,7 @@ fn main() {
 }
 
 fn storybook<V: 'static>(cx: &mut ViewContext<V>) -> impl Element<V> {
-    collab_panel().themed(current_theme(cx))
+    workspace().themed(current_theme(cx))
 }
 
 // Nathan: During the transition to gpui2, we will include the base theme on the legacy Theme struct.
@@ -64,6 +63,7 @@ fn current_theme<V: 'static>(cx: &mut ViewContext<V>) -> Theme {
 use anyhow::{anyhow, Result};
 use gpui2::AssetSource;
 use rust_embed::RustEmbed;
+use workspace::workspace;
 
 #[derive(RustEmbed)]
 #[folder = "../../assets"]

crates/storybook/src/workspace.rs 🔗

@@ -1,41 +1,350 @@
 use crate::theme::theme;
 use gpui2::{
-    elements::div, geometry::pixels, style::StyleHelpers, Element, IntoElement, ParentElement,
-    ViewContext,
+    elements::{div, svg},
+    geometry::pixels,
+    style::{StyleHelpers, Styleable},
+    Element, IntoElement, ParentElement, ViewContext,
 };
 
 #[derive(Element)]
-struct WorkspaceElement;
+struct TitleBar;
 
-pub fn workspace<V: 'static>() -> impl Element<V> {
-    WorkspaceElement
+pub fn titlebar<V: 'static>() -> impl Element<V> {
+    TitleBar
 }
 
-impl WorkspaceElement {
+impl TitleBar {
     fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
         let theme = theme(cx);
         div()
-            .full()
             .flex()
-            .flex_col()
-            .fill(theme.middle.base.default.background)
-            .child(self.title_bar(cx))
-            .child(self.stage(cx))
-            .child(self.status_bar(cx))
+            .items_center()
+            .justify_between()
+            .w_full()
+            .h_8()
+            .fill(theme.lowest.base.default.background)
+            .child(self.left_group(cx))
+            .child(self.right_group(cx))
     }
 
-    fn title_bar<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+    fn left_group<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
         let theme = theme(cx);
         div()
-            .h(pixels(cx.titlebar_height()))
+            .flex()
+            .items_center()
+            .h_full()
+            .gap_4()
+            .px_2()
+            // === Traffic Lights === //
+            .child(
+                div()
+                    .flex()
+                    .items_center()
+                    .gap_2()
+                    .child(
+                        div()
+                            .w_3()
+                            .h_3()
+                            // .rounded_full()
+                            .fill(theme.lowest.positive.default.foreground),
+                    )
+                    .child(
+                        div()
+                            .w_3()
+                            .h_3()
+                            // .rounded_full()
+                            .fill(theme.lowest.warning.default.foreground),
+                    )
+                    .child(
+                        div()
+                            .w_3()
+                            .h_3()
+                            // .rounded_full()
+                            .fill(theme.lowest.negative.default.foreground),
+                    ),
+            )
+            // === Project Info === //
+            .child(
+                div()
+                    .flex()
+                    .items_center()
+                    .gap_1()
+                    .child(
+                        div()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .px_1()
+                            .hover()
+                            .fill(theme.lowest.base.hovered.background)
+                            .active()
+                            .fill(theme.lowest.base.pressed.background)
+                            .child(div().text_sm().child("project")),
+                    )
+                    .child(
+                        div()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .px_1()
+                            .text_color(theme.lowest.variant.default.foreground)
+                            .hover()
+                            .fill(theme.lowest.base.hovered.background)
+                            .active()
+                            .fill(theme.lowest.base.pressed.background)
+                            .child(div().text_sm().child("branch")),
+                    ),
+            )
+    }
+
+    fn right_group<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+        let theme = theme(cx);
+        div()
+            .flex()
+            .items_center()
+            .h_full()
+            .gap_4()
+            .px_2()
+            // === Comms === //
+            .child(
+                div()
+                    .flex()
+                    .items_center()
+                    .gap_1()
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/microphone.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.base.default.foreground),
+                            ),
+                    )
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/screen.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.base.default.foreground),
+                            ),
+                    )
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/exit.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.base.default.foreground),
+                            ),
+                    ),
+            )
+    }
+}
+
+// ================================================================================ //
+
+#[derive(Element)]
+struct StatusBar;
+
+pub fn statusbar<V: 'static>() -> impl Element<V> {
+    StatusBar
+}
+
+impl StatusBar {
+    fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+        let theme = theme(cx);
+        div()
+            .flex()
+            .items_center()
+            .justify_between()
+            .w_full()
+            .h_8()
             .fill(theme.lowest.base.default.background)
+            .child(self.left_group(cx))
+            .child(self.right_group(cx))
     }
 
-    fn status_bar<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
-        div().h(pixels(cx.titlebar_height())) //.fill(colors.base(0.))
+    fn left_group<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+        let theme = theme(cx);
+        div()
+            .flex()
+            .items_center()
+            .h_full()
+            .gap_4()
+            .px_2()
+            // === Tools === //
+            .child(
+                div()
+                    .flex()
+                    .items_center()
+                    .gap_1()
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/project.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.base.default.foreground),
+                            ),
+                    )
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/conversations.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.base.default.foreground),
+                            ),
+                    )
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/file_icons/notebook.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.accent.default.foreground),
+                            ),
+                    ),
+            )
+            // === Diagnostics === //
+            .child(
+                div().flex().items_center().gap_2()
+                .child(
+                    div()
+                        .h_full()
+                        .flex()
+                        .items_center()
+                        .justify_center()
+                        .gap_0p5()
+                        .px_1()
+                        .text_color(theme.lowest.variant.default.foreground)
+                        .hover()
+                        .fill(theme.lowest.base.hovered.background)
+                        .active()
+                        .fill(theme.lowest.base.pressed.background)
+                        .child(
+                            svg()
+                                .path("icons/error.svg")
+                                .w_4()
+                                .h_4()
+                                .fill(theme.lowest.negative.default.foreground),
+                        )
+                        .child(div().text_sm().child("2")),
+                )
+                .child(div().text_sm().text_color(theme.lowest.variant.default.foreground).child("Something is wrong")),
+
+            )
     }
 
-    fn stage<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
-        div().flex_grow()
+    fn right_group<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+        let theme = theme(cx);
+        div()
+            .flex()
+            .items_center()
+            .h_full()
+            .gap_4()
+            .px_2()
+            // === Tools === //
+            .child(
+                div()
+                    .flex()
+                    .items_center()
+                    .gap_1()
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/check_circle.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.base.default.foreground),
+                            ),
+                    )
+                    .child(
+                        div()
+                            .w_6()
+                            .h_full()
+                            .flex()
+                            .items_center()
+                            .justify_center()
+                            .child(
+                                svg()
+                                    .path("icons/copilot.svg")
+                                    .w_4()
+                                    .h_4()
+                                    .fill(theme.lowest.accent.default.foreground),
+                            ),
+                    ),
+            )
+    }
+}
+
+// ================================================================================ //
+
+#[derive(Element)]
+struct WorkspaceElement;
+
+pub fn workspace<V: 'static>() -> impl Element<V> {
+    WorkspaceElement
+}
+
+impl WorkspaceElement {
+    fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
+        let theme = theme(cx);
+        div()
+            .h_full()
+            .w_full()
+            .flex()
+            .flex_col()
+            .font("Zed Sans Extended")
+            .text_color(theme.lowest.base.default.foreground)
+            .fill(theme.middle.base.default.background)
+            .child(titlebar())
+            .child(div().child("panes"))
+            .child(statusbar())
     }
 }