Extract `Story` into separate `story` crate (#3378)

Marshall Bowers and Nate Butler created

This PR extracts the `Story` component into a separate `story` crate so
that it can be shared among various crates that define stories.

Release Notes:

- N/A

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>

Change summary

Cargo.lock                                        |   9 +
Cargo.toml                                        |   1 
crates/story/Cargo.toml                           |  10 +
crates/story/src/lib.rs                           |   3 
crates/story/src/story.rs                         |  35 ++++
crates/storybook2/Cargo.toml                      |   1 
crates/storybook2/src/stories/colors.rs           |  44 -----
crates/theme2/Cargo.toml                          |   5 
crates/theme2/src/story.rs                        |  38 ----
crates/theme2/src/styles.rs                       |   6 
crates/theme2/src/styles/players.rs               | 140 ----------------
crates/theme2/src/styles/stories/color.rs         |  41 ++++
crates/theme2/src/styles/stories/mod.rs           |   5 
crates/theme2/src/styles/stories/players.rs       | 137 ++++++++++++++++
crates/theme2/src/theme2.rs                       |   5 
crates/ui2/Cargo.toml                             |   3 
crates/ui2/src/components/stories/avatar.rs       |   9 
crates/ui2/src/components/stories/button.rs       |  27 +-
crates/ui2/src/components/stories/checkbox.rs     |  11 
crates/ui2/src/components/stories/context_menu.rs |   5 
crates/ui2/src/components/stories/icon.rs         |   9 
crates/ui2/src/components/stories/input.rs        |   9 
crates/ui2/src/components/stories/keybinding.rs   |  19 +-
crates/ui2/src/components/stories/label.rs        |  11 
crates/ui2/src/story.rs                           |  37 ----
crates/ui2/src/ui2.rs                             |   5 
26 files changed, 309 insertions(+), 316 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -8859,6 +8859,13 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
+[[package]]
+name = "story"
+version = "0.1.0"
+dependencies = [
+ "gpui2",
+]
+
 [[package]]
 name = "stringprep"
 version = "0.1.4"
@@ -9362,6 +9369,7 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "settings2",
+ "story",
  "toml 0.5.11",
  "util",
  "uuid 1.4.1",
@@ -10205,6 +10213,7 @@ dependencies = [
  "serde",
  "settings2",
  "smallvec",
+ "story",
  "strum",
  "theme2",
 ]

Cargo.toml 🔗

@@ -111,6 +111,7 @@ members = [
     "crates/ui2",
     "crates/util",
     "crates/semantic_index",
+    "crates/story",
     "crates/vim",
     "crates/vcs_menu",
     "crates/workspace2",

crates/story/Cargo.toml 🔗

@@ -0,0 +1,10 @@
+[package]
+name = "story"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+gpui = { package = "gpui2", path = "../gpui2" }

crates/story/src/story.rs 🔗

@@ -0,0 +1,35 @@
+use gpui::prelude::*;
+use gpui::{div, hsla, Div, SharedString};
+
+pub struct Story {}
+
+impl Story {
+    pub fn container() -> Div {
+        div().size_full().flex().flex_col().pt_2().px_4().bg(hsla(
+            0. / 360.,
+            0. / 100.,
+            100. / 100.,
+            1.,
+        ))
+    }
+
+    pub fn title(title: impl Into<SharedString>) -> impl Element {
+        div()
+            .text_xl()
+            .text_color(hsla(0. / 360., 0. / 100., 0. / 100., 1.))
+            .child(title.into())
+    }
+
+    pub fn title_for<T>() -> impl Element {
+        Self::title(std::any::type_name::<T>())
+    }
+
+    pub fn label(label: impl Into<SharedString>) -> impl Element {
+        div()
+            .mt_4()
+            .mb_2()
+            .text_xs()
+            .text_color(hsla(0. / 360., 0. / 100., 0. / 100., 1.))
+            .child(label.into())
+    }
+}

crates/storybook2/Cargo.toml 🔗

@@ -25,6 +25,7 @@ serde.workspace = true
 settings2 = { path = "../settings2" }
 simplelog = "0.9"
 smallvec.workspace = true
+story = { path = "../story" }
 strum = { version = "0.25.0", features = ["derive"] }
 theme = { path = "../theme" }
 theme2 = { path = "../theme2" }

crates/storybook2/src/stories/colors.rs 🔗

@@ -1,44 +0,0 @@
-use crate::story::Story;
-use gpui::{prelude::*, px, Div, Render};
-use theme2::{default_color_scales, ColorScaleStep};
-use ui::prelude::*;
-
-pub struct ColorsStory;
-
-impl Render for ColorsStory {
-    type Element = Div;
-
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        let color_scales = default_color_scales();
-
-        Story::container(cx)
-            .child(Story::title(cx, "Colors"))
-            .child(
-                div()
-                    .id("colors")
-                    .flex()
-                    .flex_col()
-                    .gap_1()
-                    .overflow_y_scroll()
-                    .text_color(gpui::white())
-                    .children(color_scales.into_iter().map(|scale| {
-                        div()
-                            .flex()
-                            .child(
-                                div()
-                                    .w(px(75.))
-                                    .line_height(px(24.))
-                                    .child(scale.name().clone()),
-                            )
-                            .child(
-                                div()
-                                    .flex()
-                                    .gap_1()
-                                    .children(ColorScaleStep::ALL.map(|step| {
-                                        div().flex().size_6().bg(scale.step(cx, step))
-                                    })),
-                            )
-                    })),
-            )
-    }
-}

crates/theme2/Cargo.toml 🔗

@@ -5,9 +5,9 @@ edition = "2021"
 publish = false
 
 [features]
-default = ["stories"]
+default = []
 importing-themes = []
-stories = ["dep:itertools"]
+stories = ["dep:itertools", "dep:story"]
 test-support = [
     "gpui/test-support",
     "fs/test-support",
@@ -30,6 +30,7 @@ serde.workspace = true
 serde_derive.workspace = true
 serde_json.workspace = true
 settings = { package = "settings2", path = "../settings2" }
+story = { path = "../story", optional = true }
 toml.workspace = true
 uuid.workspace = true
 util = { path = "../util" }

crates/theme2/src/story.rs 🔗

@@ -1,38 +0,0 @@
-use gpui::{div, Div, Element, ParentElement, SharedString, Styled, WindowContext};
-
-use crate::ActiveTheme;
-
-pub struct Story {}
-
-impl Story {
-    pub fn container(cx: &mut WindowContext) -> Div {
-        div()
-            .size_full()
-            .flex()
-            .flex_col()
-            .pt_2()
-            .px_4()
-            .font("Zed Mono")
-            .bg(cx.theme().colors().background)
-    }
-
-    pub fn title(cx: &mut WindowContext, title: SharedString) -> impl Element {
-        div()
-            .text_xl()
-            .text_color(cx.theme().colors().text)
-            .child(title)
-    }
-
-    pub fn title_for<T>(cx: &mut WindowContext) -> impl Element {
-        Self::title(cx, std::any::type_name::<T>().into())
-    }
-
-    pub fn label(cx: &mut WindowContext, label: impl Into<SharedString>) -> impl Element {
-        div()
-            .mt_4()
-            .mb_2()
-            .text_xs()
-            .text_color(cx.theme().colors().text)
-            .child(label.into())
-    }
-}

crates/theme2/src/styles.rs 🔗

@@ -4,8 +4,14 @@ mod status;
 mod syntax;
 mod system;
 
+#[cfg(feature = "stories")]
+mod stories;
+
 pub use colors::*;
 pub use players::*;
 pub use status::*;
 pub use syntax::*;
 pub use system::*;
+
+#[cfg(feature = "stories")]
+pub use stories::*;

crates/theme2/src/styles/players.rs 🔗

@@ -1,5 +1,7 @@
 use gpui::Hsla;
 
+use crate::{amber, blue, jade, lime, orange, pink, purple, red};
+
 #[derive(Debug, Clone, Copy, Default)]
 pub struct PlayerColor {
     pub cursor: Hsla,
@@ -133,141 +135,3 @@ impl PlayerColors {
         self.0[(participant_index as usize % len) + 1]
     }
 }
-
-#[cfg(feature = "stories")]
-pub use stories::*;
-
-use crate::{amber, blue, jade, lime, orange, pink, purple, red};
-
-#[cfg(feature = "stories")]
-mod stories {
-    use super::*;
-    use crate::{ActiveTheme, Story};
-    use gpui::{div, img, px, Div, ParentElement, Render, Styled, ViewContext};
-
-    pub struct PlayerStory;
-
-    impl Render for PlayerStory {
-        type Element = Div;
-
-        fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-            Story::container(cx).child(
-                div()
-                    .flex()
-                    .flex_col()
-                    .gap_4()
-                    .child(Story::title_for::<PlayerColors>(cx))
-                    .child(Story::label(cx, "Player Colors"))
-                    .child(
-                        div()
-                            .flex()
-                            .flex_col()
-                            .gap_1()
-                            .child(
-                                div().flex().gap_1().children(
-                                    cx.theme().players().0.clone().iter_mut().map(|player| {
-                                        div().w_8().h_8().rounded_md().bg(player.cursor)
-                                    }),
-                                ),
-                            )
-                            .child(div().flex().gap_1().children(
-                                cx.theme().players().0.clone().iter_mut().map(|player| {
-                                    div().w_8().h_8().rounded_md().bg(player.background)
-                                }),
-                            ))
-                            .child(div().flex().gap_1().children(
-                                cx.theme().players().0.clone().iter_mut().map(|player| {
-                                    div().w_8().h_8().rounded_md().bg(player.selection)
-                                }),
-                            )),
-                    )
-                    .child(Story::label(cx, "Avatar Rings"))
-                    .child(div().flex().gap_1().children(
-                        cx.theme().players().0.clone().iter_mut().map(|player| {
-                            div()
-                                .my_1()
-                                .rounded_full()
-                                .border_2()
-                                .border_color(player.cursor)
-                                .child(
-                                    img()
-                                        .rounded_full()
-                                        .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
-                                        .size_6()
-                                        .bg(gpui::red()),
-                                )
-                        }),
-                    ))
-                    .child(Story::label(cx, "Player Backgrounds"))
-                    .child(div().flex().gap_1().children(
-                        cx.theme().players().0.clone().iter_mut().map(|player| {
-                            div()
-                                .my_1()
-                                .rounded_xl()
-                                .flex()
-                                .items_center()
-                                .h_8()
-                                .py_0p5()
-                                .px_1p5()
-                                .bg(player.background)
-                                .child(
-                                div().relative().neg_mx_1().rounded_full().z_index(3)
-                                    .border_2()
-                                    .border_color(player.background)
-                                    .size(px(28.))
-                                    .child(
-                                    img()
-                                        .rounded_full()
-                                        .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
-                                        .size(px(24.))
-                                        .bg(gpui::red()),
-                                ),
-                            ).child(
-                            div().relative().neg_mx_1().rounded_full().z_index(2)
-                                .border_2()
-                                .border_color(player.background)
-                                .size(px(28.))
-                                .child(
-                                img()
-                                    .rounded_full()
-                                    .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
-                                    .size(px(24.))
-                                    .bg(gpui::red()),
-                            ),
-                        ).child(
-                        div().relative().neg_mx_1().rounded_full().z_index(1)
-                            .border_2()
-                            .border_color(player.background)
-                            .size(px(28.))
-                            .child(
-                            img()
-                                .rounded_full()
-                                .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
-                                .size(px(24.))
-                                .bg(gpui::red()),
-                        ),
-                    )
-                        }),
-                    ))
-                    .child(Story::label(cx, "Player Selections"))
-                    .child(div().flex().flex_col().gap_px().children(
-                        cx.theme().players().0.clone().iter_mut().map(|player| {
-                            div()
-                                .flex()
-                                .child(
-                                    div()
-                                        .flex()
-                                        .flex_none()
-                                        .rounded_sm()
-                                        .px_0p5()
-                                        .text_color(cx.theme().colors().text)
-                                        .bg(player.selection)
-                                        .child("The brown fox jumped over the lazy dog."),
-                                )
-                                .child(div().flex_1())
-                        }),
-                    )),
-            )
-        }
-    }
-}

crates/theme2/src/styles/stories/color.rs 🔗

@@ -0,0 +1,41 @@
+use gpui::prelude::*;
+use gpui::{div, px, Div, ViewContext};
+use story::Story;
+
+use crate::{default_color_scales, ColorScaleStep};
+
+pub struct ColorsStory;
+
+impl Render for ColorsStory {
+    type Element = Div;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        let color_scales = default_color_scales();
+
+        Story::container().child(Story::title("Colors")).child(
+            div()
+                .id("colors")
+                .flex()
+                .flex_col()
+                .gap_1()
+                .overflow_y_scroll()
+                .text_color(gpui::white())
+                .children(color_scales.into_iter().map(|scale| {
+                    div()
+                        .flex()
+                        .child(
+                            div()
+                                .w(px(75.))
+                                .line_height(px(24.))
+                                .child(scale.name().clone()),
+                        )
+                        .child(
+                            div().flex().gap_1().children(
+                                ColorScaleStep::ALL
+                                    .map(|step| div().flex().size_6().bg(scale.step(cx, step))),
+                            ),
+                        )
+                })),
+        )
+    }
+}

