ui: Remove outdated/unused component stories (#43118)

This PR removes basically all of the component stories, with the
exception of the context menu, which is a bit more intricate to set up.
All of the component that won't have a story after this PR will have an
entry in the Component Preview, which serves basically the same purpose.

Release Notes:

- N/A
This commit is contained in:
Danilo Leal
2025-11-20 01:52:13 -03:00
committed by GitHub
parent ba596267d8
commit 66382acd52
17 changed files with 352 additions and 709 deletions

View File

@@ -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(),

View File

@@ -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(),
)
}
}

View File

@@ -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(),
)
}
}

View File

@@ -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(),
)
}
}

View File

@@ -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(),
)
}
}

View File

@@ -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(),
)
}
}

View File

@@ -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::*;

View File

@@ -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))
}
}

View File

@@ -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()
}
}

View File

@@ -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),
)
}
}

View File

@@ -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")),
)
}
}

View File

@@ -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)),
)
}
}

View File

@@ -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)),
)
}
}

View File

@@ -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")),
)
}
}

View File

@@ -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),
),
)
}
}