Cargo.lock 🔗
@@ -9060,6 +9060,7 @@ dependencies = [
"anyhow",
"chrono",
"gpui3",
+ "itertools 0.11.0",
"rand 0.8.5",
"serde",
"settings",
Marshall Bowers created
Cargo.lock | 1
crates/storybook2/src/stories.rs | 1
crates/storybook2/src/stories/components.rs | 23 -
crates/storybook2/src/stories/components/breadcrumb.rs | 54 --
crates/storybook2/src/stories/components/buffer.rs | 46 --
crates/storybook2/src/stories/components/chat_panel.rs | 56 --
crates/storybook2/src/stories/components/collab_panel.rs | 26 -
crates/storybook2/src/stories/components/command_palette.rs | 26 -
crates/storybook2/src/stories/components/context_menu.rs | 30 -
crates/storybook2/src/stories/components/facepile.rs | 35 -
crates/storybook2/src/stories/components/keybinding.rs | 74 ---
crates/storybook2/src/stories/components/language_selector.rs | 26 -
crates/storybook2/src/stories/components/multi_buffer.rs | 34 -
crates/storybook2/src/stories/components/palette.rs | 63 --
crates/storybook2/src/stories/components/panel.rs | 35 -
crates/storybook2/src/stories/components/project_panel.rs | 30 -
crates/storybook2/src/stories/components/recent_projects.rs | 26 -
crates/storybook2/src/stories/components/tab.rs | 101 ----
crates/storybook2/src/stories/components/tab_bar.rs | 56 --
crates/storybook2/src/stories/components/terminal.rs | 26 -
crates/storybook2/src/stories/components/theme_selector.rs | 26 -
crates/storybook2/src/stories/components/title_bar.rs | 26 -
crates/storybook2/src/stories/components/toast.rs | 30 -
crates/storybook2/src/stories/components/toolbar.rs | 79 ---
crates/storybook2/src/stories/components/traffic_lights.rs | 28 -
crates/storybook2/src/stories/components/workspace.rs | 22 -
crates/storybook2/src/story_selector.rs | 54 +-
crates/ui2/Cargo.toml | 3
crates/ui2/src/components/assistant_panel.rs | 2
crates/ui2/src/components/breadcrumb.rs | 58 ++
crates/ui2/src/components/buffer.rs | 51 ++
crates/ui2/src/components/chat_panel.rs | 61 ++
crates/ui2/src/components/collab_panel.rs | 30 +
crates/ui2/src/components/command_palette.rs | 30 +
crates/ui2/src/components/context_menu.rs | 36 +
crates/ui2/src/components/facepile.rs | 39 +
crates/ui2/src/components/keybinding.rs | 78 +++
crates/ui2/src/components/language_selector.rs | 30 +
crates/ui2/src/components/multi_buffer.rs | 38 +
crates/ui2/src/components/palette.rs | 69 +++
crates/ui2/src/components/panel.rs | 39 +
crates/ui2/src/components/project_panel.rs | 34 +
crates/ui2/src/components/recent_projects.rs | 30 +
crates/ui2/src/components/tab.rs | 106 +++++
crates/ui2/src/components/tab_bar.rs | 60 ++
crates/ui2/src/components/terminal.rs | 30 +
crates/ui2/src/components/theme_selector.rs | 30 +
crates/ui2/src/components/title_bar.rs | 30 +
crates/ui2/src/components/toast.rs | 36 +
crates/ui2/src/components/toolbar.rs | 85 ++++
crates/ui2/src/components/traffic_lights.rs | 32 +
crates/ui2/src/components/workspace.rs | 26 +
52 files changed, 1,085 insertions(+), 1,012 deletions(-)
@@ -9060,6 +9060,7 @@ dependencies = [
"anyhow",
"chrono",
"gpui3",
+ "itertools 0.11.0",
"rand 0.8.5",
"serde",
"settings",
@@ -1,3 +1,2 @@
-pub mod components;
pub mod elements;
pub mod kitchen_sink;
@@ -1,23 +0,0 @@
-pub mod breadcrumb;
-pub mod buffer;
-pub mod chat_panel;
-pub mod collab_panel;
-pub mod command_palette;
-pub mod context_menu;
-pub mod facepile;
-pub mod keybinding;
-pub mod language_selector;
-pub mod multi_buffer;
-pub mod palette;
-pub mod panel;
-pub mod project_panel;
-pub mod recent_projects;
-pub mod tab;
-pub mod tab_bar;
-pub mod terminal;
-pub mod theme_selector;
-pub mod title_bar;
-pub mod toast;
-pub mod toolbar;
-pub mod traffic_lights;
-pub mod workspace;
@@ -1,54 +0,0 @@
-use std::marker::PhantomData;
-use std::path::PathBuf;
-use std::str::FromStr;
-
-use ui::prelude::*;
-use ui::{Breadcrumb, HighlightedText, Symbol};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct BreadcrumbStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> BreadcrumbStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- let theme = theme(cx);
-
- Story::container(cx)
- .child(Story::title_for::<_, Breadcrumb<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Breadcrumb::new(
- PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
- vec![
- Symbol(vec![
- HighlightedText {
- text: "impl ".to_string(),
- color: HighlightColor::Keyword.hsla(&theme),
- },
- HighlightedText {
- text: "BreadcrumbStory".to_string(),
- color: HighlightColor::Function.hsla(&theme),
- },
- ]),
- Symbol(vec![
- HighlightedText {
- text: "fn ".to_string(),
- color: HighlightColor::Keyword.hsla(&theme),
- },
- HighlightedText {
- text: "render".to_string(),
- color: HighlightColor::Function.hsla(&theme),
- },
- ]),
- ],
- ))
- }
-}
@@ -1,46 +0,0 @@
-use std::marker::PhantomData;
-
-use gpui3::rems;
-use ui::prelude::*;
-use ui::{
- empty_buffer_example, hello_world_rust_buffer_example,
- hello_world_rust_buffer_with_status_example, Buffer,
-};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct BufferStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> BufferStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- let theme = theme(cx);
-
- Story::container(cx)
- .child(Story::title_for::<_, Buffer<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(div().w(rems(64.)).h_96().child(empty_buffer_example()))
- .child(Story::label(cx, "Hello World (Rust)"))
- .child(
- div()
- .w(rems(64.))
- .h_96()
- .child(hello_world_rust_buffer_example(&theme)),
- )
- .child(Story::label(cx, "Hello World (Rust) with Status"))
- .child(
- div()
- .w(rems(64.))
- .h_96()
- .child(hello_world_rust_buffer_with_status_example(&theme)),
- )
- }
-}
@@ -1,56 +0,0 @@
-use std::marker::PhantomData;
-
-use chrono::DateTime;
-use ui::prelude::*;
-use ui::{ChatMessage, ChatPanel, Panel};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct ChatPanelStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> ChatPanelStory<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::<_, ChatPanel<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Panel::new(
- ScrollState::default(),
- |_, _| vec![ChatPanel::new(ScrollState::default()).into_any()],
- Box::new(()),
- ))
- .child(Story::label(cx, "With Mesages"))
- .child(Panel::new(
- ScrollState::default(),
- |_, _| {
- vec![ChatPanel::new(ScrollState::default())
- .with_messages(vec![
- ChatMessage::new(
- "osiewicz".to_string(),
- "is this thing on?".to_string(),
- DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
- .unwrap()
- .naive_local(),
- ),
- ChatMessage::new(
- "maxdeviant".to_string(),
- "Reading you loud and clear!".to_string(),
- DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
- .unwrap()
- .naive_local(),
- ),
- ])
- .into_any()]
- },
- Box::new(()),
- ))
- }
-}
@@ -1,26 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::CollabPanel;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct CollabPanelStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> CollabPanelStory<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::<_, CollabPanel<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(CollabPanel::new(ScrollState::default()))
- }
-}
@@ -1,26 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::CommandPalette;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct CommandPaletteStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> CommandPaletteStory<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::<_, CommandPalette<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(CommandPalette::new(ScrollState::default()))
- }
-}
@@ -1,30 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{ContextMenu, ContextMenuItem, Label};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct ContextMenuStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> ContextMenuStory<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::<_, ContextMenu<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(ContextMenu::new([
- ContextMenuItem::header("Section header"),
- ContextMenuItem::Separator,
- ContextMenuItem::entry(Label::new("Some entry")),
- ]))
- }
-}
@@ -1,35 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{static_players, Facepile};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct FacepileStory<S: 'static + Send + Sync> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync> FacepileStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- let players = static_players();
-
- Story::container(cx)
- .child(Story::title_for::<_, Facepile<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(
- div()
- .flex()
- .gap_3()
- .child(Facepile::new(players.clone().into_iter().take(1)))
- .child(Facepile::new(players.clone().into_iter().take(2)))
- .child(Facepile::new(players.clone().into_iter().take(3))),
- )
- }
-}
@@ -1,74 +0,0 @@
-use std::marker::PhantomData;
-
-use itertools::Itertools;
-use strum::IntoEnumIterator;
-use ui::prelude::*;
-use ui::{Keybinding, ModifierKey, ModifierKeys};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct KeybindingStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> KeybindingStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- let all_modifier_permutations = ModifierKey::iter().permutations(2);
-
- Story::container(cx)
- .child(Story::title_for::<_, Keybinding<S>>(cx))
- .child(Story::label(cx, "Single Key"))
- .child(Keybinding::new("Z".to_string(), ModifierKeys::new()))
- .child(Story::label(cx, "Single Key with Modifier"))
- .child(
- div()
- .flex()
- .gap_3()
- .children(ModifierKey::iter().map(|modifier| {
- Keybinding::new("C".to_string(), ModifierKeys::new().add(modifier))
- })),
- )
- .child(Story::label(cx, "Single Key with Modifier (Permuted)"))
- .child(
- div().flex().flex_col().children(
- all_modifier_permutations
- .chunks(4)
- .into_iter()
- .map(|chunk| {
- div()
- .flex()
- .gap_4()
- .py_3()
- .children(chunk.map(|permutation| {
- let mut modifiers = ModifierKeys::new();
-
- for modifier in permutation {
- modifiers = modifiers.add(modifier);
- }
-
- Keybinding::new("X".to_string(), modifiers)
- }))
- }),
- ),
- )
- .child(Story::label(cx, "Single Key with All Modifiers"))
- .child(Keybinding::new("Z".to_string(), ModifierKeys::all()))
- .child(Story::label(cx, "Chord"))
- .child(Keybinding::new_chord(
- ("A".to_string(), ModifierKeys::new()),
- ("Z".to_string(), ModifierKeys::new()),
- ))
- .child(Story::label(cx, "Chord with Modifier"))
- .child(Keybinding::new_chord(
- ("A".to_string(), ModifierKeys::new().control(true)),
- ("Z".to_string(), ModifierKeys::new().shift(true)),
- ))
- }
-}
@@ -1,26 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::LanguageSelector;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct LanguageSelectorStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> LanguageSelectorStory<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::<_, LanguageSelector<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(LanguageSelector::new())
- }
-}
@@ -1,34 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{hello_world_rust_buffer_example, MultiBuffer};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct MultiBufferStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> MultiBufferStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- let theme = theme(cx);
-
- Story::container(cx)
- .child(Story::title_for::<_, MultiBuffer<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(MultiBuffer::new(vec![
- hello_world_rust_buffer_example(&theme),
- hello_world_rust_buffer_example(&theme),
- hello_world_rust_buffer_example(&theme),
- hello_world_rust_buffer_example(&theme),
- hello_world_rust_buffer_example(&theme),
- ]))
- }
-}
@@ -1,63 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{Keybinding, ModifierKeys, Palette, PaletteItem};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct PaletteStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> PaletteStory<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::<_, Palette<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Palette::new(ScrollState::default()))
- .child(Story::label(cx, "With Items"))
- .child(
- Palette::new(ScrollState::default())
- .placeholder("Execute a command...")
- .items(vec![
- PaletteItem::new("theme selector: toggle").keybinding(
- Keybinding::new_chord(
- ("k".to_string(), ModifierKeys::new().command(true)),
- ("t".to_string(), ModifierKeys::new().command(true)),
- ),
- ),
- PaletteItem::new("assistant: inline assist").keybinding(Keybinding::new(
- "enter".to_string(),
- ModifierKeys::new().command(true),
- )),
- PaletteItem::new("assistant: quote selection").keybinding(Keybinding::new(
- ">".to_string(),
- ModifierKeys::new().command(true),
- )),
- PaletteItem::new("assistant: toggle focus").keybinding(Keybinding::new(
- "?".to_string(),
- ModifierKeys::new().command(true),
- )),
- PaletteItem::new("auto update: check"),
- PaletteItem::new("auto update: view release notes"),
- PaletteItem::new("branches: open recent").keybinding(Keybinding::new(
- "b".to_string(),
- ModifierKeys::new().command(true).alt(true),
- )),
- PaletteItem::new("chat panel: toggle focus"),
- PaletteItem::new("cli: install"),
- PaletteItem::new("client: sign in"),
- PaletteItem::new("client: sign out"),
- PaletteItem::new("editor: cancel")
- .keybinding(Keybinding::new("escape".to_string(), ModifierKeys::new())),
- ]),
- )
- }
-}
@@ -1,35 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{Label, Panel};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct PanelStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> PanelStory<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::<_, Panel<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Panel::new(
- ScrollState::default(),
- |_, _| {
- vec![div()
- .overflow_y_scroll(ScrollState::default())
- .children((0..100).map(|ix| Label::new(format!("Item {}", ix + 1))))
- .into_any()]
- },
- Box::new(()),
- ))
- }
-}
@@ -1,30 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{Panel, ProjectPanel};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct ProjectPanelStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> ProjectPanelStory<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::<_, ProjectPanel<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Panel::new(
- ScrollState::default(),
- |_, _| vec![ProjectPanel::new(ScrollState::default()).into_any()],
- Box::new(()),
- ))
- }
-}
@@ -1,26 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::RecentProjects;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct RecentProjectsStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> RecentProjectsStory<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::<_, RecentProjects<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(RecentProjects::new())
- }
-}
@@ -1,101 +0,0 @@
-use std::marker::PhantomData;
-
-use strum::IntoEnumIterator;
-use ui::prelude::*;
-use ui::{h_stack, v_stack, Tab};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct TabStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> TabStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- let git_statuses = GitStatus::iter();
- let fs_statuses = FileSystemStatus::iter();
-
- Story::container(cx)
- .child(Story::title_for::<_, Tab<S>>(cx))
- .child(
- h_stack().child(
- v_stack()
- .gap_2()
- .child(Story::label(cx, "Default"))
- .child(Tab::new()),
- ),
- )
- .child(
- h_stack().child(
- v_stack().gap_2().child(Story::label(cx, "Current")).child(
- h_stack()
- .gap_4()
- .child(Tab::new().title("Current".to_string()).current(true))
- .child(Tab::new().title("Not Current".to_string()).current(false)),
- ),
- ),
- )
- .child(
- h_stack().child(
- v_stack()
- .gap_2()
- .child(Story::label(cx, "Titled"))
- .child(Tab::new().title("label".to_string())),
- ),
- )
- .child(
- h_stack().child(
- v_stack()
- .gap_2()
- .child(Story::label(cx, "With Icon"))
- .child(
- Tab::new()
- .title("label".to_string())
- .icon(Some(ui::Icon::Envelope)),
- ),
- ),
- )
- .child(
- h_stack().child(
- v_stack()
- .gap_2()
- .child(Story::label(cx, "Close Side"))
- .child(
- h_stack()
- .gap_4()
- .child(
- Tab::new()
- .title("Left".to_string())
- .close_side(IconSide::Left),
- )
- .child(Tab::new().title("Right".to_string())),
- ),
- ),
- )
- .child(
- v_stack()
- .gap_2()
- .child(Story::label(cx, "Git Status"))
- .child(h_stack().gap_4().children(git_statuses.map(|git_status| {
- Tab::new()
- .title(git_status.to_string())
- .git_status(git_status)
- }))),
- )
- .child(
- v_stack()
- .gap_2()
- .child(Story::label(cx, "File System Status"))
- .child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
- Tab::new().title(fs_status.to_string()).fs_status(fs_status)
- }))),
- )
- }
-}
@@ -1,56 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{Tab, TabBar};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct TabBarStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> TabBarStory<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::<_, TabBar<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(TabBar::new(vec![
- Tab::new()
- .title("Cargo.toml".to_string())
- .current(false)
- .git_status(GitStatus::Modified),
- Tab::new()
- .title("Channels Panel".to_string())
- .current(false),
- Tab::new()
- .title("channels_panel.rs".to_string())
- .current(true)
- .git_status(GitStatus::Modified),
- Tab::new()
- .title("workspace.rs".to_string())
- .current(false)
- .git_status(GitStatus::Modified),
- Tab::new()
- .title("icon_button.rs".to_string())
- .current(false),
- Tab::new()
- .title("storybook.rs".to_string())
- .current(false)
- .git_status(GitStatus::Created),
- Tab::new().title("theme.rs".to_string()).current(false),
- Tab::new()
- .title("theme_registry.rs".to_string())
- .current(false),
- Tab::new()
- .title("styleable_helpers.rs".to_string())
- .current(false),
- ]))
- }
-}
@@ -1,26 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::Terminal;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct TerminalStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> TerminalStory<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::<_, Terminal<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Terminal::new())
- }
-}
@@ -1,26 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::ThemeSelector;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct ThemeSelectorStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> ThemeSelectorStory<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::<_, ThemeSelector<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(ThemeSelector::new())
- }
-}
@@ -1,26 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::TitleBar;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct TitleBarStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> TitleBarStory<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::<_, TitleBar<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(TitleBar::new(cx))
- }
-}
@@ -1,30 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::{Label, Toast, ToastOrigin};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct ToastStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> ToastStory<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::<_, Toast<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Toast::new(
- ToastOrigin::Bottom,
- |_, _| vec![Label::new("label").into_any()],
- Box::new(()),
- ))
- }
-}
@@ -1,79 +0,0 @@
-use std::marker::PhantomData;
-use std::path::PathBuf;
-use std::str::FromStr;
-use std::sync::Arc;
-
-use ui::prelude::*;
-use ui::{theme, Breadcrumb, HighlightColor, HighlightedText, Icon, IconButton, Symbol, Toolbar};
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct ToolbarStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> ToolbarStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- let theme = theme(cx);
-
- struct LeftItemsPayload {
- pub theme: Arc<Theme>,
- }
-
- Story::container(cx)
- .child(Story::title_for::<_, Toolbar<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(Toolbar::new(
- |_, payload| {
- let payload = payload.downcast_ref::<LeftItemsPayload>().unwrap();
-
- let theme = payload.theme.clone();
-
- vec![Breadcrumb::new(
- PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
- vec![
- Symbol(vec![
- HighlightedText {
- text: "impl ".to_string(),
- color: HighlightColor::Keyword.hsla(&theme),
- },
- HighlightedText {
- text: "ToolbarStory".to_string(),
- color: HighlightColor::Function.hsla(&theme),
- },
- ]),
- Symbol(vec![
- HighlightedText {
- text: "fn ".to_string(),
- color: HighlightColor::Keyword.hsla(&theme),
- },
- HighlightedText {
- text: "render".to_string(),
- color: HighlightColor::Function.hsla(&theme),
- },
- ]),
- ],
- )
- .into_any()]
- },
- Box::new(LeftItemsPayload {
- theme: theme.clone(),
- }),
- |_, _| {
- vec![
- IconButton::new(Icon::InlayHint).into_any(),
- IconButton::new(Icon::MagnifyingGlass).into_any(),
- IconButton::new(Icon::MagicWand).into_any(),
- ]
- },
- Box::new(()),
- ))
- }
-}
@@ -1,28 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::TrafficLights;
-
-use crate::story::Story;
-
-#[derive(Element)]
-pub struct TrafficLightsStory<S: 'static + Send + Sync> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync> TrafficLightsStory<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::<_, TrafficLights<S>>(cx))
- .child(Story::label(cx, "Default"))
- .child(TrafficLights::new())
- .child(Story::label(cx, "Unfocused"))
- .child(TrafficLights::new().window_has_focus(false))
- }
-}
@@ -1,22 +0,0 @@
-use std::marker::PhantomData;
-
-use ui::prelude::*;
-use ui::WorkspaceElement;
-
-#[derive(Element)]
-pub struct WorkspaceStory<S: 'static + Send + Sync + Clone> {
- state_type: PhantomData<S>,
-}
-
-impl<S: 'static + Send + Sync + Clone> WorkspaceStory<S> {
- pub fn new() -> Self {
- Self {
- state_type: PhantomData,
- }
- }
-
- fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
- // Just render the workspace without any story boilerplate.
- WorkspaceElement::new()
- }
-}
@@ -68,39 +68,31 @@ pub enum ComponentStory {
impl ComponentStory {
pub fn story<S: 'static + Send + Sync + Clone>(&self) -> AnyElement<S> {
- use crate::stories::components;
-
match self {
Self::AssistantPanel => ui::AssistantPanelStory::new().into_any(),
- Self::Buffer => components::buffer::BufferStory::new().into_any(),
- Self::Breadcrumb => components::breadcrumb::BreadcrumbStory::new().into_any(),
- Self::ChatPanel => components::chat_panel::ChatPanelStory::new().into_any(),
- Self::CollabPanel => components::collab_panel::CollabPanelStory::new().into_any(),
- Self::CommandPalette => {
- components::command_palette::CommandPaletteStory::new().into_any()
- }
- Self::ContextMenu => components::context_menu::ContextMenuStory::new().into_any(),
- Self::Facepile => components::facepile::FacepileStory::new().into_any(),
- Self::Keybinding => components::keybinding::KeybindingStory::new().into_any(),
- Self::LanguageSelector => {
- components::language_selector::LanguageSelectorStory::new().into_any()
- }
- Self::MultiBuffer => components::multi_buffer::MultiBufferStory::new().into_any(),
- Self::Palette => components::palette::PaletteStory::new().into_any(),
- Self::Panel => components::panel::PanelStory::new().into_any(),
- Self::ProjectPanel => components::project_panel::ProjectPanelStory::new().into_any(),
- Self::RecentProjects => {
- components::recent_projects::RecentProjectsStory::new().into_any()
- }
- Self::Tab => components::tab::TabStory::new().into_any(),
- Self::TabBar => components::tab_bar::TabBarStory::new().into_any(),
- Self::Terminal => components::terminal::TerminalStory::new().into_any(),
- Self::ThemeSelector => components::theme_selector::ThemeSelectorStory::new().into_any(),
- Self::TitleBar => components::title_bar::TitleBarStory::new().into_any(),
- Self::Toast => components::toast::ToastStory::new().into_any(),
- Self::Toolbar => components::toolbar::ToolbarStory::new().into_any(),
- Self::TrafficLights => components::traffic_lights::TrafficLightsStory::new().into_any(),
- Self::Workspace => components::workspace::WorkspaceStory::new().into_any(),
+ Self::Buffer => ui::BufferStory::new().into_any(),
+ Self::Breadcrumb => ui::BreadcrumbStory::new().into_any(),
+ Self::ChatPanel => ui::ChatPanelStory::new().into_any(),
+ Self::CollabPanel => ui::CollabPanelStory::new().into_any(),
+ Self::CommandPalette => ui::CommandPaletteStory::new().into_any(),
+ Self::ContextMenu => ui::ContextMenuStory::new().into_any(),
+ Self::Facepile => ui::FacepileStory::new().into_any(),
+ Self::Keybinding => ui::KeybindingStory::new().into_any(),
+ Self::LanguageSelector => ui::LanguageSelectorStory::new().into_any(),
+ Self::MultiBuffer => ui::MultiBufferStory::new().into_any(),
+ Self::Palette => ui::PaletteStory::new().into_any(),
+ Self::Panel => ui::PanelStory::new().into_any(),
+ Self::ProjectPanel => ui::ProjectPanelStory::new().into_any(),
+ Self::RecentProjects => ui::RecentProjectsStory::new().into_any(),
+ Self::Tab => ui::TabStory::new().into_any(),
+ Self::TabBar => ui::TabBarStory::new().into_any(),
+ Self::Terminal => ui::TerminalStory::new().into_any(),
+ Self::ThemeSelector => ui::ThemeSelectorStory::new().into_any(),
+ Self::TitleBar => ui::TitleBarStory::new().into_any(),
+ Self::Toast => ui::ToastStory::new().into_any(),
+ Self::Toolbar => ui::ToolbarStory::new().into_any(),
+ Self::TrafficLights => ui::TrafficLightsStory::new().into_any(),
+ Self::Workspace => ui::WorkspaceStory::new().into_any(),
}
}
}
@@ -8,6 +8,7 @@ publish = false
anyhow.workspace = true
chrono = "0.4"
gpui3 = { path = "../gpui3" }
+itertools = { version = "0.11.0", optional = true }
serde.workspace = true
settings = { path = "../settings" }
smallvec.workspace = true
@@ -17,4 +18,4 @@ rand = "0.8"
[features]
default = ["stories"]
-stories = []
+stories = ["dep:itertools"]
@@ -94,7 +94,7 @@ pub use stories::*;
#[cfg(feature = "stories")]
mod stories {
- use crate::story::Story;
+ use crate::Story;
use super::*;
@@ -75,3 +75,61 @@ impl<S: 'static + Send + Sync + Clone> Breadcrumb<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use std::str::FromStr;
+
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct BreadcrumbStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> BreadcrumbStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let theme = theme(cx);
+
+ Story::container(cx)
+ .child(Story::title_for::<_, Breadcrumb<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Breadcrumb::new(
+ PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
+ vec![
+ Symbol(vec![
+ HighlightedText {
+ text: "impl ".to_string(),
+ color: HighlightColor::Keyword.hsla(&theme),
+ },
+ HighlightedText {
+ text: "BreadcrumbStory".to_string(),
+ color: HighlightColor::Function.hsla(&theme),
+ },
+ ]),
+ Symbol(vec![
+ HighlightedText {
+ text: "fn ".to_string(),
+ color: HighlightColor::Keyword.hsla(&theme),
+ },
+ HighlightedText {
+ text: "render".to_string(),
+ color: HighlightColor::Function.hsla(&theme),
+ },
+ ]),
+ ],
+ ))
+ }
+ }
+}
@@ -236,3 +236,54 @@ impl<S: 'static + Send + Sync + Clone> Buffer<S> {
.children(rows)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use gpui3::rems;
+
+ use crate::{
+ empty_buffer_example, hello_world_rust_buffer_example,
+ hello_world_rust_buffer_with_status_example, Story,
+ };
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct BufferStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> BufferStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let theme = theme(cx);
+
+ Story::container(cx)
+ .child(Story::title_for::<_, Buffer<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(div().w(rems(64.)).h_96().child(empty_buffer_example()))
+ .child(Story::label(cx, "Hello World (Rust)"))
+ .child(
+ div()
+ .w(rems(64.))
+ .h_96()
+ .child(hello_world_rust_buffer_example(&theme)),
+ )
+ .child(Story::label(cx, "Hello World (Rust) with Status"))
+ .child(
+ div()
+ .w(rems(64.))
+ .h_96()
+ .child(hello_world_rust_buffer_with_status_example(&theme)),
+ )
+ }
+ }
+}
@@ -106,3 +106,64 @@ impl<S: 'static + Send + Sync + Clone> ChatMessage<S> {
.child(div().child(Label::new(self.text.clone())))
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use chrono::DateTime;
+
+ use crate::{Panel, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct ChatPanelStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> ChatPanelStory<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::<_, ChatPanel<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Panel::new(
+ ScrollState::default(),
+ |_, _| vec![ChatPanel::new(ScrollState::default()).into_any()],
+ Box::new(()),
+ ))
+ .child(Story::label(cx, "With Mesages"))
+ .child(Panel::new(
+ ScrollState::default(),
+ |_, _| {
+ vec![ChatPanel::new(ScrollState::default())
+ .with_messages(vec![
+ ChatMessage::new(
+ "osiewicz".to_string(),
+ "is this thing on?".to_string(),
+ DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
+ .unwrap()
+ .naive_local(),
+ ),
+ ChatMessage::new(
+ "maxdeviant".to_string(),
+ "Reading you loud and clear!".to_string(),
+ DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
+ .unwrap()
+ .naive_local(),
+ ),
+ ])
+ .into_any()]
+ },
+ Box::new(()),
+ ))
+ }
+ }
+}
@@ -158,3 +158,33 @@ impl<S: 'static + Send + Sync + Clone> CollabPanel<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct CollabPanelStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> CollabPanelStory<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::<_, CollabPanel<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(CollabPanel::new(ScrollState::default()))
+ }
+ }
+}
@@ -27,3 +27,33 @@ impl<S: 'static + Send + Sync + Clone> CommandPalette<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct CommandPaletteStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> CommandPaletteStory<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::<_, CommandPalette<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(CommandPalette::new(ScrollState::default()))
+ }
+ }
+}
@@ -65,3 +65,39 @@ impl<S: 'static + Send + Sync + Clone> ContextMenu<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use std::marker::PhantomData;
+
+ use crate::story::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct ContextMenuStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> ContextMenuStory<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::<_, ContextMenu<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(ContextMenu::new([
+ ContextMenuItem::header("Section header"),
+ ContextMenuItem::Separator,
+ ContextMenuItem::entry(Label::new("Some entry")),
+ ]))
+ }
+ }
+}
@@ -30,3 +30,42 @@ impl<S: 'static + Send + Sync> Facepile<S> {
div().p_1().flex().items_center().children(player_list)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::{static_players, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct FacepileStory<S: 'static + Send + Sync> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync> FacepileStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let players = static_players();
+
+ Story::container(cx)
+ .child(Story::title_for::<_, Facepile<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(
+ div()
+ .flex()
+ .gap_3()
+ .child(Facepile::new(players.clone().into_iter().take(1)))
+ .child(Facepile::new(players.clone().into_iter().take(2)))
+ .child(Facepile::new(players.clone().into_iter().take(3))),
+ )
+ }
+ }
+}
@@ -165,3 +165,81 @@ impl ModifierKeys {
self
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use itertools::Itertools;
+
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct KeybindingStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> KeybindingStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let all_modifier_permutations = ModifierKey::iter().permutations(2);
+
+ Story::container(cx)
+ .child(Story::title_for::<_, Keybinding<S>>(cx))
+ .child(Story::label(cx, "Single Key"))
+ .child(Keybinding::new("Z".to_string(), ModifierKeys::new()))
+ .child(Story::label(cx, "Single Key with Modifier"))
+ .child(
+ div()
+ .flex()
+ .gap_3()
+ .children(ModifierKey::iter().map(|modifier| {
+ Keybinding::new("C".to_string(), ModifierKeys::new().add(modifier))
+ })),
+ )
+ .child(Story::label(cx, "Single Key with Modifier (Permuted)"))
+ .child(
+ div().flex().flex_col().children(
+ all_modifier_permutations
+ .chunks(4)
+ .into_iter()
+ .map(|chunk| {
+ div()
+ .flex()
+ .gap_4()
+ .py_3()
+ .children(chunk.map(|permutation| {
+ let mut modifiers = ModifierKeys::new();
+
+ for modifier in permutation {
+ modifiers = modifiers.add(modifier);
+ }
+
+ Keybinding::new("X".to_string(), modifiers)
+ }))
+ }),
+ ),
+ )
+ .child(Story::label(cx, "Single Key with All Modifiers"))
+ .child(Keybinding::new("Z".to_string(), ModifierKeys::all()))
+ .child(Story::label(cx, "Chord"))
+ .child(Keybinding::new_chord(
+ ("A".to_string(), ModifierKeys::new()),
+ ("Z".to_string(), ModifierKeys::new()),
+ ))
+ .child(Story::label(cx, "Chord with Modifier"))
+ .child(Keybinding::new_chord(
+ ("A".to_string(), ModifierKeys::new().control(true)),
+ ("Z".to_string(), ModifierKeys::new().shift(true)),
+ ))
+ }
+ }
+}
@@ -38,3 +38,33 @@ impl<S: 'static + Send + Sync + Clone> LanguageSelector<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct LanguageSelectorStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> LanguageSelectorStory<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::<_, LanguageSelector<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(LanguageSelector::new())
+ }
+ }
+}
@@ -40,3 +40,41 @@ impl<S: 'static + Send + Sync + Clone> MultiBuffer<S> {
}))
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::{hello_world_rust_buffer_example, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct MultiBufferStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> MultiBufferStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let theme = theme(cx);
+
+ Story::container(cx)
+ .child(Story::title_for::<_, MultiBuffer<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(MultiBuffer::new(vec![
+ hello_world_rust_buffer_example(&theme),
+ hello_world_rust_buffer_example(&theme),
+ hello_world_rust_buffer_example(&theme),
+ hello_world_rust_buffer_example(&theme),
+ hello_world_rust_buffer_example(&theme),
+ ]))
+ }
+ }
+}
@@ -150,3 +150,72 @@ impl<S: 'static + Send + Sync + Clone> PaletteItem<S> {
.children(self.keybinding.clone())
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::{ModifierKeys, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct PaletteStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> PaletteStory<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::<_, Palette<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Palette::new(ScrollState::default()))
+ .child(Story::label(cx, "With Items"))
+ .child(
+ Palette::new(ScrollState::default())
+ .placeholder("Execute a command...")
+ .items(vec![
+ PaletteItem::new("theme selector: toggle").keybinding(
+ Keybinding::new_chord(
+ ("k".to_string(), ModifierKeys::new().command(true)),
+ ("t".to_string(), ModifierKeys::new().command(true)),
+ ),
+ ),
+ PaletteItem::new("assistant: inline assist").keybinding(
+ Keybinding::new(
+ "enter".to_string(),
+ ModifierKeys::new().command(true),
+ ),
+ ),
+ PaletteItem::new("assistant: quote selection").keybinding(
+ Keybinding::new(">".to_string(), ModifierKeys::new().command(true)),
+ ),
+ PaletteItem::new("assistant: toggle focus").keybinding(
+ Keybinding::new("?".to_string(), ModifierKeys::new().command(true)),
+ ),
+ PaletteItem::new("auto update: check"),
+ PaletteItem::new("auto update: view release notes"),
+ PaletteItem::new("branches: open recent").keybinding(Keybinding::new(
+ "b".to_string(),
+ ModifierKeys::new().command(true).alt(true),
+ )),
+ PaletteItem::new("chat panel: toggle focus"),
+ PaletteItem::new("cli: install"),
+ PaletteItem::new("client: sign in"),
+ PaletteItem::new("client: sign out"),
+ PaletteItem::new("editor: cancel").keybinding(Keybinding::new(
+ "escape".to_string(),
+ ModifierKeys::new(),
+ )),
+ ]),
+ )
+ }
+ }
+}
@@ -143,3 +143,42 @@ impl<S: 'static + Send + Sync> Panel<S> {
panel_base.children_any((self.children)(cx, self.payload.as_ref()))
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::{Label, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct PanelStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> PanelStory<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::<_, Panel<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Panel::new(
+ ScrollState::default(),
+ |_, _| {
+ vec![div()
+ .overflow_y_scroll(ScrollState::default())
+ .children((0..100).map(|ix| Label::new(format!("Item {}", ix + 1))))
+ .into_any()]
+ },
+ Box::new(()),
+ ))
+ }
+ }
+}
@@ -56,3 +56,37 @@ impl<S: 'static + Send + Sync + Clone> ProjectPanel<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::{Panel, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct ProjectPanelStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> ProjectPanelStory<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::<_, ProjectPanel<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Panel::new(
+ ScrollState::default(),
+ |_, _| vec![ProjectPanel::new(ScrollState::default()).into_any()],
+ Box::new(()),
+ ))
+ }
+ }
+}
@@ -34,3 +34,33 @@ impl<S: 'static + Send + Sync + Clone> RecentProjects<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct RecentProjectsStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> RecentProjectsStory<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::<_, RecentProjects<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(RecentProjects::new())
+ }
+ }
+}
@@ -133,3 +133,109 @@ impl<S: 'static + Send + Sync + Clone> Tab<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use strum::IntoEnumIterator;
+
+ use crate::{h_stack, v_stack, Icon, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct TabStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> TabStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let git_statuses = GitStatus::iter();
+ let fs_statuses = FileSystemStatus::iter();
+
+ Story::container(cx)
+ .child(Story::title_for::<_, Tab<S>>(cx))
+ .child(
+ h_stack().child(
+ v_stack()
+ .gap_2()
+ .child(Story::label(cx, "Default"))
+ .child(Tab::new()),
+ ),
+ )
+ .child(
+ h_stack().child(
+ v_stack().gap_2().child(Story::label(cx, "Current")).child(
+ h_stack()
+ .gap_4()
+ .child(Tab::new().title("Current".to_string()).current(true))
+ .child(Tab::new().title("Not Current".to_string()).current(false)),
+ ),
+ ),
+ )
+ .child(
+ h_stack().child(
+ v_stack()
+ .gap_2()
+ .child(Story::label(cx, "Titled"))
+ .child(Tab::new().title("label".to_string())),
+ ),
+ )
+ .child(
+ h_stack().child(
+ v_stack()
+ .gap_2()
+ .child(Story::label(cx, "With Icon"))
+ .child(
+ Tab::new()
+ .title("label".to_string())
+ .icon(Some(Icon::Envelope)),
+ ),
+ ),
+ )
+ .child(
+ h_stack().child(
+ v_stack()
+ .gap_2()
+ .child(Story::label(cx, "Close Side"))
+ .child(
+ h_stack()
+ .gap_4()
+ .child(
+ Tab::new()
+ .title("Left".to_string())
+ .close_side(IconSide::Left),
+ )
+ .child(Tab::new().title("Right".to_string())),
+ ),
+ ),
+ )
+ .child(
+ v_stack()
+ .gap_2()
+ .child(Story::label(cx, "Git Status"))
+ .child(h_stack().gap_4().children(git_statuses.map(|git_status| {
+ Tab::new()
+ .title(git_status.to_string())
+ .git_status(git_status)
+ }))),
+ )
+ .child(
+ v_stack()
+ .gap_2()
+ .child(Story::label(cx, "File System Status"))
+ .child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
+ Tab::new().title(fs_status.to_string()).fs_status(fs_status)
+ }))),
+ )
+ }
+ }
+}
@@ -83,3 +83,63 @@ impl<S: 'static + Send + Sync + Clone> TabBar<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct TabBarStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> TabBarStory<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::<_, TabBar<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(TabBar::new(vec![
+ Tab::new()
+ .title("Cargo.toml".to_string())
+ .current(false)
+ .git_status(GitStatus::Modified),
+ Tab::new()
+ .title("Channels Panel".to_string())
+ .current(false),
+ Tab::new()
+ .title("channels_panel.rs".to_string())
+ .current(true)
+ .git_status(GitStatus::Modified),
+ Tab::new()
+ .title("workspace.rs".to_string())
+ .current(false)
+ .git_status(GitStatus::Modified),
+ Tab::new()
+ .title("icon_button.rs".to_string())
+ .current(false),
+ Tab::new()
+ .title("storybook.rs".to_string())
+ .current(false)
+ .git_status(GitStatus::Created),
+ Tab::new().title("theme.rs".to_string()).current(false),
+ Tab::new()
+ .title("theme_registry.rs".to_string())
+ .current(false),
+ Tab::new()
+ .title("styleable_helpers.rs".to_string())
+ .current(false),
+ ]))
+ }
+ }
+}
@@ -87,3 +87,33 @@ impl<S: 'static + Send + Sync + Clone> Terminal<S> {
))
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct TerminalStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> TerminalStory<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::<_, Terminal<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Terminal::new())
+ }
+ }
+}
@@ -39,3 +39,33 @@ impl<S: 'static + Send + Sync + Clone> ThemeSelector<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct ThemeSelectorStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> ThemeSelectorStory<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::<_, ThemeSelector<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(ThemeSelector::new())
+ }
+ }
+}
@@ -117,3 +117,33 @@ impl<S: 'static + Send + Sync + Clone> TitleBar<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct TitleBarStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> TitleBarStory<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::<_, TitleBar<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(TitleBar::new(cx))
+ }
+ }
+}
@@ -65,3 +65,39 @@ impl<S: 'static + Send + Sync> Toast<S> {
.children_any((self.children)(cx, self.payload.as_ref()))
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use std::marker::PhantomData;
+
+ use crate::{Label, Story};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct ToastStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> ToastStory<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::<_, Toast<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Toast::new(
+ ToastOrigin::Bottom,
+ |_, _| vec![Label::new("label").into_any()],
+ Box::new(()),
+ ))
+ }
+ }
+}
@@ -47,3 +47,88 @@ impl<S: 'static + Send + Sync> Toolbar<S> {
)
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use std::marker::PhantomData;
+ use std::path::PathBuf;
+ use std::str::FromStr;
+ use std::sync::Arc;
+
+ use crate::{Breadcrumb, HighlightedText, Icon, IconButton, Story, Symbol};
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct ToolbarStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> ToolbarStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ let theme = theme(cx);
+
+ struct LeftItemsPayload {
+ pub theme: Arc<Theme>,
+ }
+
+ Story::container(cx)
+ .child(Story::title_for::<_, Toolbar<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(Toolbar::new(
+ |_, payload| {
+ let payload = payload.downcast_ref::<LeftItemsPayload>().unwrap();
+
+ let theme = payload.theme.clone();
+
+ vec![Breadcrumb::new(
+ PathBuf::from_str("crates/ui/src/components/toolbar.rs").unwrap(),
+ vec![
+ Symbol(vec![
+ HighlightedText {
+ text: "impl ".to_string(),
+ color: HighlightColor::Keyword.hsla(&theme),
+ },
+ HighlightedText {
+ text: "ToolbarStory".to_string(),
+ color: HighlightColor::Function.hsla(&theme),
+ },
+ ]),
+ Symbol(vec![
+ HighlightedText {
+ text: "fn ".to_string(),
+ color: HighlightColor::Keyword.hsla(&theme),
+ },
+ HighlightedText {
+ text: "render".to_string(),
+ color: HighlightColor::Function.hsla(&theme),
+ },
+ ]),
+ ],
+ )
+ .into_any()]
+ },
+ Box::new(LeftItemsPayload {
+ theme: theme.clone(),
+ }),
+ |_, _| {
+ vec![
+ IconButton::new(Icon::InlayHint).into_any(),
+ IconButton::new(Icon::MagnifyingGlass).into_any(),
+ IconButton::new(Icon::MagicWand).into_any(),
+ ]
+ },
+ Box::new(()),
+ ))
+ }
+ }
+}
@@ -82,3 +82,35 @@ impl<S: 'static + Send + Sync> TrafficLights<S> {
))
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use crate::Story;
+
+ use super::*;
+
+ #[derive(Element)]
+ pub struct TrafficLightsStory<S: 'static + Send + Sync> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync> TrafficLightsStory<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::<_, TrafficLights<S>>(cx))
+ .child(Story::label(cx, "Default"))
+ .child(TrafficLights::new())
+ .child(Story::label(cx, "Unfocused"))
+ .child(TrafficLights::new().window_has_focus(false))
+ }
+ }
+}
@@ -195,3 +195,29 @@ impl<S: 'static + Send + Sync + Clone> WorkspaceElement<S> {
))
}
}
+
+#[cfg(feature = "stories")]
+pub use stories::*;
+
+#[cfg(feature = "stories")]
+mod stories {
+ use super::*;
+
+ #[derive(Element)]
+ pub struct WorkspaceStory<S: 'static + Send + Sync + Clone> {
+ state_type: PhantomData<S>,
+ }
+
+ impl<S: 'static + Send + Sync + Clone> WorkspaceStory<S> {
+ pub fn new() -> Self {
+ Self {
+ state_type: PhantomData,
+ }
+ }
+
+ fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+ // Just render the workspace without any story boilerplate.
+ WorkspaceElement::new()
+ }
+ }
+}