crates/theme2/src/styles/stories/players.rs 🔗

@@ -0,0 +1,137 @@
+use gpui::{div, img, px, Div, ParentElement, Render, Styled, ViewContext};
+use story::Story;
+
+use crate::{ActiveTheme, PlayerColors};
+
+pub struct PlayerStory;
+
+impl Render for PlayerStory {
+    type Element = Div;
+
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        Story::container().child(
+            div()
+                .flex()
+                .flex_col()
+                .gap_4()
+                .child(Story::title_for::<PlayerColors>())
+                .child(Story::label("Player Colors"))
+                .child(
+                    div()
+                        .flex()
+                        .flex_col()
+                        .gap_1()
+                        .child(
+                            div().flex().gap_1().children(
+                                cx.theme()
+                                    .players()
+                                    .0
+                                    .clone()
+                                    .iter_mut()
+                                    .map(|player| div().w_8().h_8().rounded_md().bg(player.cursor)),
+                            ),
+                        )
+                        .child(
+                            div().flex().gap_1().children(
+                                cx.theme().players().0.clone().iter_mut().map(|player| {
+                                    div().w_8().h_8().rounded_md().bg(player.background)
+                                }),
+                            ),
+                        )
+                        .child(
+                            div().flex().gap_1().children(
+                                cx.theme().players().0.clone().iter_mut().map(|player| {
+                                    div().w_8().h_8().rounded_md().bg(player.selection)
+                                }),
+                            ),
+                        ),
+                )
+                .child(Story::label("Avatar Rings"))
+                .child(div().flex().gap_1().children(
+                    cx.theme().players().0.clone().iter_mut().map(|player| {
+                        div()
+                            .my_1()
+                            .rounded_full()
+                            .border_2()
+                            .border_color(player.cursor)
+                            .child(
+                                img()
+                                    .rounded_full()
+                                    .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+                                    .size_6()
+                                    .bg(gpui::red()),
+                            )
+                    }),
+                ))
+                .child(Story::label("Player Backgrounds"))
+                .child(div().flex().gap_1().children(
+                    cx.theme().players().0.clone().iter_mut().map(|player| {
+                        div()
+                                .my_1()
+                                .rounded_xl()
+                                .flex()
+                                .items_center()
+                                .h_8()
+                                .py_0p5()
+                                .px_1p5()
+                                .bg(player.background)
+                                .child(
+                                div().relative().neg_mx_1().rounded_full().z_index(3)
+                                    .border_2()
+                                    .border_color(player.background)
+                                    .size(px(28.))
+                                    .child(
+                                    img()
+                                        .rounded_full()
+                                        .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+                                        .size(px(24.))
+                                        .bg(gpui::red()),
+                                ),
+                            ).child(
+                            div().relative().neg_mx_1().rounded_full().z_index(2)
+                                .border_2()
+                                .border_color(player.background)
+                                .size(px(28.))
+                                .child(
+                                img()
+                                    .rounded_full()
+                                    .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+                                    .size(px(24.))
+                                    .bg(gpui::red()),
+                            ),
+                        ).child(
+                        div().relative().neg_mx_1().rounded_full().z_index(1)
+                            .border_2()
+                            .border_color(player.background)
+                            .size(px(28.))
+                            .child(
+                            img()
+                                .rounded_full()
+                                .uri("https://avatars.githubusercontent.com/u/1714999?v=4")
+                                .size(px(24.))
+                                .bg(gpui::red()),
+                        ),
+                    )
+                    }),
+                ))
+                .child(Story::label("Player Selections"))
+                .child(div().flex().flex_col().gap_px().children(
+                    cx.theme().players().0.clone().iter_mut().map(|player| {
+                        div()
+                            .flex()
+                            .child(
+                                div()
+                                    .flex()
+                                    .flex_none()
+                                    .rounded_sm()
+                                    .px_0p5()
+                                    .text_color(cx.theme().colors().text)
+                                    .bg(player.selection)
+                                    .child("The brown fox jumped over the lazy dog."),
+                            )
+                            .child(div().flex_1())
+                    }),
+                )),
+        )
+    }
+}

