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`.
This commit is contained in:
Jason Lee 2025-03-07 18:46:47 +08:00 committed by GitHub
parent 8611a23aae
commit 8f2ca40c51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 110 additions and 33 deletions

View file

@ -4,7 +4,7 @@ use gpui::{
};
use gpui_component::{
accordion::Accordion,
button::{Button, ButtonGroup},
button::{Button, ButtonGroup, ButtonVariants as _},
checkbox::Checkbox,
h_flex,
switch::Switch,
@ -72,6 +72,8 @@ impl Render for AccordionStory {
.gap_2()
.child(
ButtonGroup::new("toggle-size")
.outline()
.compact()
.child(
Button::new("xsmall")
.label("XSmall")

View file

@ -6,7 +6,7 @@ use gpui::{
ParentElement, Pixels, Render, ScrollHandle, SharedString, Size, Styled, Window,
};
use gpui_component::{
button::{Button, ButtonGroup},
button::{Button, ButtonGroup, ButtonVariants as _},
divider::Divider,
gray_100, gray_800, h_flex,
label::Label,
@ -103,6 +103,8 @@ impl ScrollableStory {
.gap_2()
.child(
ButtonGroup::new("test-cases")
.outline()
.compact()
.child(
Button::new("test-0")
.label("Size 0")
@ -138,6 +140,8 @@ impl ScrollableStory {
.child(Divider::vertical().px_2())
.child(
ButtonGroup::new("scrollbars")
.outline()
.compact()
.child(
Button::new("test-axis-both")
.label("Both Scrollbar")

View file

@ -67,6 +67,8 @@ impl Render for TabsStory {
.gap_6()
.child(
ButtonGroup::new("toggle-size")
.outline()
.compact()
.child(
Button::new("xsmall")
.label("XSmall")
@ -144,6 +146,28 @@ impl Render for TabsStory {
),
),
)
.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")
@ -164,6 +188,26 @@ impl Render for TabsStory {
.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")
@ -180,27 +224,5 @@ impl Render for TabsStory {
.children(vec!["Appearance", "Settings", "About", "License"]),
),
)
.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"),
),
)
}
}

View file

@ -12,6 +12,7 @@ use gpui::{
pub enum TabVariant {
#[default]
Tab,
Outline,
Pill,
Segmented,
Underline,
@ -66,23 +67,23 @@ impl TabVariant {
fn inner_height(&self, size: Size) -> Pixels {
match size {
Size::XSmall => match self {
TabVariant::Tab | TabVariant::Pill => px(20.),
TabVariant::Tab | TabVariant::Outline | TabVariant::Pill => px(20.),
TabVariant::Segmented => px(16.),
TabVariant::Underline => px(20.),
},
Size::Small => match self {
TabVariant::Tab | TabVariant::Pill => px(24.),
TabVariant::Tab | TabVariant::Outline | TabVariant::Pill => px(24.),
TabVariant::Segmented => px(20.),
TabVariant::Underline => px(22.),
},
Size::Large => match self {
TabVariant::Tab | TabVariant::Pill => px(36.),
TabVariant::Tab | TabVariant::Outline | TabVariant::Pill => px(36.),
TabVariant::Segmented => px(28.),
TabVariant::Underline => px(30.),
},
_ => match self {
TabVariant::Tab => px(30.),
TabVariant::Pill => px(26.),
TabVariant::Outline | TabVariant::Pill => px(26.),
TabVariant::Segmented => px(24.),
TabVariant::Underline => px(24.),
},
@ -143,7 +144,7 @@ impl TabVariant {
border_color: cx.theme().transparent,
..Default::default()
},
TabVariant::Pill => TabStyle {
TabVariant::Outline => TabStyle {
fg: cx.theme().tab_foreground,
bg: cx.theme().transparent,
borders: Edges::all(px(1.)),
@ -151,6 +152,12 @@ impl TabVariant {
radius: px(99.),
..Default::default()
},
TabVariant::Pill => TabStyle {
fg: cx.theme().foreground,
bg: cx.theme().transparent,
radius: px(99.),
..Default::default()
},
TabVariant::Segmented => TabStyle {
fg: cx.theme().tab_foreground,
bg: cx.theme().transparent,
@ -187,7 +194,7 @@ impl TabVariant {
border_color: cx.theme().transparent,
..Default::default()
},
TabVariant::Pill => TabStyle {
TabVariant::Outline => TabStyle {
fg: cx.theme().secondary_foreground,
bg: cx.theme().secondary_hover,
borders: Edges::all(px(1.)),
@ -195,6 +202,12 @@ impl TabVariant {
radius: px(99.),
..Default::default()
},
TabVariant::Pill => TabStyle {
fg: cx.theme().secondary_foreground,
bg: cx.theme().secondary_hover,
radius: px(99.),
..Default::default()
},
TabVariant::Segmented => TabStyle {
fg: cx.theme().tab_foreground,
bg: cx.theme().transparent,
@ -236,7 +249,7 @@ impl TabVariant {
border_color: cx.theme().border,
..Default::default()
},
TabVariant::Pill => TabStyle {
TabVariant::Outline => TabStyle {
fg: cx.theme().primary,
bg: cx.theme().transparent,
borders: Edges::all(px(1.)),
@ -244,6 +257,12 @@ impl TabVariant {
radius: px(99.),
..Default::default()
},
TabVariant::Pill => TabStyle {
fg: cx.theme().primary_foreground,
bg: cx.theme().primary,
radius: px(99.),
..Default::default()
},
TabVariant::Segmented => TabStyle {
fg: cx.theme().tab_active_foreground,
bg: cx.theme().transparent,
@ -283,7 +302,7 @@ impl TabVariant {
},
..Default::default()
},
TabVariant::Pill => TabStyle {
TabVariant::Outline => TabStyle {
fg: cx.theme().muted_foreground,
bg: cx.theme().transparent,
borders: Edges::all(px(1.)),
@ -295,6 +314,20 @@ impl TabVariant {
radius: px(99.),
..Default::default()
},
TabVariant::Pill => TabStyle {
fg: if selected {
cx.theme().primary_foreground.opacity(0.5)
} else {
cx.theme().muted_foreground
},
bg: if selected {
cx.theme().primary.opacity(0.5)
} else {
cx.theme().transparent
},
radius: px(99.),
..Default::default()
},
TabVariant::Segmented => TabStyle {
fg: cx.theme().muted_foreground,
bg: cx.theme().tab_bar,
@ -425,6 +458,12 @@ impl Tab {
self
}
/// Use outline variant.
pub fn outline(mut self) -> Self {
self.variant = TabVariant::Outline;
self
}
/// Use Segmented variant.
pub fn segmented(mut self) -> Self {
self.variant = TabVariant::Segmented;

View file

@ -54,6 +54,12 @@ impl TabBar {
self
}
/// Set the Tab variant to Outline, all children will inherit the variant.
pub fn outline(mut self) -> Self {
self.variant = TabVariant::Outline;
self
}
/// Set the Tab variant to Segmented, all children will inherit the variant.
pub fn segmented(mut self) -> Self {
self.variant = TabVariant::Segmented;
@ -143,10 +149,14 @@ impl RenderOnce for TabBar {
let padding = Edges::all(px(0.));
(cx.theme().tab_bar, padding, px(0.))
}
TabVariant::Pill => {
TabVariant::Outline => {
let padding = Edges::all(px(0.));
(cx.theme().transparent, padding, default_gap)
}
TabVariant::Pill => {
let padding = Edges::all(px(0.));
(cx.theme().transparent, padding, px(4.))
}
TabVariant::Segmented => {
let padding_x = match self.size {
Size::XSmall => px(3.),