gpui-component/crates/story/src/tabs_story.rs
Jason Lee 8f2ca40c51
tab: Add new pill style, renamed old pill tab to outline. (#696)
<img width="1011" alt="image"
src="https://github.com/user-attachments/assets/4800a737-4e57-405b-b083-bf57ae3038ad"
/>

## Break Changes

- As you see on the above screenshot, the old `pill` style has been
renamed to `outline`.
2025-03-07 18:46:47 +08:00

228 lines
8.6 KiB
Rust

use gpui::{
App, AppContext, Context, Entity, Focusable, IntoElement, ParentElement, Render, Styled, Window,
};
use gpui_component::{
button::{Button, ButtonGroup, ButtonVariants},
h_flex,
tab::{Tab, TabBar},
v_flex, IconName, Selectable as _, Sizable, Size,
};
use crate::section;
pub struct TabsStory {
focus_handle: gpui::FocusHandle,
active_tab_ix: usize,
size: Size,
}
impl super::Story for TabsStory {
fn title() -> &'static str {
"Tabs"
}
fn description() -> &'static str {
"A set of layered sections of content—known as tab panels—that are displayed one at a time."
}
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render + Focusable> {
Self::view(window, cx)
}
}
impl TabsStory {
pub fn view(window: &mut Window, cx: &mut App) -> Entity<Self> {
cx.new(|cx| Self::new(window, cx))
}
fn new(_: &mut Window, cx: &mut Context<Self>) -> Self {
Self {
focus_handle: cx.focus_handle(),
active_tab_ix: 0,
size: Size::default(),
}
}
fn set_active_tab(&mut self, ix: usize, _: &mut Window, cx: &mut Context<Self>) {
self.active_tab_ix = ix;
cx.notify();
}
fn set_size(&mut self, size: Size, _: &mut Window, cx: &mut Context<Self>) {
self.size = size;
cx.notify();
}
}
impl Focusable for TabsStory {
fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle {
self.focus_handle.clone()
}
}
impl Render for TabsStory {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.gap_6()
.child(
ButtonGroup::new("toggle-size")
.outline()
.compact()
.child(
Button::new("xsmall")
.label("XSmall")
.selected(self.size == Size::XSmall),
)
.child(
Button::new("small")
.label("Small")
.selected(self.size == Size::Small),
)
.child(
Button::new("medium")
.label("Medium")
.selected(self.size == Size::Medium),
)
.child(
Button::new("large")
.label("Large")
.selected(self.size == Size::Large),
)
.on_click(cx.listener(|this, selecteds: &Vec<usize>, window, cx| {
let size = match selecteds[0] {
0 => Size::XSmall,
1 => Size::Small,
2 => Size::Medium,
3 => Size::Large,
_ => unreachable!(),
};
this.set_size(size, window, cx);
})),
)
.child(
section("Tabs", cx).child(
TabBar::new("tabs")
.w_full()
.with_size(self.size)
.selected_index(self.active_tab_ix)
.on_click(cx.listener(|this, ix: &usize, window, cx| {
this.set_active_tab(*ix, window, cx);
}))
.prefix(
h_flex()
.mx_1()
.child(
Button::new("back")
.ghost()
.xsmall()
.icon(IconName::ArrowLeft),
)
.child(
Button::new("forward")
.ghost()
.xsmall()
.icon(IconName::ArrowRight),
),
)
.child(Tab::new("Account"))
.child(Tab::new("Profile").disabled(true))
.child(Tab::new("Documents"))
.child(Tab::new("Mail"))
.child(Tab::new("Appearance"))
.child(Tab::new("Settings"))
.child(Tab::new("About"))
.child(Tab::new("License"))
.suffix(
h_flex()
.mx_1()
.child(Button::new("inbox").ghost().xsmall().icon(IconName::Inbox))
.child(
Button::new("more")
.ghost()
.xsmall()
.icon(IconName::Ellipsis),
),
),
),
)
.child(
section("Underline Tabs", cx).child(
TabBar::new("underline")
.w_full()
.px_2()
.mx_3()
.underline()
.with_size(self.size)
.selected_index(self.active_tab_ix)
.on_click(cx.listener(|this, ix: &usize, window, cx| {
this.set_active_tab(*ix, window, cx);
}))
.child("Account")
.child("Profile")
.child("Documents")
.child("Mail")
.child("Appearance")
.child("Settings")
.child("About")
.child("License"),
),
)
.child(
section("Pill Tabs", cx).child(
TabBar::new("pill")
.w_full()
.pill()
.with_size(self.size)
.selected_index(self.active_tab_ix)
.on_click(cx.listener(|this, ix: &usize, window, cx| {
this.set_active_tab(*ix, window, cx);
}))
.child(Tab::new("Account"))
.child(Tab::new("Profile").disabled(true))
.child(Tab::new("Documents & Files"))
.child(Tab::new("Mail"))
.child(Tab::new("Appearance"))
.child(Tab::new("Settings"))
.child(Tab::new("About"))
.child(Tab::new("License")),
),
)
.child(
section("Outline Tabs", cx).child(
TabBar::new("outline")
.w_full()
.outline()
.with_size(self.size)
.selected_index(self.active_tab_ix)
.on_click(cx.listener(|this, ix: &usize, window, cx| {
this.set_active_tab(*ix, window, cx);
}))
.child(Tab::new("Account"))
.child(Tab::new("Profile").disabled(true))
.child(Tab::new("Documents & Files"))
.child(Tab::new("Mail"))
.child(Tab::new("Appearance"))
.child(Tab::new("Settings"))
.child(Tab::new("About"))
.child(Tab::new("License")),
),
)
.child(
section("Segmented Tabs", cx).child(
TabBar::new("segmented")
.w_full()
.segmented()
.with_size(self.size)
.selected_index(self.active_tab_ix)
.on_click(cx.listener(|this, ix: &usize, window, cx| {
this.set_active_tab(*ix, window, cx);
}))
.child(IconName::Bot)
.child(IconName::Calendar)
.child(IconName::Map)
.children(vec!["Appearance", "Settings", "About", "License"]),
),
)
}
}