From 8f2ca40c514a1a15c3d2a8daccfacb5ba6a13514 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 7 Mar 2025 18:46:47 +0800 Subject: [PATCH] tab: Add new `pill` style, renamed old `pill` tab to `outline`. (#696) image ## Break Changes - As you see on the above screenshot, the old `pill` style has been renamed to `outline`. --- crates/story/src/accordion_story.rs | 4 +- crates/story/src/scrollable_story.rs | 6 ++- crates/story/src/tabs_story.rs | 66 ++++++++++++++++++---------- crates/ui/src/tab/tab.rs | 55 +++++++++++++++++++---- crates/ui/src/tab/tab_bar.rs | 12 ++++- 5 files changed, 110 insertions(+), 33 deletions(-) diff --git a/crates/story/src/accordion_story.rs b/crates/story/src/accordion_story.rs index c43fa0d0..31cf445b 100644 --- a/crates/story/src/accordion_story.rs +++ b/crates/story/src/accordion_story.rs @@ -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") diff --git a/crates/story/src/scrollable_story.rs b/crates/story/src/scrollable_story.rs index eceb1103..83287101 100644 --- a/crates/story/src/scrollable_story.rs +++ b/crates/story/src/scrollable_story.rs @@ -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") diff --git a/crates/story/src/tabs_story.rs b/crates/story/src/tabs_story.rs index ede83467..7371a699 100644 --- a/crates/story/src/tabs_story.rs +++ b/crates/story/src/tabs_story.rs @@ -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"), - ), - ) } } diff --git a/crates/ui/src/tab/tab.rs b/crates/ui/src/tab/tab.rs index a92e2f55..7ca15e56 100644 --- a/crates/ui/src/tab/tab.rs +++ b/crates/ui/src/tab/tab.rs @@ -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; diff --git a/crates/ui/src/tab/tab_bar.rs b/crates/ui/src/tab/tab_bar.rs index ce16a25d..380c1125 100644 --- a/crates/ui/src/tab/tab_bar.rs +++ b/crates/ui/src/tab/tab_bar.rs @@ -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.),