Use updated story container in Text story

Nate Butler created

Change summary

crates/story/src/story.rs             | 118 +++++++++++++++++++++++++---
crates/storybook2/src/stories/text.rs |  50 +++++++++++-
2 files changed, 148 insertions(+), 20 deletions(-)

Detailed changes

crates/story/src/story.rs 🔗

@@ -1,5 +1,6 @@
 use gpui::{
-    div, hsla, prelude::*, px, rems, AnyElement, Div, ElementId, Hsla, SharedString, WindowContext,
+    div, hsla, prelude::*, px, rems, AnyElement, Div, ElementId, Hsla, SharedString, Stateful,
+    WindowContext,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
@@ -49,47 +50,134 @@ pub fn story_color() -> StoryColor {
     StoryColor::new()
 }
 
-pub struct Story {}
+#[derive(IntoElement)]
+pub struct StoryContainer {
+    title: SharedString,
+    relative_path: &'static str,
+    children: SmallVec<[AnyElement; 2]>,
+}
 
-impl Story {
-    pub fn container() -> Div {
-        div()
-            .size_full()
-            .flex()
-            .flex_col()
-            .bg(story_color().background)
+impl StoryContainer {
+    pub fn new(title: impl Into<SharedString>, relative_path: &'static str) -> Self {
+        Self {
+            title: title.into(),
+            relative_path,
+            children: SmallVec::new(),
+        }
     }
+}
 
-    // TODO: Move all stories to container2, then rename
-    pub fn container2<T>(relative_path: &'static str) -> Div {
+impl ParentElement for StoryContainer {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
+        &mut self.children
+    }
+}
+
+impl RenderOnce for StoryContainer {
+    type Rendered = Stateful<Div>;
+
+    fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
         div()
             .size_full()
             .flex()
             .flex_col()
+            .id("story_container")
             .bg(story_color().background)
             .child(
                 div()
                     .flex()
+                    .flex_none()
+                    .w_full()
                     .justify_between()
                     .p_2()
+                    .bg(story_color().background)
                     .border_b()
                     .border_color(story_color().border)
-                    .child(Story::title_for::<T>())
+                    .child(Story::title(self.title))
                     .child(
                         div()
                             .text_xs()
                             .text_color(story_color().primary)
-                            .child(Story::open_story_link(relative_path)),
+                            .child(Story::open_story_link(self.relative_path)),
                     ),
             )
+            .child(
+                div()
+                    .w_full()
+                    .h_px()
+                    .flex_1()
+                    .id("story_body")
+                    .overflow_hidden_x()
+                    .overflow_y_scroll()
+                    .flex()
+                    .flex_col()
+                    .pb_4()
+                    .children(self.children),
+            )
+    }
+}
+
+pub struct Story {}
+
+impl Story {
+    pub fn container() -> Div {
+        div().size_full().overflow_hidden().child(
+            div()
+                .id("story_container")
+                .overflow_y_scroll()
+                .w_full()
+                .min_h_full()
+                .flex()
+                .flex_col()
+                .bg(story_color().background),
+        )
+    }
+
+    // TODO: Move all stories to container2, then rename
+    pub fn container2<T>(relative_path: &'static str) -> Div {
+        div().size_full().child(
+            div()
+                .size_full()
+                .id("story_container")
+                .overflow_y_scroll()
+                .flex()
+                .flex_col()
+                .flex_none()
+                .child(
+                    div()
+                        .flex()
+                        .justify_between()
+                        .p_2()
+                        .border_b()
+                        .border_color(story_color().border)
+                        .child(Story::title_for::<T>())
+                        .child(
+                            div()
+                                .text_xs()
+                                .text_color(story_color().primary)
+                                .child(Story::open_story_link(relative_path)),
+                        ),
+                )
+                .child(
+                    div()
+                        .w_full()
+                        .min_h_full()
+                        .flex()
+                        .flex_col()
+                        .bg(story_color().background),
+                ),
+        )
     }
 
     pub fn open_story_link(relative_path: &'static str) -> impl Element {
         let path = PathBuf::from_iter([relative_path]);
+
         div()
-            .id(SharedString::from(format!("id_{}", relative_path)))
+            .flex()
+            .gap_2()
             .text_xs()
             .text_color(story_color().primary)
+            .id(SharedString::from(format!("id_{}", relative_path)))
             .on_click({
                 let path = path.clone();
 
@@ -99,7 +187,7 @@ impl Story {
                     std::process::Command::new("zed").arg(path).spawn().ok();
                 }
             })
-            .child(Story::link(path.to_string_lossy().to_string()))
+            .children(vec![div().child(Story::link("Open in Zed →"))])
     }
 
     pub fn title(title: impl Into<SharedString>) -> impl Element {

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

@@ -1,4 +1,7 @@
-use gpui::{div, red, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext};
+use gpui::{
+    div, green, red, Component, Div, HighlightStyle, InteractiveText, IntoElement, ParentElement,
+    Render, Styled, StyledText, View, VisualContext, WindowContext,
+};
 use indoc::indoc;
 use story::*;
 
@@ -11,10 +14,13 @@ impl TextStory {
 }
 
 impl Render for TextStory {
-    type Element = Div;
+    type Element = Component<StoryContainer>;
+
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
+        StoryContainer::new("Text Story", "crates/storybook2/src/stories/text.rs")
+            .children(
+                vec![
 
-    fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element {
-        Story::container2::<TextStory>("crates/storybook2/src/stories/text.rs").child(
             StorySection::new()
                 .child(
                     StoryItem::new("Default", div().bg(gpui::blue()).child("Hello World!"))
@@ -71,10 +77,44 @@ impl Render for TextStory {
                         "##
                     })
                 )
-        )
+                .child(
+                    StoryItem::new("Interactive Text",
+                        InteractiveText::new(
+                            "interactive",
+                            StyledText::new("Hello world, how is it going?").with_highlights(&cx.text_style(), [
+                                (6..11, HighlightStyle {
+                                    background_color: Some(green()),
+                                    ..Default::default()
+                                }),
+                            ]),
+                        )
+                        .on_click(vec![2..4, 1..3, 7..9], |range_ix, _cx| {
+                            println!("Clicked range {range_ix}");
+                        })
+                    )
+                    .usage(indoc! {r##"
+                        InteractiveText::new(
+                            "interactive",
+                            StyledText::new("Hello world, how is it going?").with_highlights(&cx.text_style(), [
+                                (6..11, HighlightStyle {
+                                    background_color: Some(green()),
+                                    ..Default::default()
+                                }),
+                            ]),
+                        )
+                        .on_click(vec![2..4, 1..3, 7..9], |range_ix, _cx| {
+                            println!("Clicked range {range_ix}");
+                        })
+                        "##
+                    })
+                )
+        ]
+            ).into_element()
     }
 }
 
+// TODO: Check all were updated to new style and remove
+
 // impl Render for TextStory {
 //     type Element = Div;