Detailed changes
@@ -17,16 +17,9 @@ pub enum ComponentStory {
ContextMenu,
Cursor,
Focus,
- IconButton,
- Keybinding,
- List,
- ListHeader,
- ListItem,
OverflowScroll,
Picker,
Scroll,
- Tab,
- TabBar,
Text,
ViewportUnits,
WithRemSize,
@@ -46,16 +39,9 @@ impl ComponentStory {
Self::ContextMenu => cx.new(|_| ui::ContextMenuStory).into(),
Self::Cursor => cx.new(|_| crate::stories::CursorStory).into(),
Self::Focus => FocusStory::model(window, cx).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::ViewportUnits => cx.new(|_| crate::stories::ViewportUnitsStory).into(),
Self::WithRemSize => cx.new(|_| crate::stories::WithRemSizeStory).into(),
@@ -1,14 +1,15 @@
+use component::{Component, ComponentScope, example_group_with_title, single_example};
use gpui::AnyElement;
use smallvec::SmallVec;
-use crate::{Label, ListHeader, prelude::*, v_flex};
+use crate::{Label, ListHeader, ListItem, prelude::*};
pub enum EmptyMessage {
Text(SharedString),
Element(AnyElement),
}
-#[derive(IntoElement)]
+#[derive(IntoElement, RegisterComponent)]
pub struct List {
/// Message to display when the list is empty
/// Defaults to "No items"
@@ -92,3 +93,50 @@ impl RenderOnce for List {
})
}
}
+
+impl Component for List {
+ fn scope() -> ComponentScope {
+ ComponentScope::Layout
+ }
+
+ fn description() -> Option<&'static str> {
+ Some(
+ "A container component for displaying a collection of list items with optional header and empty state.",
+ )
+ }
+
+ fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
+ Some(
+ v_flex()
+ .gap_6()
+ .children(vec![example_group_with_title(
+ "Basic Lists",
+ vec![
+ single_example(
+ "Simple List",
+ List::new()
+ .child(ListItem::new("item1").child(Label::new("Item 1")))
+ .child(ListItem::new("item2").child(Label::new("Item 2")))
+ .child(ListItem::new("item3").child(Label::new("Item 3")))
+ .into_any_element(),
+ ),
+ single_example(
+ "With Header",
+ List::new()
+ .header(ListHeader::new("Section Header"))
+ .child(ListItem::new("item1").child(Label::new("Item 1")))
+ .child(ListItem::new("item2").child(Label::new("Item 2")))
+ .into_any_element(),
+ ),
+ single_example(
+ "Empty List",
+ List::new()
+ .empty_message("No items to display")
+ .into_any_element(),
+ ),
+ ],
+ )])
+ .into_any_element(),
+ )
+ }
+}
@@ -1,7 +1,8 @@
use crate::{ListItem, prelude::*};
+use component::{Component, ComponentScope, example_group_with_title, single_example};
use gpui::{IntoElement, ParentElement, SharedString};
-#[derive(IntoElement)]
+#[derive(IntoElement, RegisterComponent)]
pub struct ListBulletItem {
label: SharedString,
}
@@ -38,3 +39,45 @@ impl RenderOnce for ListBulletItem {
.into_any_element()
}
}
+
+impl Component for ListBulletItem {
+ fn scope() -> ComponentScope {
+ ComponentScope::DataDisplay
+ }
+
+ fn description() -> Option<&'static str> {
+ Some("A list item with a bullet point indicator for unordered lists.")
+ }
+
+ fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
+ Some(
+ v_flex()
+ .gap_6()
+ .child(example_group_with_title(
+ "Bullet Items",
+ vec![
+ single_example(
+ "Simple",
+ ListBulletItem::new("First bullet item").into_any_element(),
+ ),
+ single_example(
+ "Multiple Lines",
+ v_flex()
+ .child(ListBulletItem::new("First item"))
+ .child(ListBulletItem::new("Second item"))
+ .child(ListBulletItem::new("Third item"))
+ .into_any_element(),
+ ),
+ single_example(
+ "Long Text",
+ ListBulletItem::new(
+ "A longer bullet item that demonstrates text wrapping behavior",
+ )
+ .into_any_element(),
+ ),
+ ],
+ ))
+ .into_any_element(),
+ )
+ }
+}
@@ -1,11 +1,12 @@
use std::sync::Arc;
-use crate::{Disclosure, Label, h_flex, prelude::*};
+use crate::{Disclosure, prelude::*};
+use component::{Component, ComponentScope, example_group_with_title, single_example};
use gpui::{AnyElement, ClickEvent};
use settings::Settings;
use theme::ThemeSettings;
-#[derive(IntoElement)]
+#[derive(IntoElement, RegisterComponent)]
pub struct ListHeader {
/// The label of the header.
label: SharedString,
@@ -138,3 +139,80 @@ impl RenderOnce for ListHeader {
)
}
}
+
+impl Component for ListHeader {
+ fn scope() -> ComponentScope {
+ ComponentScope::DataDisplay
+ }
+
+ fn description() -> Option<&'static str> {
+ Some(
+ "A header component for lists with support for icons, actions, and collapsible sections.",
+ )
+ }
+
+ fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
+ Some(
+ v_flex()
+ .gap_6()
+ .children(vec![
+ example_group_with_title(
+ "Basic Headers",
+ vec![
+ single_example(
+ "Simple",
+ ListHeader::new("Section Header").into_any_element(),
+ ),
+ single_example(
+ "With Icon",
+ ListHeader::new("Files")
+ .start_slot(Icon::new(IconName::File))
+ .into_any_element(),
+ ),
+ single_example(
+ "With End Slot",
+ ListHeader::new("Recent")
+ .end_slot(Label::new("5").color(Color::Muted))
+ .into_any_element(),
+ ),
+ ],
+ ),
+ example_group_with_title(
+ "Collapsible Headers",
+ vec![
+ single_example(
+ "Expanded",
+ ListHeader::new("Expanded Section")
+ .toggle(Some(true))
+ .into_any_element(),
+ ),
+ single_example(
+ "Collapsed",
+ ListHeader::new("Collapsed Section")
+ .toggle(Some(false))
+ .into_any_element(),
+ ),
+ ],
+ ),
+ example_group_with_title(
+ "States",
+ vec![
+ single_example(
+ "Selected",
+ ListHeader::new("Selected Header")
+ .toggle_state(true)
+ .into_any_element(),
+ ),
+ single_example(
+ "Inset",
+ ListHeader::new("Inset Header")
+ .inset(true)
+ .into_any_element(),
+ ),
+ ],
+ ),
+ ])
+ .into_any_element(),
+ )
+ }
+}
@@ -1,5 +1,6 @@
use std::sync::Arc;
+use component::{Component, ComponentScope, example_group_with_title, single_example};
use gpui::{AnyElement, AnyView, ClickEvent, MouseButton, MouseDownEvent, Pixels, px};
use smallvec::SmallVec;
@@ -13,7 +14,7 @@ pub enum ListItemSpacing {
Sparse,
}
-#[derive(IntoElement)]
+#[derive(IntoElement, RegisterComponent)]
pub struct ListItem {
id: ElementId,
group_name: Option<SharedString>,
@@ -355,3 +356,115 @@ impl RenderOnce for ListItem {
)
}
}
+
+impl Component for ListItem {
+ fn scope() -> ComponentScope {
+ ComponentScope::DataDisplay
+ }
+
+ fn description() -> Option<&'static str> {
+ Some(
+ "A flexible list item component with support for icons, actions, disclosure toggles, and hierarchical display.",
+ )
+ }
+
+ fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
+ Some(
+ v_flex()
+ .gap_6()
+ .children(vec![
+ example_group_with_title(
+ "Basic List Items",
+ vec![
+ single_example(
+ "Simple",
+ ListItem::new("simple")
+ .child(Label::new("Simple list item"))
+ .into_any_element(),
+ ),
+ single_example(
+ "With Icon",
+ ListItem::new("with_icon")
+ .start_slot(Icon::new(IconName::File))
+ .child(Label::new("List item with icon"))
+ .into_any_element(),
+ ),
+ single_example(
+ "Selected",
+ ListItem::new("selected")
+ .toggle_state(true)
+ .start_slot(Icon::new(IconName::Check))
+ .child(Label::new("Selected item"))
+ .into_any_element(),
+ ),
+ ],
+ ),
+ example_group_with_title(
+ "List Item Spacing",
+ vec![
+ single_example(
+ "Dense",
+ ListItem::new("dense")
+ .spacing(ListItemSpacing::Dense)
+ .child(Label::new("Dense spacing"))
+ .into_any_element(),
+ ),
+ single_example(
+ "Extra Dense",
+ ListItem::new("extra_dense")
+ .spacing(ListItemSpacing::ExtraDense)
+ .child(Label::new("Extra dense spacing"))
+ .into_any_element(),
+ ),
+ single_example(
+ "Sparse",
+ ListItem::new("sparse")
+ .spacing(ListItemSpacing::Sparse)
+ .child(Label::new("Sparse spacing"))
+ .into_any_element(),
+ ),
+ ],
+ ),
+ example_group_with_title(
+ "With Slots",
+ vec![
+ single_example(
+ "End Slot",
+ ListItem::new("end_slot")
+ .child(Label::new("Item with end slot"))
+ .end_slot(Icon::new(IconName::ChevronRight))
+ .into_any_element(),
+ ),
+ single_example(
+ "With Toggle",
+ ListItem::new("with_toggle")
+ .toggle(Some(true))
+ .child(Label::new("Expandable item"))
+ .into_any_element(),
+ ),
+ ],
+ ),
+ example_group_with_title(
+ "States",
+ vec![
+ single_example(
+ "Disabled",
+ ListItem::new("disabled")
+ .disabled(true)
+ .child(Label::new("Disabled item"))
+ .into_any_element(),
+ ),
+ single_example(
+ "Non-selectable",
+ ListItem::new("non_selectable")
+ .selectable(false)
+ .child(Label::new("Non-selectable item"))
+ .into_any_element(),
+ ),
+ ],
+ ),
+ ])
+ .into_any_element(),
+ )
+ }
+}
@@ -1,7 +1,7 @@
use crate::prelude::*;
-use crate::{Icon, IconName, IconSize, Label, h_flex};
+use component::{Component, ComponentScope, example_group_with_title, single_example};
-#[derive(IntoElement)]
+#[derive(IntoElement, RegisterComponent)]
pub struct ListSubHeader {
label: SharedString,
start_slot: Option<IconName>,
@@ -85,3 +85,65 @@ impl RenderOnce for ListSubHeader {
)
}
}
+
+impl Component for ListSubHeader {
+ fn scope() -> ComponentScope {
+ ComponentScope::DataDisplay
+ }
+
+ fn description() -> Option<&'static str> {
+ Some(
+ "A sub-header component for organizing list content into subsections with optional icons and end slots.",
+ )
+ }
+
+ fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
+ Some(
+ v_flex()
+ .gap_6()
+ .children(vec![
+ example_group_with_title(
+ "Basic Sub-headers",
+ vec![
+ single_example(
+ "Simple",
+ ListSubHeader::new("Subsection").into_any_element(),
+ ),
+ single_example(
+ "With Icon",
+ ListSubHeader::new("Documents")
+ .left_icon(Some(IconName::File))
+ .into_any_element(),
+ ),
+ single_example(
+ "With End Slot",
+ ListSubHeader::new("Recent")
+ .end_slot(
+ Label::new("3").color(Color::Muted).into_any_element(),
+ )
+ .into_any_element(),
+ ),
+ ],
+ ),
+ example_group_with_title(
+ "States",
+ vec![
+ single_example(
+ "Selected",
+ ListSubHeader::new("Selected")
+ .toggle_state(true)
+ .into_any_element(),
+ ),
+ single_example(
+ "Inset",
+ ListSubHeader::new("Inset Sub-header")
+ .inset(true)
+ .into_any_element(),
+ ),
+ ],
+ ),
+ ])
+ .into_any_element(),
+ )
+ }
+}
@@ -1,17 +1,3 @@
mod context_menu;
-mod icon_button;
-mod keybinding;
-mod list;
-mod list_header;
-mod list_item;
-mod tab;
-mod tab_bar;
pub use context_menu::*;
-pub use icon_button::*;
-pub use keybinding::*;
-pub use list::*;
-pub use list_header::*;
-pub use list_item::*;
-pub use tab::*;
-pub use tab_bar::*;
@@ -1,18 +0,0 @@
-use gpui::Render;
-use story::Story;
-
-use crate::Disclosure;
-use crate::prelude::*;
-
-pub struct DisclosureStory;
-
-impl Render for DisclosureStory {
- fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- Story::container(cx)
- .child(Story::title_for::<Disclosure>(cx))
- .child(Story::label("Toggled"))
- .child(Disclosure::new("toggled", true))
- .child(Story::label("Not Toggled"))
- .child(Disclosure::new("not_toggled", false))
- }
-}
@@ -1,148 +0,0 @@
-use gpui::Render;
-use story::{Story, StoryItem, StorySection};
-
-use crate::{IconButton, IconName};
-use crate::{IconButtonShape, Tooltip, prelude::*};
-
-pub struct IconButtonStory;
-
-impl Render for IconButtonStory {
- fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- let default_button = StoryItem::new(
- "Default",
- IconButton::new("default_icon_button", IconName::Hash),
- )
- .description("Displays an icon button.")
- .usage(
- r#"
- IconButton::new("default_icon_button", Icon::Hash)
- "#,
- );
-
- let selected_button = StoryItem::new(
- "Selected",
- IconButton::new("selected_icon_button", IconName::Hash).toggle_state(true),
- )
- .description("Displays an icon button that is selected.")
- .usage(
- r#"
- IconButton::new("selected_icon_button", Icon::Hash).selected(true)
- "#,
- );
-
- let selected_with_selected_icon = StoryItem::new(
- "Selected with `selected_icon`",
- IconButton::new("selected_with_selected_icon_button", IconName::AudioOn)
- .toggle_state(true)
- .selected_icon(IconName::AudioOff),
- )
- .description(
- "Displays an icon button that is selected and shows a different icon when selected.",
- )
- .usage(
- r#"
- IconButton::new("selected_with_selected_icon_button", Icon::AudioOn)
- .selected(true)
- .selected_icon(Icon::AudioOff)
- "#,
- );
-
- let disabled_button = StoryItem::new(
- "Disabled",
- IconButton::new("disabled_icon_button", IconName::Hash).disabled(true),
- )
- .description("Displays an icon button that is disabled.")
- .usage(
- r#"
- IconButton::new("disabled_icon_button", Icon::Hash).disabled(true)
- "#,
- );
-
- let with_on_click_button = StoryItem::new(
- "With `on_click`",
- IconButton::new("with_on_click_button", IconName::Ai).on_click(
- |_event, _window, _cx| {
- println!("Clicked!");
- },
- ),
- )
- .description("Displays an icon button which triggers an event on click.")
- .usage(
- r#"
- IconButton::new("with_on_click_button", Icon::Ai).on_click(|_event, _cx| {
- println!("Clicked!");
- })
- "#,
- );
-
- let with_tooltip_button = StoryItem::new(
- "With `tooltip`",
- IconButton::new("with_tooltip_button", IconName::Chat)
- .tooltip(Tooltip::text("Open messages")),
- )
- .description("Displays an icon button that has a tooltip when hovered.")
- .usage(
- r#"
- IconButton::new("with_tooltip_button", Icon::MessageBubbles)
- .tooltip(Tooltip::text_f("Open messages"))
- "#,
- );
-
- let selected_with_tooltip_button = StoryItem::new(
- "Selected with `tooltip`",
- IconButton::new("selected_with_tooltip_button", IconName::CaseSensitive)
- .toggle_state(true)
- .tooltip(Tooltip::text("Toggle inlay hints")),
- )
- .description("Displays a selected icon button with tooltip.")
- .usage(
- r#"
- IconButton::new("selected_with_tooltip_button", Icon::InlayHint)
- .selected(true)
- .tooltip(Tooltip::text_f("Toggle inlay hints"))
- "#,
- );
-
- let buttons = vec![
- default_button,
- selected_button,
- selected_with_selected_icon,
- disabled_button,
- with_on_click_button,
- with_tooltip_button,
- selected_with_tooltip_button,
- ];
-
- Story::container(cx)
- .child(Story::title_for::<IconButton>(cx))
- .child(StorySection::new().children(buttons))
- .child(
- StorySection::new().child(StoryItem::new(
- "Square",
- h_flex()
- .gap_2()
- .child(
- IconButton::new("square-medium", IconName::Close)
- .shape(IconButtonShape::Square)
- .icon_size(IconSize::Medium),
- )
- .child(
- IconButton::new("square-small", IconName::Close)
- .shape(IconButtonShape::Square)
- .icon_size(IconSize::Small),
- )
- .child(
- IconButton::new("square-xsmall", IconName::Close)
- .shape(IconButtonShape::Square)
- .icon_size(IconSize::XSmall),
- )
- .child(
- IconButton::new("square-indicator", IconName::Close)
- .shape(IconButtonShape::Square)
- .icon_size(IconSize::Indicator),
- ),
- )),
- )
- .into_element()
- }
-}
@@ -1,136 +0,0 @@
-use gpui::NoAction;
-use gpui::Render;
-use itertools::Itertools;
-use settings::KeybindSource;
-use story::Story;
-
-use crate::{KeyBinding, prelude::*};
-
-pub struct KeybindingStory;
-
-pub fn binding(key: &str) -> gpui::KeyBinding {
- gpui::KeyBinding::new(key, NoAction {}, None)
-}
-
-impl Render for KeybindingStory {
- fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- let all_modifier_permutations = ["ctrl", "alt", "cmd", "shift"].into_iter().permutations(2);
-
- const SOURCE: KeybindSource = KeybindSource::Base;
-
- Story::container(cx)
- .child(Story::title_for::<KeyBinding>(cx))
- .child(Story::label("Single Key", cx))
- .child(KeyBinding::from_keystrokes(
- binding("Z").keystrokes().into(),
- SOURCE,
- ))
- .child(Story::label("Single Key with Modifier", cx))
- .child(
- div()
- .flex()
- .gap_3()
- .child(KeyBinding::from_keystrokes(
- binding("ctrl-c").keystrokes().into(),
- SOURCE,
- ))
- .child(KeyBinding::from_keystrokes(
- binding("alt-c").keystrokes().into(),
- SOURCE,
- ))
- .child(KeyBinding::from_keystrokes(
- binding("cmd-c").keystrokes().into(),
- SOURCE,
- ))
- .child(KeyBinding::from_keystrokes(
- binding("shift-c").keystrokes().into(),
- SOURCE,
- )),
- )
- .child(Story::label("Single Key with Modifier (Permuted)", cx))
- .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| {
- KeyBinding::from_keystrokes(
- binding(&(permutation.join("-") + "-x"))
- .keystrokes()
- .into(),
- SOURCE,
- )
- }))
- }),
- ),
- )
- .child(Story::label("Single Key with All Modifiers", cx))
- .child(KeyBinding::from_keystrokes(
- binding("ctrl-alt-cmd-shift-z").keystrokes().into(),
- SOURCE,
- ))
- .child(Story::label("Chord", cx))
- .child(KeyBinding::from_keystrokes(
- binding("a z").keystrokes().into(),
- SOURCE,
- ))
- .child(Story::label("Chord with Modifier", cx))
- .child(KeyBinding::from_keystrokes(
- binding("ctrl-a shift-z").keystrokes().into(),
- SOURCE,
- ))
- .child(KeyBinding::from_keystrokes(
- binding("fn-s").keystrokes().into(),
- SOURCE,
- ))
- .child(Story::label("Single Key with All Modifiers (Linux)", cx))
- .child(
- KeyBinding::from_keystrokes(
- binding("ctrl-alt-cmd-shift-z").keystrokes().into(),
- SOURCE,
- )
- .platform_style(PlatformStyle::Linux),
- )
- .child(Story::label("Chord (Linux)", cx))
- .child(
- KeyBinding::from_keystrokes(binding("a z").keystrokes().into(), SOURCE)
- .platform_style(PlatformStyle::Linux),
- )
- .child(Story::label("Chord with Modifier (Linux)", cx))
- .child(
- KeyBinding::from_keystrokes(binding("ctrl-a shift-z").keystrokes().into(), SOURCE)
- .platform_style(PlatformStyle::Linux),
- )
- .child(
- KeyBinding::from_keystrokes(binding("fn-s").keystrokes().into(), SOURCE)
- .platform_style(PlatformStyle::Linux),
- )
- .child(Story::label("Single Key with All Modifiers (Windows)", cx))
- .child(
- KeyBinding::from_keystrokes(
- binding("ctrl-alt-cmd-shift-z").keystrokes().into(),
- SOURCE,
- )
- .platform_style(PlatformStyle::Windows),
- )
- .child(Story::label("Chord (Windows)", cx))
- .child(
- KeyBinding::from_keystrokes(binding("a z").keystrokes().into(), SOURCE)
- .platform_style(PlatformStyle::Windows),
- )
- .child(Story::label("Chord with Modifier (Windows)", cx))
- .child(
- KeyBinding::from_keystrokes(binding("ctrl-a shift-z").keystrokes().into(), SOURCE)
- .platform_style(PlatformStyle::Windows),
- )
- .child(
- KeyBinding::from_keystrokes(binding("fn-s").keystrokes().into(), SOURCE)
- .platform_style(PlatformStyle::Windows),
- )
- }
-}
@@ -1,36 +0,0 @@
-use gpui::Render;
-use story::Story;
-
-use crate::{List, ListItem};
-use crate::{ListHeader, ListSeparator, ListSubHeader, prelude::*};
-
-pub struct ListStory;
-
-impl Render for ListStory {
- fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- Story::container(cx)
- .child(Story::title_for::<List>(cx))
- .child(Story::label("Default", cx))
- .child(
- List::new()
- .child(ListItem::new("apple").child("Apple"))
- .child(ListItem::new("banana").child("Banana"))
- .child(ListItem::new("cherry").child("Cherry")),
- )
- .child(Story::label("With sections", cx))
- .child(
- List::new()
- .header(ListHeader::new("Produce"))
- .child(ListSubHeader::new("Fruits"))
- .child(ListItem::new("apple").child("Apple"))
- .child(ListItem::new("banana").child("Banana"))
- .child(ListItem::new("cherry").child("Cherry"))
- .child(ListSeparator)
- .child(ListSubHeader::new("Root Vegetables"))
- .child(ListItem::new("carrot").child("Carrot"))
- .child(ListItem::new("potato").child("Potato"))
- .child(ListSubHeader::new("Leafy Vegetables"))
- .child(ListItem::new("kale").child("Kale")),
- )
- }
-}
@@ -1,31 +0,0 @@
-use gpui::Render;
-use story::Story;
-
-use crate::{IconButton, prelude::*};
-use crate::{IconName, ListHeader};
-
-pub struct ListHeaderStory;
-
-impl Render for ListHeaderStory {
- fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- Story::container(cx)
- .child(Story::title_for::<ListHeader>(cx))
- .child(Story::label("Default", cx))
- .child(ListHeader::new("Section 1"))
- .child(Story::label("With left icon", cx))
- .child(ListHeader::new("Section 2").start_slot(Icon::new(IconName::Bell)))
- .child(Story::label("With left icon and meta", cx))
- .child(
- ListHeader::new("Section 3")
- .start_slot(Icon::new(IconName::BellOff))
- .end_slot(IconButton::new("action_1", IconName::BoltFilled)),
- )
- .child(Story::label("With multiple meta", cx))
- .child(
- ListHeader::new("Section 4")
- .end_slot(IconButton::new("action_1", IconName::BoltFilled))
- .end_slot(IconButton::new("action_2", IconName::Warning))
- .end_slot(IconButton::new("action_3", IconName::Plus)),
- )
- }
-}
@@ -1,131 +0,0 @@
-use gpui::Render;
-use story::Story;
-
-use crate::{Avatar, prelude::*};
-use crate::{IconName, ListItem};
-
-const OVERFLOWING_TEXT: &str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean mauris ligula, luctus vel dignissim eu, vestibulum sed libero. Sed at convallis velit.";
-
-pub struct ListItemStory;
-
-impl Render for ListItemStory {
- fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- Story::container(cx)
- .bg(cx.theme().colors().background)
- .child(Story::title_for::<ListItem>(cx))
- .child(Story::label("Default", cx))
- .child(ListItem::new("hello_world").child("Hello, world!"))
- .child(Story::label("Inset", cx))
- .child(
- ListItem::new("inset_list_item")
- .inset(true)
- .start_slot(
- Icon::new(IconName::Bell)
- .size(IconSize::Small)
- .color(Color::Muted),
- )
- .child("Hello, world!")
- .end_slot(
- Icon::new(IconName::Bell)
- .size(IconSize::Small)
- .color(Color::Muted),
- ),
- )
- .child(Story::label("With start slot icon", cx))
- .child(
- ListItem::new("with start slot_icon")
- .child("Hello, world!")
- .start_slot(
- Icon::new(IconName::Bell)
- .size(IconSize::Small)
- .color(Color::Muted),
- ),
- )
- .child(Story::label("With start slot avatar", cx))
- .child(
- ListItem::new("with_start slot avatar")
- .child("Hello, world!")
- .start_slot(Avatar::new(
- "https://avatars.githubusercontent.com/u/1714999?v=4",
- )),
- )
- .child(Story::label("With end slot", cx))
- .child(
- ListItem::new("with_left_avatar")
- .child("Hello, world!")
- .end_slot(Avatar::new(
- "https://avatars.githubusercontent.com/u/1714999?v=4",
- )),
- )
- .child(Story::label("With end hover slot", cx))
- .child(
- ListItem::new("with_end_hover_slot")
- .child("Hello, world!")
- .end_slot(
- h_flex()
- .gap_2()
- .child(Avatar::new(
- "https://avatars.githubusercontent.com/u/1789?v=4",
- ))
- .child(Avatar::new(
- "https://avatars.githubusercontent.com/u/1789?v=4",
- ))
- .child(Avatar::new(
- "https://avatars.githubusercontent.com/u/1789?v=4",
- ))
- .child(Avatar::new(
- "https://avatars.githubusercontent.com/u/1789?v=4",
- ))
- .child(Avatar::new(
- "https://avatars.githubusercontent.com/u/1789?v=4",
- )),
- )
- .end_hover_slot(Avatar::new(
- "https://avatars.githubusercontent.com/u/1714999?v=4",
- )),
- )
- .child(Story::label("With `on_click`", cx))
- .child(ListItem::new("with_on_click").child("Click me").on_click(
- |_event, _window, _cx| {
- println!("Clicked!");
- },
- ))
- .child(Story::label("With `on_secondary_mouse_down`", cx))
- .child(
- ListItem::new("with_on_secondary_mouse_down")
- .child("Right click me")
- .on_secondary_mouse_down(|_event, _window, _cx| {
- println!("Right mouse down!");
- }),
- )
- .child(Story::label(
- "With overflowing content in the `end_slot`",
- cx,
- ))
- .child(
- ListItem::new("with_overflowing_content_in_end_slot")
- .child("An excerpt")
- .end_slot(Label::new(OVERFLOWING_TEXT).color(Color::Muted)),
- )
- .child(Story::label(
- "`inset` with overflowing content in the `end_slot`",
- cx,
- ))
- .child(
- ListItem::new("inset_with_overflowing_content_in_end_slot")
- .inset(true)
- .child("An excerpt")
- .end_slot(Label::new(OVERFLOWING_TEXT).color(Color::Muted)),
- )
- .child(Story::label(
- "`inset` with overflowing content in `children` and `end_slot`",
- cx,
- ))
- .child(
- ListItem::new("inset_with_overflowing_content_in_children_and_end_slot")
- .inset(true)
- .child(Label::new(OVERFLOWING_TEXT))
- .end_slot(Label::new(OVERFLOWING_TEXT).color(Color::Muted)),
- )
- }
-}
@@ -1,114 +0,0 @@
-use std::cmp::Ordering;
-
-use gpui::Render;
-use story::Story;
-
-use crate::{IconButtonShape, TabPosition, prelude::*};
-use crate::{Indicator, Tab};
-
-pub struct TabStory;
-
-impl Render for TabStory {
- fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- Story::container(cx)
- .child(Story::title_for::<Tab>(cx))
- .child(Story::label("Default", cx))
- .child(h_flex().child(Tab::new("tab_1").child("Tab 1")))
- .child(Story::label("With indicator", cx))
- .child(
- h_flex().child(
- Tab::new("tab_1")
- .start_slot(Indicator::dot().color(Color::Warning))
- .child("Tab 1"),
- ),
- )
- .child(Story::label("With close button", cx))
- .child(
- h_flex().child(
- Tab::new("tab_1")
- .end_slot(
- IconButton::new("close_button", IconName::Close)
- .visible_on_hover("")
- .shape(IconButtonShape::Square)
- .icon_color(Color::Muted)
- .size(ButtonSize::None)
- .icon_size(IconSize::XSmall),
- )
- .child("Tab 1"),
- ),
- )
- .child(Story::label("List of tabs", cx))
- .child(
- h_flex()
- .child(Tab::new("tab_1").child("Tab 1"))
- .child(Tab::new("tab_2").child("Tab 2")),
- )
- .child(Story::label("List of tabs with first tab selected", cx))
- .child(
- h_flex()
- .child(
- Tab::new("tab_1")
- .toggle_state(true)
- .position(TabPosition::First)
- .child("Tab 1"),
- )
- .child(
- Tab::new("tab_2")
- .position(TabPosition::Middle(Ordering::Greater))
- .child("Tab 2"),
- )
- .child(
- Tab::new("tab_3")
- .position(TabPosition::Middle(Ordering::Greater))
- .child("Tab 3"),
- )
- .child(Tab::new("tab_4").position(TabPosition::Last).child("Tab 4")),
- )
- .child(Story::label("List of tabs with last tab selected", cx))
- .child(
- h_flex()
- .child(
- Tab::new("tab_1")
- .position(TabPosition::First)
- .child("Tab 1"),
- )
- .child(
- Tab::new("tab_2")
- .position(TabPosition::Middle(Ordering::Less))
- .child("Tab 2"),
- )
- .child(
- Tab::new("tab_3")
- .position(TabPosition::Middle(Ordering::Less))
- .child("Tab 3"),
- )
- .child(
- Tab::new("tab_4")
- .position(TabPosition::Last)
- .toggle_state(true)
- .child("Tab 4"),
- ),
- )
- .child(Story::label("List of tabs with second tab selected", cx))
- .child(
- h_flex()
- .child(
- Tab::new("tab_1")
- .position(TabPosition::First)
- .child("Tab 1"),
- )
- .child(
- Tab::new("tab_2")
- .position(TabPosition::Middle(Ordering::Equal))
- .toggle_state(true)
- .child("Tab 2"),
- )
- .child(
- Tab::new("tab_3")
- .position(TabPosition::Middle(Ordering::Greater))
- .child("Tab 3"),
- )
- .child(Tab::new("tab_4").position(TabPosition::Last).child("Tab 4")),
- )
- }
-}
@@ -1,59 +0,0 @@
-use gpui::Render;
-use story::Story;
-
-use crate::{Tab, TabBar, TabPosition, prelude::*};
-
-pub struct TabBarStory;
-
-impl Render for TabBarStory {
- fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
- let tab_count = 20;
- let selected_tab_index = 3;
-
- let tabs = (0..tab_count)
- .map(|index| {
- Tab::new(index)
- .toggle_state(index == selected_tab_index)
- .position(if index == 0 {
- TabPosition::First
- } else if index == tab_count - 1 {
- TabPosition::Last
- } else {
- TabPosition::Middle(index.cmp(&selected_tab_index))
- })
- .child(Label::new(format!("Tab {}", index + 1)).color(
- if index == selected_tab_index {
- Color::Default
- } else {
- Color::Muted
- },
- ))
- })
- .collect::<Vec<_>>();
-
- Story::container(cx)
- .child(Story::title_for::<TabBar>(cx))
- .child(Story::label("Default", cx))
- .child(
- h_flex().child(
- TabBar::new("tab_bar_1")
- .start_child(
- IconButton::new("navigate_backward", IconName::ArrowLeft)
- .icon_size(IconSize::Small),
- )
- .start_child(
- IconButton::new("navigate_forward", IconName::ArrowRight)
- .icon_size(IconSize::Small),
- )
- .end_child(
- IconButton::new("new", IconName::Plus).icon_size(IconSize::Small),
- )
- .end_child(
- IconButton::new("split_pane", IconName::Split)
- .icon_size(IconSize::Small),
- )
- .children(tabs),
- ),
- )
- }
-}