feat: add new theme (#61)

Reviewed-on: #61
This commit was merged in pull request #61.
This commit is contained in:
2026-10-10 00:30:42 +00:00
parent 4ef764984b
commit 602a91b4f0
94 changed files with 3337 additions and 4456 deletions
+27 -80
View File
@@ -5,9 +5,9 @@ use gpui::{
AnyElement, App, ClickEvent, Div, InteractiveElement, IntoElement, MouseButton, ParentElement,
RenderOnce, SharedString, StatefulInteractiveElement, Styled, Window, div, px,
};
use theme::ActiveTheme;
use theme::{ActiveTheme, TextStyle, Typeset as _};
use crate::{Icon, IconName, Selectable, h_flex};
use crate::{Selectable, h_flex};
pub mod tab_bar;
@@ -17,61 +17,27 @@ pub mod tab_bar;
pub struct Tab {
ix: usize,
base: Div,
pub(super) label: Option<SharedString>,
icon: Option<Icon>,
prefix: Option<AnyElement>,
pub(super) tab_bar_prefix: Option<bool>,
suffix: Option<AnyElement>,
label: Option<SharedString>,
children: Vec<AnyElement>,
pub(super) disabled: bool,
pub(super) selected: bool,
pub(super) segmented: bool,
tab_bar_prefix: Option<bool>,
suffix: Option<AnyElement>,
disabled: bool,
selected: bool,
segmented: bool,
on_click: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
}
impl From<&'static str> for Tab {
fn from(label: &'static str) -> Self {
Self::new().label(label)
}
}
impl From<String> for Tab {
fn from(label: String) -> Self {
Self::new().label(label)
}
}
impl From<SharedString> for Tab {
fn from(label: SharedString) -> Self {
Self::new().label(label)
}
}
impl From<Icon> for Tab {
fn from(icon: Icon) -> Self {
Self::default().icon(icon)
}
}
impl From<IconName> for Tab {
fn from(icon_name: IconName) -> Self {
Self::default().icon(Icon::new(icon_name))
}
}
impl Default for Tab {
fn default() -> Self {
Self {
ix: 0,
base: div(),
label: None,
icon: None,
tab_bar_prefix: None,
children: Vec::new(),
disabled: false,
selected: false,
segmented: false,
prefix: None,
suffix: None,
on_click: None,
}
@@ -90,32 +56,20 @@ impl Tab {
self
}
/// Set icon for the tab.
pub fn icon(mut self, icon: impl Into<Icon>) -> Self {
self.icon = Some(icon.into());
self
}
/// Set the left side of the tab
pub fn prefix(mut self, prefix: impl IntoElement) -> Self {
self.prefix = Some(prefix.into_any_element());
self
}
/// Set the right side of the tab
pub fn suffix(mut self, suffix: impl IntoElement) -> Self {
pub(crate) fn suffix(mut self, suffix: impl IntoElement) -> Self {
self.suffix = Some(suffix.into_any_element());
self
}
/// Set disabled state to the tab, default false.
pub fn disabled(mut self, disabled: bool) -> Self {
pub(crate) fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
/// Set the click handler for the tab.
pub fn on_click(
pub(crate) fn on_click(
mut self,
on_click: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
) -> Self {
@@ -179,8 +133,6 @@ impl RenderOnce for Tab {
ix,
base,
label,
icon,
prefix,
suffix,
children,
disabled,
@@ -193,9 +145,9 @@ impl RenderOnce for Tab {
let foreground = if disabled {
cx.theme().text_muted
} else if selected {
cx.theme().tab_active_foreground
cx.theme().text
} else {
cx.theme().tab_foreground
cx.theme().text_muted
};
let content = h_flex()
@@ -206,15 +158,11 @@ impl RenderOnce for Tab {
.overflow_hidden()
.when(segmented, |this| this.justify_center().px_1())
.when(!segmented, |this| this.justify_start())
.map(|this| match icon {
Some(icon) => this.w(px(38.)).child(icon.size_4()),
None => this
.map(|this| match label {
Some(label) => this.child(label),
None => this,
})
.children(children),
});
.map(|this| match label {
Some(label) => this.child(label),
None => this,
})
.children(children);
base.id(ix)
.group("tab")
@@ -222,16 +170,16 @@ impl RenderOnce for Tab {
.items_center()
.text_color(foreground)
.when(segmented, |this| {
this.text_xs()
this.text_style(TextStyle::Caption)
.flex_1()
.h_6()
.rounded(cx.theme().radius)
.rounded(px(theme::button_radius()))
.when(selected && !disabled, |this| {
this.bg(cx.theme().tab_active_background)
this.bg(cx.theme().bg)
.when(cx.theme().shadow, |this| this.shadow_sm())
})
.when(!selected && !disabled, |this| {
this.hover(|this| this.bg(cx.theme().tab_hover_background))
this.hover(|this| this.bg(cx.theme().element_hover))
})
})
.when(!segmented, |this| {
@@ -240,20 +188,19 @@ impl RenderOnce for Tab {
.h_7()
.gap_1()
.px_1p5()
.text_sm()
.rounded(cx.theme().radius)
.text_style(TextStyle::Callout)
.rounded(px(theme::button_radius()))
.overflow_hidden()
.when(selected && !disabled, |this| {
this.bg(cx.theme().tab_background)
this.bg(cx.theme().element_active)
})
.when(!selected && !disabled, |this| {
this.hover(|this| {
this.bg(cx.theme().tab_hover_background)
.text_color(cx.theme().tab_active_foreground)
this.bg(cx.theme().element_hover)
.text_color(cx.theme().text)
})
})
})
.when_some(prefix, |this, prefix| this.child(prefix))
.child(content)
.when_some(suffix, |this, suffix| {
this.child(
+8 -10
View File
@@ -52,25 +52,25 @@ impl TabBar {
}
/// Track the scroll of the TabBar.
pub fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
pub(crate) fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
self.scroll_handle = Some(scroll_handle.clone());
self
}
/// Set the prefix element of the TabBar
pub fn prefix(mut self, prefix: impl IntoElement) -> Self {
pub(crate) fn prefix(mut self, prefix: impl IntoElement) -> Self {
self.prefix = Some(prefix.into_any_element());
self
}
/// Set the suffix element of the TabBar
pub fn suffix(mut self, suffix: impl IntoElement) -> Self {
pub(crate) fn suffix(mut self, suffix: impl IntoElement) -> Self {
self.suffix = Some(suffix.into_any_element());
self
}
/// Add children of the TabBar.
pub fn children(mut self, children: impl IntoIterator<Item = impl Into<Tab>>) -> Self {
pub(crate) fn children(mut self, children: impl IntoIterator<Item = impl Into<Tab>>) -> Self {
self.children.extend(children.into_iter().map(Into::into));
self
}
@@ -88,14 +88,12 @@ impl TabBar {
}
/// Set the last empty space element of the TabBar.
pub fn last_empty_space(mut self, last_empty_space: impl IntoElement) -> Self {
pub(crate) fn last_empty_space(mut self, last_empty_space: impl IntoElement) -> Self {
self.last_empty_space = last_empty_space.into_any_element();
self
}
/// Set the on_click callback of the TabBar, the first parameter is the index of the clicked tab.
///
/// When this is set, the children's on_click will be ignored.
/// Set the on_click callback of the TabBar; when set, the children's on_click is ignored.
pub fn on_click<F>(mut self, on_click: F) -> Self
where
F: Fn(&usize, &mut Window, &mut App) + 'static,
@@ -124,9 +122,9 @@ impl RenderOnce for TabBar {
.min_w_0()
.refine_style(&self.style)
.when(segmented, |this| {
this.bg(cx.theme().tab_background)
this.bg(cx.theme().surface)
.p_0p5()
.rounded(cx.theme().radius)
.rounded(px(theme::button_radius()))
})
.when_some(self.prefix, |this, prefix| this.child(prefix))
.child(