story_selector.rs

  1use std::str::FromStr;
  2use std::sync::OnceLock;
  3
  4use crate::stories::*;
  5use clap::ValueEnum;
  6use clap::builder::PossibleValue;
  7use gpui::AnyView;
  8use strum::{EnumIter, EnumString, IntoEnumIterator};
  9use ui::prelude::*;
 10
 11#[derive(Debug, PartialEq, Eq, Clone, Copy, strum::Display, EnumString, EnumIter)]
 12#[strum(serialize_all = "snake_case")]
 13pub enum ComponentStory {
 14    ApplicationMenu,
 15    AutoHeightEditor,
 16    CollabNotification,
 17    ContextMenu,
 18    Cursor,
 19    Focus,
 20    OverflowScroll,
 21    Picker,
 22    Scroll,
 23    Text,
 24    ViewportUnits,
 25    WithRemSize,
 26    IndentGuides,
 27}
 28
 29impl ComponentStory {
 30    pub fn story(&self, window: &mut Window, cx: &mut App) -> AnyView {
 31        match self {
 32            Self::ApplicationMenu => cx
 33                .new(|cx| title_bar::ApplicationMenuStory::new(window, cx))
 34                .into(),
 35            Self::AutoHeightEditor => AutoHeightEditorStory::new(window, cx).into(),
 36            Self::CollabNotification => cx
 37                .new(|_| collab_ui::notifications::CollabNotificationStory)
 38                .into(),
 39            Self::ContextMenu => cx.new(|_| ui::ContextMenuStory).into(),
 40            Self::Cursor => cx.new(|_| crate::stories::CursorStory).into(),
 41            Self::Focus => FocusStory::model(window, cx).into(),
 42            Self::OverflowScroll => cx.new(|_| crate::stories::OverflowScrollStory).into(),
 43            Self::Picker => PickerStory::new(window, cx).into(),
 44            Self::Scroll => ScrollStory::model(cx).into(),
 45            Self::Text => TextStory::model(cx).into(),
 46            Self::ViewportUnits => cx.new(|_| crate::stories::ViewportUnitsStory).into(),
 47            Self::WithRemSize => cx.new(|_| crate::stories::WithRemSizeStory).into(),
 48            Self::IndentGuides => crate::stories::IndentGuidesStory::model(window, cx).into(),
 49        }
 50    }
 51}
 52
 53#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 54pub enum StorySelector {
 55    Component(ComponentStory),
 56    KitchenSink,
 57}
 58
 59impl FromStr for StorySelector {
 60    type Err = anyhow::Error;
 61
 62    fn from_str(raw_story_name: &str) -> std::result::Result<Self, Self::Err> {
 63        use anyhow::Context as _;
 64
 65        let story = raw_story_name.to_ascii_lowercase();
 66
 67        if story == "kitchen_sink" {
 68            return Ok(Self::KitchenSink);
 69        }
 70
 71        if let Some((_, story)) = story.split_once("components/") {
 72            let component_story = ComponentStory::from_str(story)
 73                .with_context(|| format!("story not found for component '{story}'"))?;
 74
 75            return Ok(Self::Component(component_story));
 76        }
 77
 78        anyhow::bail!("story not found for '{raw_story_name}'")
 79    }
 80}
 81
 82impl StorySelector {
 83    pub fn story(&self, window: &mut Window, cx: &mut App) -> AnyView {
 84        match self {
 85            Self::Component(component_story) => component_story.story(window, cx),
 86            Self::KitchenSink => KitchenSinkStory::model(cx).into(),
 87        }
 88    }
 89}
 90
 91/// The list of all stories available in the storybook.
 92static ALL_STORY_SELECTORS: OnceLock<Vec<StorySelector>> = OnceLock::new();
 93
 94impl ValueEnum for StorySelector {
 95    fn value_variants<'a>() -> &'a [Self] {
 96        (ALL_STORY_SELECTORS.get_or_init(|| {
 97            let component_stories = ComponentStory::iter().map(StorySelector::Component);
 98
 99            component_stories
100                .chain(std::iter::once(StorySelector::KitchenSink))
101                .collect::<Vec<_>>()
102        })) as _
103    }
104
105    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
106        let value = match self {
107            Self::Component(story) => format!("components/{story}"),
108            Self::KitchenSink => "kitchen_sink".to_string(),
109        };
110
111        Some(PossibleValue::new(value))
112    }
113}