diff --git a/crates/storybook2/src/stories/components.rs b/crates/storybook2/src/stories/components.rs index d6750c3b84..b7f008ac08 100644 --- a/crates/storybook2/src/stories/components.rs +++ b/crates/storybook2/src/stories/components.rs @@ -4,6 +4,7 @@ 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 palette; diff --git a/crates/storybook2/src/stories/components/context_menu.rs b/crates/storybook2/src/stories/components/context_menu.rs new file mode 100644 index 0000000000..f93f97f133 --- /dev/null +++ b/crates/storybook2/src/stories/components/context_menu.rs @@ -0,0 +1,30 @@ +use std::marker::PhantomData; + +use ui::prelude::*; +use ui::{ContextMenu, ContextMenuItem, Label}; + +use crate::story::Story; + +#[derive(Element)] +pub struct ContextMenuStory { + state_type: PhantomData, +} + +impl ContextMenuStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + Story::container(cx) + .child(Story::title_for::<_, ContextMenu>(cx)) + .child(Story::label(cx, "Default")) + .child(ContextMenu::new([ + ContextMenuItem::header("Section header"), + ContextMenuItem::Separator, + ContextMenuItem::entry(Label::new("Some entry")), + ])) + } +} diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 56387eee1d..feacea235d 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -42,6 +42,7 @@ pub enum ComponentStory { ChatPanel, CollabPanel, CommandPalette, + ContextMenu, Facepile, Keybinding, Palette, @@ -71,6 +72,7 @@ impl ComponentStory { 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::Palette => components::palette::PaletteStory::new().into_any(), diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index 968b7bee38..9e28d30662 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -4,6 +4,7 @@ mod buffer; mod chat_panel; mod collab_panel; mod command_palette; +mod context_menu; mod editor_pane; mod facepile; mod icon_button; @@ -29,6 +30,7 @@ pub use buffer::*; pub use chat_panel::*; pub use collab_panel::*; pub use command_palette::*; +pub use context_menu::*; pub use editor_pane::*; pub use facepile::*; pub use icon_button::*; diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs new file mode 100644 index 0000000000..9fa7e7c635 --- /dev/null +++ b/crates/ui2/src/components/context_menu.rs @@ -0,0 +1,67 @@ +use crate::prelude::*; +use crate::{ + theme, v_stack, Label, List, ListEntry, ListItem, ListItemVariant, ListSeparator, ListSubHeader, +}; + +#[derive(Clone)] +pub enum ContextMenuItem { + Header(&'static str), + Entry(Label), + Separator, +} + +impl ContextMenuItem { + fn to_list_item(self) -> ListItem { + match self { + ContextMenuItem::Header(label) => ListSubHeader::new(label).into(), + ContextMenuItem::Entry(label) => { + ListEntry::new(label).variant(ListItemVariant::Inset).into() + } + ContextMenuItem::Separator => ListSeparator::new().into(), + } + } + + pub fn header(label: &'static str) -> Self { + Self::Header(label) + } + + pub fn separator() -> Self { + Self::Separator + } + + pub fn entry(label: Label) -> Self { + Self::Entry(label) + } +} + +#[derive(Element)] +pub struct ContextMenu { + items: Vec>, +} + +impl ContextMenu { + pub fn new(items: impl IntoIterator>) -> Self { + Self { + items: items.into_iter().collect(), + } + } + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + let theme = theme(cx); + + v_stack() + .flex() + .fill(theme.lowest.base.default.background) + .border() + .border_color(theme.lowest.base.default.border) + .child( + List::new( + self.items + .clone() + .into_iter() + .map(ContextMenuItem::to_list_item) + .collect(), + ) + .set_toggle(ToggleState::Toggled), + ) + } +}