From 322f03728980b612aacad107b727191c64671213 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Tue, 10 Nov 2026 07:17:23 +0700 Subject: [PATCH] chore: drop tab icon in favor of lead --- crates/core/Cargo.toml | 4 ++-- crates/data/src/tabs.rs | 34 +++++----------------------------- crates/layout/src/dock.rs | 7 +++++-- examples/gallery/src/main.rs | 29 ++++++++++++++++++++++++++++- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index d555ad2..99f18c8 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -63,8 +63,8 @@ badge = [] input = ["button"] clipboard = ["button"] popover = [] -scroll_area = [] -scrollbar = ["scroll_area"] +scroll_area = ["scrollbar"] +scrollbar = [] segmented = [] separator = [] spinner = [] diff --git a/crates/data/src/tabs.rs b/crates/data/src/tabs.rs index 48f22ca..6f72dca 100644 --- a/crates/data/src/tabs.rs +++ b/crates/data/src/tabs.rs @@ -10,7 +10,7 @@ use gpui_native_core::button::{Button, ButtonVariant}; use gpui_native_core::common::Sizable as _; use gpui_native_core::spinner::Spinner; use gpui_native_core::tooltip::Tooltip; -use gpui_native_icons::{Icon, IconRole}; +use gpui_native_icons::IconRole; use gpui_native_theme::{ActiveTheme as _, Size}; use gpui_native_utils::adjacent_selectable; @@ -35,7 +35,6 @@ pub struct Tab { /// The stable identity for element state; must survive reordering. key: ElementId, label: SharedString, - icon: Option, lead: Option, busy: bool, disabled: bool, @@ -53,7 +52,6 @@ impl Tab { Self { key: key.into(), label: label.into(), - icon: None, lead: None, busy: false, disabled: false, @@ -62,16 +60,7 @@ impl Tab { } } - /// Shows an icon leading the label. - pub fn icon(mut self, icon: I) -> Self - where - I: Into, - { - self.icon = Some(icon.into()); - self - } - - /// Sets the leading element. + /// Sets the leading element, e.g. an icon or an avatar. pub fn lead(mut self, lead: E) -> Self where E: IntoElement + 'static, @@ -346,22 +335,9 @@ fn render_tab( }), }; - let lead = tab.lead.take(); - let icon = tab.icon.take(); - - strip_tab = match lead { - Some(lead) => strip_tab.child(lead), - None => match variant { - TabsVariant::Underline => { - strip_tab.child(div().flex_none().pb_0p5().when_some(icon, |slot, icon| { - slot.child(icon.size(metrics.dense_icon_size).color(label_color)) - })) - } - TabsVariant::Pill => strip_tab.when_some(icon, |strip_tab, icon| { - strip_tab.child(icon.size(metrics.dense_icon_size).color(label_color)) - }), - }, - }; + if let Some(lead) = tab.lead.take() { + strip_tab = strip_tab.child(lead); + } strip_tab = strip_tab.child(tab.label.clone()); diff --git a/crates/layout/src/dock.rs b/crates/layout/src/dock.rs index 7f453e7..d3327c0 100644 --- a/crates/layout/src/dock.rs +++ b/crates/layout/src/dock.rs @@ -1038,12 +1038,15 @@ fn render_pane( .selected(selected) .tabs({ let tabs = pane.tabs.clone(); - move |_, _| { + move |_, cx| { + let theme = cx.theme(); + let metrics = theme.sizes.resolve(Size::default()); + tabs.iter() .map(|tab| { let mut entry = Tab::new(tab.panel.clone(), tab.title.clone()); if let Some(icon) = tab.icon.clone() { - entry = entry.icon(icon); + entry = entry.lead(icon.size(metrics.icon_size)); } entry.closeable(true).wrap({ let panel = tab.panel.clone(); diff --git a/examples/gallery/src/main.rs b/examples/gallery/src/main.rs index d7663a8..522b358 100644 --- a/examples/gallery/src/main.rs +++ b/examples/gallery/src/main.rs @@ -509,6 +509,7 @@ impl Gallery { SharedString::from("Blame"), ], pill_selected: 0, + lead_selected: 0, }) .into() })); @@ -2193,6 +2194,7 @@ struct TabsDemo { selected: usize, pill_tabs: Vec, pill_selected: usize, + lead_selected: usize, } impl Render for TabsDemo { @@ -2200,6 +2202,7 @@ impl Render for TabsDemo { let view = cx.entity(); let view_pill = view.clone(); let view_close = view.clone(); + let view_leads = view.clone(); let colors = cx.theme().colors; let pill_count = self.pill_tabs.len(); @@ -2281,7 +2284,31 @@ impl Render for TabsDemo { .child(format!( "{pill_count} tabs left; \"Syncing\" spins while it loads" )), - ), + ) + .child(demo_section( + "leads", + colors, + Tabs::new("tabs-demo-leads") + .variant(TabsVariant::Pill) + .selected(self.lead_selected) + .on_change(move |selected, _, cx| { + view_leads.update(cx, |demo, cx| { + demo.lead_selected = selected; + cx.notify(); + }); + }) + .tabs(|_, cx| { + let theme = cx.theme(); + let metrics = theme.sizes.resolve(Size::default()); + vec![ + Tab::new("files", "Files") + .lead(icon(IconRole::Folder).size(metrics.dense_icon_size)), + Tab::new("people", "People") + .lead(Avatar::new("ada").name("Ada Lovelace").small()), + Tab::new("plain", "Plain"), + ] + }), + )), ) } }