138 lines · 4.5 KB · Rust
RawDownload
use std::str::FromStr;use std::sync::OnceLock; use crate::stories::*;use anyhow::anyhow;use clap::builder::PossibleValue;use clap::ValueEnum;use gpui::AnyView;use strum::{EnumIter, EnumString, IntoEnumIterator};use ui::prelude::*; #[derive(Debug, PartialEq, Eq, Clone, Copy, strum::Display, EnumString, EnumIter)]#[strum(serialize_all = "snake_case")]pub enum ComponentStory {    ApplicationMenu,    AutoHeightEditor,    CollabNotification,    ContextMenu,    Cursor,    DefaultColors,    Disclosure,    Focus,    Icon,    IconButton,    Keybinding,    List,    ListHeader,    ListItem,    OverflowScroll,    Picker,    Scroll,    Tab,    TabBar,    Text,    ToggleButton,    ViewportUnits,    WithRemSize,    Vector,} impl ComponentStory {    pub fn story(&self, window: &mut Window, cx: &mut App) -> AnyView {        match self {            Self::ApplicationMenu => cx                .new(|cx| title_bar::ApplicationMenuStory::new(window, cx))                .into(),            Self::AutoHeightEditor => AutoHeightEditorStory::new(window, cx).into(),            Self::CollabNotification => cx                .new(|_| collab_ui::notifications::CollabNotificationStory)                .into(),            Self::ContextMenu => cx.new(|_| ui::ContextMenuStory).into(),            Self::Cursor => cx.new(|_| crate::stories::CursorStory).into(),            Self::DefaultColors => DefaultColorsStory::model(cx).into(),            Self::Disclosure => cx.new(|_| ui::DisclosureStory).into(),            Self::Focus => FocusStory::model(window, cx).into(),            Self::Icon => cx.new(|_| ui::IconStory).into(),            Self::IconButton => cx.new(|_| ui::IconButtonStory).into(),            Self::Keybinding => cx.new(|_| ui::KeybindingStory).into(),            Self::List => cx.new(|_| ui::ListStory).into(),            Self::ListHeader => cx.new(|_| ui::ListHeaderStory).into(),            Self::ListItem => cx.new(|_| ui::ListItemStory).into(),            Self::OverflowScroll => cx.new(|_| crate::stories::OverflowScrollStory).into(),            Self::Picker => PickerStory::new(window, cx).into(),            Self::Scroll => ScrollStory::model(cx).into(),            Self::Tab => cx.new(|_| ui::TabStory).into(),            Self::TabBar => cx.new(|_| ui::TabBarStory).into(),            Self::Text => TextStory::model(cx).into(),            Self::ToggleButton => cx.new(|_| ui::ToggleButtonStory).into(),            Self::ViewportUnits => cx.new(|_| crate::stories::ViewportUnitsStory).into(),            Self::WithRemSize => cx.new(|_| crate::stories::WithRemSizeStory).into(),            Self::Vector => cx.new(|_| ui::VectorStory).into(),        }    }} #[derive(Debug, PartialEq, Eq, Clone, Copy)]pub enum StorySelector {    Component(ComponentStory),    KitchenSink,} impl FromStr for StorySelector {    type Err = anyhow::Error;     fn from_str(raw_story_name: &str) -> std::result::Result<Self, Self::Err> {        use anyhow::Context as _;         let story = raw_story_name.to_ascii_lowercase();         if story == "kitchen_sink" {            return Ok(Self::KitchenSink);        }         if let Some((_, story)) = story.split_once("components/") {            let component_story = ComponentStory::from_str(story)                .with_context(|| format!("story not found for component '{story}'"))?;             return Ok(Self::Component(component_story));        }         Err(anyhow!("story not found for '{raw_story_name}'"))    }} impl StorySelector {    pub fn story(&self, window: &mut Window, cx: &mut App) -> AnyView {        match self {            Self::Component(component_story) => component_story.story(window, cx),            Self::KitchenSink => KitchenSinkStory::model(cx).into(),        }    }} /// The list of all stories available in the storybook.static ALL_STORY_SELECTORS: OnceLock<Vec<StorySelector>> = OnceLock::new(); impl ValueEnum for StorySelector {    fn value_variants<'a>() -> &'a [Self] {        let stories = ALL_STORY_SELECTORS.get_or_init(|| {            let component_stories = ComponentStory::iter().map(StorySelector::Component);             component_stories                .chain(std::iter::once(StorySelector::KitchenSink))                .collect::<Vec<_>>()        });         stories    }     fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {        let value = match self {            Self::Component(story) => format!("components/{story}"),            Self::KitchenSink => "kitchen_sink".to_string(),        };         Some(PossibleValue::new(value))    }}