storybook.rs

  1mod assets;
  2mod stories;
  3mod story_selector;
  4
  5use clap::Parser;
  6use dialoguer::FuzzySelect;
  7use gpui::{
  8    div, px, size, AnyView, AppContext, Bounds, Render, ViewContext, VisualContext, WindowBounds,
  9    WindowOptions,
 10};
 11use log::LevelFilter;
 12use settings::{default_settings, Settings, SettingsStore};
 13use simplelog::SimpleLogger;
 14use strum::IntoEnumIterator;
 15use theme::{ThemeRegistry, ThemeSettings};
 16use ui::prelude::*;
 17
 18use crate::assets::Assets;
 19use crate::story_selector::{ComponentStory, StorySelector};
 20pub use indoc::indoc;
 21
 22#[derive(Parser)]
 23#[command(author, version, about, long_about = None)]
 24struct Args {
 25    #[arg(value_enum)]
 26    story: Option<StorySelector>,
 27
 28    /// The name of the theme to use in the storybook.
 29    ///
 30    /// If not provided, the default theme will be used.
 31    #[arg(long)]
 32    theme: Option<String>,
 33}
 34
 35fn main() {
 36    // unsafe { backtrace_on_stack_overflow::enable() };
 37
 38    SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
 39
 40    let args = Args::parse();
 41
 42    let story_selector = args.story.clone().unwrap_or_else(|| {
 43        let stories = ComponentStory::iter().collect::<Vec<_>>();
 44
 45        ctrlc::set_handler(move || {}).unwrap();
 46
 47        let result = FuzzySelect::new()
 48            .with_prompt("Choose a story to run:")
 49            .items(&stories)
 50            .interact();
 51
 52        let Ok(selection) = result else {
 53            dialoguer::console::Term::stderr().show_cursor().unwrap();
 54            std::process::exit(0);
 55        };
 56
 57        StorySelector::Component(stories[selection])
 58    });
 59    let theme_name = args.theme.unwrap_or("One Dark".to_string());
 60
 61    gpui::App::new().with_assets(Assets).run(move |cx| {
 62        load_embedded_fonts(cx).unwrap();
 63
 64        let mut store = SettingsStore::default();
 65        store
 66            .set_default_settings(default_settings().as_ref(), cx)
 67            .unwrap();
 68        cx.set_global(store);
 69
 70        theme::init(theme::LoadThemes::All(Box::new(Assets)), cx);
 71
 72        let selector = story_selector;
 73
 74        let theme_registry = ThemeRegistry::global(cx);
 75        let mut theme_settings = ThemeSettings::get_global(cx).clone();
 76        theme_settings.active_theme = theme_registry.get(&theme_name).unwrap();
 77        ThemeSettings::override_global(theme_settings, cx);
 78
 79        language::init(cx);
 80        editor::init(cx);
 81
 82        let _window = cx.open_window(
 83            WindowOptions {
 84                bounds: WindowBounds::Fixed(Bounds {
 85                    origin: Default::default(),
 86                    size: size(px(1500.), px(780.)).into(),
 87                }),
 88                ..Default::default()
 89            },
 90            move |cx| {
 91                let ui_font_size = ThemeSettings::get_global(cx).ui_font_size;
 92                cx.set_rem_size(ui_font_size);
 93
 94                cx.new_view(|cx| StoryWrapper::new(selector.story(cx)))
 95            },
 96        );
 97
 98        cx.activate(true);
 99    });
100}
101
102#[derive(Clone)]
103pub struct StoryWrapper {
104    story: AnyView,
105}
106
107impl StoryWrapper {
108    pub(crate) fn new(story: AnyView) -> Self {
109        Self { story }
110    }
111}
112
113impl Render for StoryWrapper {
114    fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
115        div()
116            .flex()
117            .flex_col()
118            .size_full()
119            .font("Zed Mono")
120            .child(self.story.clone())
121    }
122}
123
124fn load_embedded_fonts(cx: &AppContext) -> gpui::Result<()> {
125    let font_paths = cx.asset_source().list("fonts")?;
126    let mut embedded_fonts = Vec::new();
127    for font_path in font_paths {
128        if font_path.ends_with(".ttf") {
129            let font_bytes = cx.asset_source().load(&font_path)?;
130            embedded_fonts.push(font_bytes);
131        }
132    }
133
134    cx.text_system().add_fonts(embedded_fonts)
135}