crates/theme2/src/theme2.rs 🔗

@@ -144,8 +144,3 @@ pub struct DiagnosticStyle {
     pub hint: Hsla,
     pub ignored: Hsla,
 }
-
-#[cfg(feature = "stories")]
-mod story;
-#[cfg(feature = "stories")]
-pub use story::*;

crates/ui2/Cargo.toml 🔗

@@ -17,10 +17,11 @@ menu = { package = "menu2", path = "../menu2"}
 serde.workspace = true
 settings2 = { path = "../settings2" }
 smallvec.workspace = true
+story = { path = "../story", optional = true }
 strum = { version = "0.25.0", features = ["derive"] }
 theme2 = { path = "../theme2" }
 rand = "0.8"
 
 [features]
 default = []
-stories = ["dep:itertools"]
+stories = ["dep:itertools", "dep:story"]

crates/ui2/src/components/stories/avatar.rs 🔗

@@ -1,7 +1,8 @@
 use gpui::{Div, Render};
+use story::Story;
 
 use crate::prelude::*;
-use crate::{Avatar, Story};
+use crate::Avatar;
 
 pub struct AvatarStory;
 
@@ -9,9 +10,9 @@ impl Render for AvatarStory {
     type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        Story::container(cx)
-            .child(Story::title_for::<Avatar>(cx))
-            .child(Story::label(cx, "Default"))
+        Story::container()
+            .child(Story::title_for::<Avatar>())
+            .child(Story::label("Default"))
             .child(Avatar::new(
                 "https://avatars.githubusercontent.com/u/1714999?v=4",
             ))

crates/ui2/src/components/stories/button.rs 🔗

@@ -1,8 +1,9 @@
 use gpui::{rems, Div, Render};
+use story::Story;
 use strum::IntoEnumIterator;
 
 use crate::prelude::*;
-use crate::{h_stack, v_stack, Button, Icon, IconPosition, Label, Story};
+use crate::{h_stack, v_stack, Button, Icon, IconPosition, Label};
 
 pub struct ButtonStory;
 
@@ -12,15 +13,15 @@ impl Render for ButtonStory {
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let states = InteractionState::iter();
 
-        Story::container(cx)
-            .child(Story::title_for::<Button>(cx))
+        Story::container()
+            .child(Story::title_for::<Button>())
             .child(
                 div()
                     .flex()
                     .gap_8()
                     .child(
                         div()
-                            .child(Story::label(cx, "Ghost (Default)"))
+                            .child(Story::label("Ghost (Default)"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -29,7 +30,7 @@ impl Render for ButtonStory {
                                         Button::new("Label").variant(ButtonVariant::Ghost), // .state(state),
                                     )
                             })))
-                            .child(Story::label(cx, "Ghost – Left Icon"))
+                            .child(Story::label("Ghost – Left Icon"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -41,7 +42,7 @@ impl Render for ButtonStory {
                                             .icon_position(IconPosition::Left), // .state(state),
                                     )
                             })))
