Colocate element stories with their elements

This commit is contained in:
Marshall Bowers 2023-10-10 16:00:04 -04:00
parent 30088afa89
commit f2ee61553f
16 changed files with 379 additions and 364 deletions

View file

@ -42,3 +42,40 @@ impl<S: 'static + Send + Sync> Avatar<S> {
.fill(theme.middle.warning.default.foreground)
}
}
#[cfg(feature = "stories")]
pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
use crate::Story;
use super::*;
#[derive(Element)]
pub struct AvatarStory<S: 'static + Send + Sync> {
state_type: PhantomData<S>,
}
impl<S: 'static + Send + Sync> AvatarStory<S> {
pub fn new() -> Self {
Self {
state_type: PhantomData,
}
}
fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
Story::container(cx)
.child(Story::title_for::<_, Avatar<S>>(cx))
.child(Story::label(cx, "Default"))
.child(Avatar::new(
"https://avatars.githubusercontent.com/u/1714999?v=4",
))
.child(Story::label(cx, "Rounded rectangle"))
.child(
Avatar::new("https://avatars.githubusercontent.com/u/1714999?v=4")
.shape(Shape::RoundedRectangle),
)
}
}
}

View file

@ -202,3 +202,206 @@ impl<S: 'static + Send + Sync + Clone> Button<S> {
el
}
}
#[cfg(feature = "stories")]
pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
use gpui3::rems;
use strum::IntoEnumIterator;
use crate::{h_stack, v_stack, LabelColor, LabelSize, Story};
use super::*;
#[derive(Element)]
pub struct ButtonStory<S: 'static + Send + Sync + Clone> {
state_type: PhantomData<S>,
}
impl<S: 'static + Send + Sync + Clone> ButtonStory<S> {
pub fn new() -> Self {
Self {
state_type: PhantomData,
}
}
fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
let states = InteractionState::iter();
Story::container(cx)
.child(Story::title_for::<_, Button<S>>(cx))
.child(
div()
.flex()
.gap_8()
.child(
div()
.child(Story::label(cx, "Ghost (Default)"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Ghost)
.state(state),
)
})))
.child(Story::label(cx, "Ghost Left Icon"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Ghost)
.icon(Icon::Plus)
.icon_position(IconPosition::Left)
.state(state),
)
})))
.child(Story::label(cx, "Ghost Right Icon"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Ghost)
.icon(Icon::Plus)
.icon_position(IconPosition::Right)
.state(state),
)
}))),
)
.child(
div()
.child(Story::label(cx, "Filled"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Filled)
.state(state),
)
})))
.child(Story::label(cx, "Filled Left Button"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Filled)
.icon(Icon::Plus)
.icon_position(IconPosition::Left)
.state(state),
)
})))
.child(Story::label(cx, "Filled Right Button"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Filled)
.icon(Icon::Plus)
.icon_position(IconPosition::Right)
.state(state),
)
}))),
)
.child(
div()
.child(Story::label(cx, "Fixed With"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Filled)
.state(state)
.width(Some(rems(6.).into())),
)
})))
.child(Story::label(cx, "Fixed With Left Icon"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Filled)
.state(state)
.icon(Icon::Plus)
.icon_position(IconPosition::Left)
.width(Some(rems(6.).into())),
)
})))
.child(Story::label(cx, "Fixed With Right Icon"))
.child(h_stack().gap_2().children(states.clone().map(|state| {
v_stack()
.gap_1()
.child(
Label::new(state.to_string())
.color(LabelColor::Muted)
.size(LabelSize::Small),
)
.child(
Button::new("Label")
.variant(ButtonVariant::Filled)
.state(state)
.icon(Icon::Plus)
.icon_position(IconPosition::Right)
.width(Some(rems(6.).into())),
)
}))),
),
)
.child(Story::label(cx, "Button with `on_click`"))
.child(
Button::new("Label").variant(ButtonVariant::Ghost), // NOTE: There currently appears to be a bug in GPUI2 where only the last event handler will fire.
// So adding additional buttons with `on_click`s after this one will cause this `on_click` to not fire.
// .on_click(|_view, _cx| println!("Button clicked.")),
)
}
}
}

View file

@ -38,3 +38,38 @@ impl<S: 'static + Send + Sync + Clone> Details<S> {
.children(self.meta.map(|m| m))
}
}
#[cfg(feature = "stories")]
pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
use crate::Story;
use super::*;
#[derive(Element)]
pub struct DetailsStory<S: 'static + Send + Sync + Clone> {
state_type: PhantomData<S>,
}
impl<S: 'static + Send + Sync + Clone> DetailsStory<S> {
pub fn new() -> Self {
Self {
state_type: PhantomData,
}
}
fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
Story::container(cx)
.child(Story::title_for::<_, Details<S>>(cx))
.child(Story::label(cx, "Default"))
.child(Details::new("The quick brown fox jumps over the lazy dog"))
.child(Story::label(cx, "With meta"))
.child(
Details::new("The quick brown fox jumps over the lazy dog")
.meta_text("Sphinx of black quartz, judge my vow."),
)
}
}
}

View file

@ -182,3 +182,37 @@ impl<S: 'static + Send + Sync> IconElement<S> {
sized_svg.flex_none().path(self.icon.path()).fill(fill)
}
}
#[cfg(feature = "stories")]
pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
use strum::IntoEnumIterator;
use crate::Story;
use super::*;
#[derive(Element, Default)]
pub struct IconStory<S: 'static + Send + Sync> {
state_type: PhantomData<S>,
}
impl<S: 'static + Send + Sync> IconStory<S> {
pub fn new() -> Self {
Self {
state_type: PhantomData,
}
}
fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
let icons = Icon::iter();
Story::container(cx)
.child(Story::title_for::<_, IconElement<S>>(cx))
.child(Story::label(cx, "All Icons"))
.child(div().flex().gap_3().children(icons.map(IconElement::new)))
}
}
}

View file

@ -108,3 +108,33 @@ impl<S: 'static + Send + Sync> Input<S> {
)
}
}
#[cfg(feature = "stories")]
pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
use crate::Story;
use super::*;
#[derive(Element)]
pub struct InputStory<S: 'static + Send + Sync + Clone> {
state_type: PhantomData<S>,
}
impl<S: 'static + Send + Sync + Clone> InputStory<S> {
pub fn new() -> Self {
Self {
state_type: PhantomData,
}
}
fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
Story::container(cx)
.child(Story::title_for::<_, Input<S>>(cx))
.child(Story::label(cx, "Default"))
.child(div().flex().child(Input::new("Search")))
}
}
}

View file

@ -163,3 +163,35 @@ struct Run {
pub text: String,
pub color: Hsla,
}
#[cfg(feature = "stories")]
pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
use crate::Story;
use super::*;
#[derive(Element)]
pub struct LabelStory<S: 'static + Send + Sync + Clone> {
state_type: PhantomData<S>,
}
impl<S: 'static + Send + Sync + Clone> LabelStory<S> {
pub fn new() -> Self {
Self {
state_type: PhantomData,
}
}
fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
Story::container(cx)
.child(Story::title_for::<_, Label<S>>(cx))
.child(Story::label(cx, "Default"))
.child(Label::new("Hello, world!"))
.child(Story::label(cx, "Highlighted"))
.child(Label::new("Hello, world!").with_highlights(vec![0, 1, 2, 7, 8, 12]))
}
}
}