<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`.
228 lines
8.6 KiB
Rust
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"]),
|
|
),
|
|
)
|
|
}
|
|
}
|