-                            .child(Story::label(cx, "Ghost – Right Icon"))
+                            .child(Story::label("Ghost – Right Icon"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -56,7 +57,7 @@ impl Render for ButtonStory {
                     )
                     .child(
                         div()
-                            .child(Story::label(cx, "Filled"))
+                            .child(Story::label("Filled"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -65,7 +66,7 @@ impl Render for ButtonStory {
                                         Button::new("Label").variant(ButtonVariant::Filled), // .state(state),
                                     )
                             })))
-                            .child(Story::label(cx, "Filled – Left Button"))
+                            .child(Story::label("Filled – Left Button"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -77,7 +78,7 @@ impl Render for ButtonStory {
                                             .icon_position(IconPosition::Left), // .state(state),
                                     )
                             })))
-                            .child(Story::label(cx, "Filled – Right Button"))
+                            .child(Story::label("Filled – Right Button"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -92,7 +93,7 @@ impl Render for ButtonStory {
                     )
                     .child(
                         div()
-                            .child(Story::label(cx, "Fixed With"))
+                            .child(Story::label("Fixed With"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -104,7 +105,7 @@ impl Render for ButtonStory {
                                             .width(Some(rems(6.).into())),
                                     )
                             })))
-                            .child(Story::label(cx, "Fixed With – Left Icon"))
+                            .child(Story::label("Fixed With – Left Icon"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -118,7 +119,7 @@ impl Render for ButtonStory {
                                             .width(Some(rems(6.).into())),
                                     )
                             })))
