diff --git a/crates/story/src/story.rs b/crates/story/src/story.rs index 4985fb1961..3419af95b0 100644 --- a/crates/story/src/story.rs +++ b/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, 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(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
; + + 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::()) + .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(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::()) + .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) -> impl Element { diff --git a/crates/storybook2/src/stories/text.rs b/crates/storybook2/src/stories/text.rs index b48b9dd4b5..7c1d29a269 100644 --- a/crates/storybook2/src/stories/text.rs +++ b/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; + + fn render(&mut self, cx: &mut gpui::ViewContext) -> Self::Element { + StoryContainer::new("Text Story", "crates/storybook2/src/stories/text.rs") + .children( + vec![ - fn render(&mut self, _cx: &mut gpui::ViewContext) -> Self::Element { - Story::container2::("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;