-                            .child(Story::label(cx, "Fixed With – Right Icon"))
+                            .child(Story::label("Fixed With – Right Icon"))
                             .child(h_stack().gap_2().children(states.clone().map(|state| {
                                 v_stack()
                                     .gap_1()
@@ -134,7 +135,7 @@ impl Render for ButtonStory {
                             }))),
                     ),
             )
-            .child(Story::label(cx, "Button with `on_click`"))
+            .child(Story::label("Button with `on_click`"))
             .child(
                 Button::new("Label")
                     .variant(ButtonVariant::Ghost)

crates/ui2/src/components/stories/checkbox.rs 🔗

@@ -1,7 +1,8 @@
 use gpui::{Div, Render, ViewContext};
+use story::Story;
 
 use crate::prelude::*;
-use crate::{h_stack, Checkbox, Story};
+use crate::{h_stack, Checkbox};
 
 pub struct CheckboxStory;
 
@@ -9,9 +10,9 @@ impl Render for CheckboxStory {
     type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        Story::container(cx)
-            .child(Story::title_for::<Checkbox>(cx))
-            .child(Story::label(cx, "Default"))
+        Story::container()
+            .child(Story::title_for::<Checkbox>())
+            .child(Story::label("Default"))
             .child(
                 h_stack()
                     .p_2()
@@ -26,7 +27,7 @@ impl Render for CheckboxStory {
                     ))
                     .child(Checkbox::new("checkbox-selected", Selection::Selected)),
             )
-            .child(Story::label(cx, "Disabled"))
+            .child(Story::label("Disabled"))
             .child(
                 h_stack()
                     .p_2()

crates/ui2/src/components/stories/context_menu.rs 🔗

@@ -1,7 +1,8 @@
 use gpui::{actions, Action, AnchorCorner, Div, Render, View};
+use story::Story;
 
 use crate::prelude::*;
-use crate::{menu_handle, ContextMenu, Label, ListItem, Story};
+use crate::{menu_handle, ContextMenu, Label, ListItem};
 
 actions!(PrintCurrentDate, PrintBestFood);
 
@@ -29,7 +30,7 @@ impl Render for ContextMenuStory {
     type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        Story::container(cx)
+        Story::container()
             .on_action(|_: &PrintCurrentDate, _| {
                 println!("printing unix time!");
                 if let Ok(unix_time) = std::time::UNIX_EPOCH.elapsed() {

crates/ui2/src/components/stories/icon.rs 🔗

@@ -1,8 +1,9 @@
 use gpui::{Div, Render};
+use story::Story;
 use strum::IntoEnumIterator;
 
 use crate::prelude::*;
-use crate::{Icon, IconElement, Story};
+use crate::{Icon, IconElement};
 
 pub struct IconStory;
 
@@ -12,9 +13,9 @@ impl Render for IconStory {
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let icons = Icon::iter();
 
-        Story::container(cx)
-            .child(Story::title_for::<IconElement>(cx))
-            .child(Story::label(cx, "All Icons"))
+        Story::container()
+            .child(Story::title_for::<IconElement>())
+            .child(Story::label("All Icons"))
             .child(div().flex().gap_3().children(icons.map(IconElement::new)))
     }
 }

crates/ui2/src/components/stories/input.rs 🔗

@@ -1,7 +1,8 @@
 use gpui::{Div, Render};
+use story::Story;
 
 use crate::prelude::*;
-use crate::{Input, Story};
+use crate::Input;
 
 pub struct InputStory;
 
@@ -9,9 +10,9 @@ impl Render for InputStory {
     type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        Story::container(cx)
-            .child(Story::title_for::<Input>(cx))
-            .child(Story::label(cx, "Default"))
+        Story::container()
+            .child(Story::title_for::<Input>())
+            .child(Story::label("Default"))
             .child(div().flex().child(Input::new("Search")))
     }
 }

crates/ui2/src/components/stories/keybinding.rs 🔗

@@ -1,8 +1,9 @@
 use gpui::{actions, Div, Render};
 use itertools::Itertools;
+use story::Story;
 
 use crate::prelude::*;
-use crate::{KeyBinding, Story};
+use crate::KeyBinding;
 
 pub struct KeybindingStory;
 
@@ -18,11 +19,11 @@ impl Render for KeybindingStory {
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
         let all_modifier_permutations = ["ctrl", "alt", "cmd", "shift"].into_iter().permutations(2);
 
-        Story::container(cx)
-            .child(Story::title_for::<KeyBinding>(cx))
-            .child(Story::label(cx, "Single Key"))
+        Story::container()
+            .child(Story::title_for::<KeyBinding>())
+            .child(Story::label("Single Key"))
             .child(KeyBinding::new(binding("Z")))
-            .child(Story::label(cx, "Single Key with Modifier"))
+            .child(Story::label("Single Key with Modifier"))
             .child(
                 div()
                     .flex()
@@ -32,7 +33,7 @@ impl Render for KeybindingStory {
                     .child(KeyBinding::new(binding("cmd-c")))
                     .child(KeyBinding::new(binding("shift-c"))),
             )
-            .child(Story::label(cx, "Single Key with Modifier (Permuted)"))
+            .child(Story::label("Single Key with Modifier (Permuted)"))
             .child(
                 div().flex().flex_col().children(
                     all_modifier_permutations
@@ -49,11 +50,11 @@ impl Render for KeybindingStory {
                         }),
                 ),
             )
-            .child(Story::label(cx, "Single Key with All Modifiers"))
+            .child(Story::label("Single Key with All Modifiers"))
             .child(KeyBinding::new(binding("ctrl-alt-cmd-shift-z")))
-            .child(Story::label(cx, "Chord"))
+            .child(Story::label("Chord"))
             .child(KeyBinding::new(binding("a z")))
-            .child(Story::label(cx, "Chord with Modifier"))
+            .child(Story::label("Chord with Modifier"))
             .child(KeyBinding::new(binding("ctrl-a shift-z")))
             .child(KeyBinding::new(binding("fn-s")))
     }

crates/ui2/src/components/stories/label.rs 🔗

@@ -1,7 +1,8 @@
 use gpui::{Div, Render};
+use story::Story;
 
 use crate::prelude::*;
-use crate::{HighlightedLabel, Label, Story};
+use crate::{HighlightedLabel, Label};
 
 pub struct LabelStory;
 
@@ -9,11 +10,11 @@ impl Render for LabelStory {
     type Element = Div;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-        Story::container(cx)
-            .child(Story::title_for::<Label>(cx))
-            .child(Story::label(cx, "Default"))
+        Story::container()
+            .child(Story::title_for::<Label>())
+            .child(Story::label("Default"))
             .child(Label::new("Hello, world!"))
-            .child(Story::label(cx, "Highlighted"))
+            .child(Story::label("Highlighted"))
             .child(HighlightedLabel::new(
                 "Hello, world!",
                 vec![0, 1, 2, 7, 8, 12],

crates/ui2/src/story.rs 🔗

@@ -1,37 +0,0 @@
-use gpui::Div;
-
-use crate::prelude::*;
-
-pub struct Story {}
-
-impl Story {
-    pub fn container(cx: &mut gpui::WindowContext) -> Div {
-        div()
-            .size_full()
-            .flex()
-            .flex_col()
-            .pt_2()
-            .px_4()
-            .bg(cx.theme().colors().background)
-    }
-
-    pub fn title(cx: &mut WindowContext, title: impl Into<SharedString>) -> impl Element {
-        div()
-            .text_xl()
-            .text_color(cx.theme().colors().text)
-            .child(title.into())
-    }
-
-    pub fn title_for<T>(cx: &mut WindowContext) -> impl Element {
-        Self::title(cx, std::any::type_name::<T>())
-    }
-
-    pub fn label(cx: &mut WindowContext, label: impl Into<SharedString>) -> impl Element {
-        div()
-            .mt_4()
-            .mb_2()
-            .text_xs()
-            .text_color(cx.theme().colors().text)
-            .child(label.into())
-    }
-}

crates/ui2/src/ui2.rs 🔗

@@ -24,8 +24,3 @@ pub use components::*;
 pub use prelude::*;
 pub use styled_ext::*;
 pub use styles::*;
-
-#[cfg(feature = "stories")]
-mod story;
-#[cfg(feature = "stories")]
-pub use story::*;