feat: add new theme #61

Merged
reya merged 14 commits from new-theme into master 2026-10-10 00:30:44 +00:00
27 changed files with 292 additions and 235 deletions
Showing only changes of commit 5c15b0e840 - Show all commits
+1 -1
View File
@@ -35,7 +35,7 @@ pub use layout::{
pub use notification::*; pub use notification::*;
pub use paint::{ pub use paint::{
INK_FILL_SCALE, INK_HAIRLINE_SCALE, SCRIM_ALPHA_DARK, band, current_appearance, hairline, ink, INK_FILL_SCALE, INK_HAIRLINE_SCALE, SCRIM_ALPHA_DARK, band, current_appearance, hairline, ink,
scrim, set_current_appearance, surface_shadows, wash, plate_active, plate_hover, scrim, set_current_appearance, surface_shadows, wash,
}; };
pub use platform_kind::PlatformKind; pub use platform_kind::PlatformKind;
pub use registry::*; pub use registry::*;
+10
View File
@@ -179,3 +179,13 @@ pub(crate) fn plate_hover_for(appearance: ThemeMode, plate: gpui::Hsla) -> gpui:
pub(crate) fn plate_active_for(appearance: ThemeMode, plate: gpui::Hsla) -> gpui::Hsla { pub(crate) fn plate_active_for(appearance: ThemeMode, plate: gpui::Hsla) -> gpui::Hsla {
crate::color::flatten(ink_for(appearance, 0.16), plate) crate::color::flatten(ink_for(appearance, 0.16), plate)
} }
/// Hover over an opaque plate, for call sites outside this crate.
pub fn plate_hover(plate: gpui::Hsla) -> gpui::Hsla {
plate_hover_for(current_appearance(), plate)
}
/// Pressed over an opaque plate, for call sites outside this crate.
pub fn plate_active(plate: gpui::Hsla) -> gpui::Hsla {
plate_active_for(current_appearance(), plate)
}
+1 -2
View File
@@ -418,7 +418,7 @@ impl InteractiveElement for Avatar {
} }
impl RenderOnce for Avatar { impl RenderOnce for Avatar {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement { fn render(self, window: &mut Window, _cx: &mut App) -> impl IntoElement {
let image_size = avatar_size(self.size).to_pixels(window.rem_size()); let image_size = avatar_size(self.size).to_pixels(window.rem_size());
let content = match self.picture { let content = match self.picture {
@@ -429,7 +429,6 @@ impl RenderOnce for Avatar {
.size(image_size) .size(image_size)
.rounded_full() .rounded_full()
.object_fit(ObjectFit::Cover) .object_fit(ObjectFit::Cover)
.bg(cx.theme().ghost_element_background)
.with_fallback(move || generated_avatar(seed.as_deref(), image_size)) .with_fallback(move || generated_avatar(seed.as_deref(), image_size))
.into_any_element() .into_any_element()
} }
+48 -48
View File
@@ -4,10 +4,10 @@ use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
AnyElement, App, ClickEvent, ElementId, Hsla, InteractiveElement, IntoElement, MouseButton, AnyElement, App, ClickEvent, ElementId, Hsla, InteractiveElement, IntoElement, MouseButton,
ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement,
Styled, Window, div, relative, Styled, Window, div, px, relative,
}; };
use gpui_base::Button as BaseButton; use gpui_base::Button as BaseButton;
use theme::ActiveTheme; use theme::{ActiveTheme, bubble_radius, button_radius, plate_active, plate_hover, wash};
use crate::indicator::Indicator; use crate::indicator::Indicator;
use crate::tooltip::Tooltip; use crate::tooltip::Tooltip;
@@ -24,10 +24,10 @@ pub struct ButtonCustomVariant {
impl ButtonCustomVariant { impl ButtonCustomVariant {
pub fn new(_window: &Window, cx: &App) -> Self { pub fn new(_window: &Window, cx: &App) -> Self {
Self { Self {
color: cx.theme().element_background, color: cx.theme().solid,
foreground: cx.theme().element_foreground, foreground: cx.theme().on_solid,
hover: cx.theme().element_hover, hover: plate_hover(cx.theme().solid),
active: cx.theme().element_active, active: plate_active(cx.theme().solid),
} }
} }
@@ -293,9 +293,16 @@ impl RenderOnce for Button {
.cursor_default() .cursor_default()
.overflow_hidden() .overflow_hidden()
.map(|this| match self.rounded { .map(|this| match self.rounded {
false => this.rounded(cx.theme().radius), false => this.rounded(px(button_radius())),
true => this.rounded_full(), true => this.rounded(px(bubble_radius())),
}) })
.when_some(
match style {
ButtonVariant::Secondary => Some(cx.theme().border),
_ => None,
},
|this, border_color| this.border_1().border_color(border_color),
)
.when(!self.compact, |this| { .when(!self.compact, |this| {
if self.label.is_none() && self.children.is_empty() { if self.label.is_none() && self.children.is_empty() {
// Icon Button // Icon Button
@@ -424,15 +431,15 @@ impl ButtonVariant {
fn bg_color(&self, cx: &App) -> Hsla { fn bg_color(&self, cx: &App) -> Hsla {
match self { match self {
ButtonVariant::Primary => cx.theme().element_background, ButtonVariant::Primary => cx.theme().solid,
ButtonVariant::Secondary => cx.theme().secondary_background, ButtonVariant::Secondary => cx.theme().surface_raised,
ButtonVariant::Danger => cx.theme().danger_background, ButtonVariant::Danger => cx.theme().danger_strong,
ButtonVariant::Warning => cx.theme().warning_background, ButtonVariant::Warning => cx.theme().warning_muted,
ButtonVariant::Ghost { alt } => { ButtonVariant::Ghost { alt } => {
if *alt { if *alt {
cx.theme().ghost_element_background_alt cx.theme().surface_raised
} else { } else {
cx.theme().ghost_element_background gpui::transparent_black()
} }
} }
ButtonVariant::Custom(colors) => colors.color, ButtonVariant::Custom(colors) => colors.color,
@@ -442,11 +449,11 @@ impl ButtonVariant {
fn text_color(&self, cx: &App) -> Hsla { fn text_color(&self, cx: &App) -> Hsla {
match self { match self {
ButtonVariant::Primary => cx.theme().element_foreground, ButtonVariant::Primary => cx.theme().on_solid,
ButtonVariant::Secondary => cx.theme().secondary_foreground, ButtonVariant::Secondary => cx.theme().text,
ButtonVariant::Danger => cx.theme().danger_foreground, ButtonVariant::Danger => cx.theme().on_accent,
ButtonVariant::Warning => cx.theme().warning_foreground, ButtonVariant::Warning => cx.theme().text,
ButtonVariant::Transparent => cx.theme().text_placeholder, ButtonVariant::Transparent => cx.theme().text_faint,
ButtonVariant::Ghost { alt } => { ButtonVariant::Ghost { alt } => {
if *alt { if *alt {
cx.theme().text cx.theme().text
@@ -460,19 +467,19 @@ impl ButtonVariant {
fn hovered(&self, cx: &App) -> ButtonVariantStyle { fn hovered(&self, cx: &App) -> ButtonVariantStyle {
let bg = match self { let bg = match self {
ButtonVariant::Primary => cx.theme().element_hover, ButtonVariant::Primary => plate_hover(cx.theme().solid),
ButtonVariant::Secondary => cx.theme().secondary_hover, ButtonVariant::Secondary => cx.theme().surface_raised_hover,
ButtonVariant::Danger => cx.theme().danger_hover, ButtonVariant::Danger => plate_hover(cx.theme().danger_strong),
ButtonVariant::Warning => cx.theme().warning_hover, ButtonVariant::Warning => cx.theme().element_hover,
ButtonVariant::Ghost { .. } => cx.theme().ghost_element_hover, ButtonVariant::Ghost { .. } => cx.theme().element_hover,
ButtonVariant::Transparent => gpui::transparent_black(), ButtonVariant::Transparent => gpui::transparent_black(),
ButtonVariant::Custom(colors) => colors.hover, ButtonVariant::Custom(colors) => colors.hover,
}; };
let fg = match self { let fg = match self {
ButtonVariant::Secondary => cx.theme().secondary_foreground, ButtonVariant::Secondary => cx.theme().text,
ButtonVariant::Ghost { .. } => cx.theme().text, ButtonVariant::Ghost { .. } => cx.theme().text,
ButtonVariant::Transparent => cx.theme().text_placeholder, ButtonVariant::Transparent => cx.theme().text_faint,
_ => self.text_color(cx), _ => self.text_color(cx),
}; };
@@ -481,18 +488,18 @@ impl ButtonVariant {
fn active(&self, cx: &App) -> ButtonVariantStyle { fn active(&self, cx: &App) -> ButtonVariantStyle {
let bg = match self { let bg = match self {
ButtonVariant::Primary => cx.theme().element_active, ButtonVariant::Primary => plate_active(cx.theme().solid),
ButtonVariant::Secondary => cx.theme().secondary_active, ButtonVariant::Secondary => plate_active(cx.theme().surface_raised),
ButtonVariant::Danger => cx.theme().danger_active, ButtonVariant::Danger => plate_active(cx.theme().danger_strong),
ButtonVariant::Warning => cx.theme().warning_active, ButtonVariant::Warning => cx.theme().element_active,
ButtonVariant::Ghost { .. } => cx.theme().ghost_element_active, ButtonVariant::Ghost { .. } => cx.theme().element_active,
ButtonVariant::Transparent => gpui::transparent_black(), ButtonVariant::Transparent => gpui::transparent_black(),
ButtonVariant::Custom(colors) => colors.active, ButtonVariant::Custom(colors) => colors.active,
}; };
let fg = match self { let fg = match self {
ButtonVariant::Secondary => cx.theme().secondary_foreground, ButtonVariant::Secondary => cx.theme().text,
ButtonVariant::Transparent => cx.theme().text_placeholder, ButtonVariant::Transparent => cx.theme().text_faint,
_ => self.text_color(cx), _ => self.text_color(cx),
}; };
@@ -501,18 +508,18 @@ impl ButtonVariant {
fn selected(&self, cx: &App) -> ButtonVariantStyle { fn selected(&self, cx: &App) -> ButtonVariantStyle {
let bg = match self { let bg = match self {
ButtonVariant::Primary => cx.theme().element_selected, ButtonVariant::Primary => cx.theme().element_active,
ButtonVariant::Secondary => cx.theme().secondary_selected, ButtonVariant::Secondary => cx.theme().element_active,
ButtonVariant::Danger => cx.theme().danger_selected, ButtonVariant::Danger => plate_active(cx.theme().danger_strong),
ButtonVariant::Warning => cx.theme().warning_selected, ButtonVariant::Warning => cx.theme().element_active,
ButtonVariant::Ghost { .. } => cx.theme().ghost_element_selected, ButtonVariant::Ghost { .. } => cx.theme().element_active,
ButtonVariant::Transparent => gpui::transparent_black(), ButtonVariant::Transparent => gpui::transparent_black(),
ButtonVariant::Custom(colors) => colors.active, ButtonVariant::Custom(colors) => colors.active,
}; };
let fg = match self { let fg = match self {
ButtonVariant::Secondary => cx.theme().secondary_foreground, ButtonVariant::Secondary => cx.theme().text,
ButtonVariant::Transparent => cx.theme().text_placeholder, ButtonVariant::Transparent => cx.theme().text_faint,
_ => self.text_color(cx), _ => self.text_color(cx),
}; };
@@ -520,14 +527,7 @@ impl ButtonVariant {
} }
fn disabled(&self, cx: &App) -> ButtonVariantStyle { fn disabled(&self, cx: &App) -> ButtonVariantStyle {
let bg = match self { let bg = wash(0.08);
ButtonVariant::Danger => cx.theme().danger_disabled,
ButtonVariant::Warning => cx.theme().warning_disabled,
ButtonVariant::Ghost { .. } => cx.theme().ghost_element_disabled,
ButtonVariant::Secondary => cx.theme().secondary_disabled,
_ => cx.theme().element_disabled,
};
let fg = cx.theme().text_muted; let fg = cx.theme().text_muted;
ButtonVariantStyle { bg, fg } ButtonVariantStyle { bg, fg }
+20 -30
View File
@@ -2,13 +2,13 @@ use std::rc::Rc;
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
Animation, AnimationExt as _, AnyElement, App, BoxShadow, ClickEvent, Div, FocusHandle, Animation, AnimationExt as _, AnyElement, App, ClickEvent, Div, FocusHandle, IntoElement,
IntoElement, ParentElement, Pixels, RenderOnce, SharedString, StyleRefinement, Styled, Window, ParentElement, Pixels, RenderOnce, SharedString, StyleRefinement, Styled, Window, div, px,
div, hsla, point, px, transparent_black,
}; };
use gpui_base::{DialogBackdrop, DialogPopup, DialogTitle}; use gpui_base::{DialogBackdrop, DialogPopup, DialogTitle};
use instant::Duration; use instant::Duration;
use theme::ActiveTheme; use theme::{ActiveTheme, SCRIM_ALPHA_DARK, hairline, scrim, surface_radius, surface_shadows};
use crate::animation::cubic_bezier; use crate::animation::cubic_bezier;
use crate::button::{Button, ButtonCustomVariant, ButtonVariant, ButtonVariants as _}; use crate::button::{Button, ButtonCustomVariant, ButtonVariant, ButtonVariants as _};
@@ -278,7 +278,9 @@ impl RenderOnce for Dialog {
let backdrop = DialogBackdrop::new() let backdrop = DialogBackdrop::new()
.absolute() .absolute()
.inset_0() .inset_0()
.when(self.overlay_visible, |this| this.bg(cx.theme().overlay)) .when(self.overlay_visible, |this| {
this.bg(scrim(SCRIM_ALPHA_DARK))
})
.with_animation("fade-in", animation.clone(), move |this, delta| { .with_animation("fade-in", animation.clone(), move |this, delta| {
this.opacity(delta) this.opacity(delta)
}); });
@@ -286,11 +288,11 @@ impl RenderOnce for Dialog {
let card = DialogPopup::new() let card = DialogPopup::new()
.flex() .flex()
.flex_col() .flex_col()
.bg(cx.theme().background) .bg(cx.theme().surface_dialog)
.border_1() .border_1()
.border_color(cx.theme().border.alpha(0.4)) .border_color(hairline(0.4))
.rounded(cx.theme().radius_lg) .rounded(px(surface_radius()))
.when(cx.theme().shadow, |this| this.shadow_xl()) .when(cx.theme().shadow, |this| this.shadow(surface_shadows()))
.min_h_24() .min_h_24()
.refine_style(&self.style) .refine_style(&self.style)
.relative() .relative()
@@ -329,10 +331,10 @@ impl RenderOnce for Dialog {
.icon(IconName::CloseCircleFill) .icon(IconName::CloseCircleFill)
.custom( .custom(
ButtonCustomVariant::new(window, cx) ButtonCustomVariant::new(window, cx)
.foreground(cx.theme().icon_muted) .foreground(cx.theme().text_faint)
.color(cx.theme().ghost_element_background) .color(transparent_black())
.hover(cx.theme().ghost_element_background) .hover(cx.theme().element_hover)
.active(cx.theme().ghost_element_background), .active(cx.theme().element_active),
) )
.on_click(move |_, window, cx| { .on_click(move |_, window, cx| {
on_cancel(&ClickEvent::default(), window, cx); on_cancel(&ClickEvent::default(), window, cx);
@@ -374,23 +376,11 @@ impl RenderOnce for Dialog {
.with_animation("slide-down", animation, move |this, delta| { .with_animation("slide-down", animation, move |this, delta| {
// Settle at the target offset; only the entrance is animated. // Settle at the target offset; only the entrance is animated.
let y_offset = px(30.) * (delta - 1.); let y_offset = px(30.) * (delta - 1.);
// This is equivalent to `shadow_xl` with an extra opacity. let mut shadow = surface_shadows();
let shadow = vec![ // The shadows fade in with the slide.
BoxShadow { for shadow in &mut shadow {
color: hsla(0., 0., 0., 0.1 * delta), shadow.color.a *= delta;
offset: point(px(0.), px(20.)), }
blur_radius: px(25.),
spread_radius: px(-5.),
inset: false,
},
BoxShadow {
color: hsla(0., 0., 0., 0.1 * delta),
offset: point(px(0.), px(8.)),
blur_radius: px(10.),
spread_radius: px(-6.),
inset: false,
},
];
this.top(y_offset).shadow(shadow) this.top(y_offset).shadow(shadow)
}); });
+11 -11
View File
@@ -17,7 +17,7 @@ use gpui_base::dock::{
PaneRef, PanelId, TabGroupContext, TabGroupRenderer, PaneRef, PanelId, TabGroupContext, TabGroupRenderer,
}; };
use gpui_base::{HandleEdge, Placement, ResizeHandleContext}; use gpui_base::{HandleEdge, Placement, ResizeHandleContext};
use theme::{ActiveTheme, TABBAR_HEIGHT}; use theme::{ActiveTheme, TABBAR_HEIGHT, button_radius, panel_radius};
use crate::button::{Button, ButtonVariants as _}; use crate::button::{Button, ButtonVariants as _};
use crate::resizable::{resize_handle, resize_handle_appearance}; use crate::resizable::{resize_handle, resize_handle_appearance};
@@ -348,12 +348,12 @@ impl Render for DragPreview {
.justify_center() .justify_center()
.overflow_hidden() .overflow_hidden()
.whitespace_nowrap() .whitespace_nowrap()
.rounded(cx.theme().radius) .rounded(px(button_radius()))
.text_sm() .text_sm()
.text_color(cx.theme().text) .text_color(cx.theme().text)
.text_ellipsis() .text_ellipsis()
.when(cx.theme().shadow, |this| this.shadow_xs()) .when(cx.theme().shadow, |this| this.shadow_xs())
.bg(cx.theme().background) .bg(cx.theme().bg)
.child(panel_title(&self.panel, cx)) .child(panel_title(&self.panel, cx))
} }
} }
@@ -448,7 +448,7 @@ impl TabGroupSkin {
.flex_grow_1() .flex_grow_1()
.min_w_16() .min_w_16()
.when(droppable, |this| { .when(droppable, |this| {
this.drag_over::<DragPanel>(|this, _, _, cx| this.bg(cx.theme().surface_background)) this.drag_over::<DragPanel>(|this, _, _, cx| this.bg(cx.theme().drop_target))
.on_drop({ .on_drop({
let group = TabGroupContext::clone(group); let group = TabGroupContext::clone(group);
move |drag: &DragPanel, window, cx| { move |drag: &DragPanel, window, cx| {
@@ -467,7 +467,7 @@ impl TabGroupSkin {
let bar = TabBar::new("tab-bar") let bar = TabBar::new("tab-bar")
.track_scroll(&self.scroll_handle) .track_scroll(&self.scroll_handle)
.h(TABBAR_HEIGHT) .h(TABBAR_HEIGHT)
.bg(cx.theme().panel_background) .bg(cx.theme().surface)
.when(needs_traffic_light_padding, |this| { .when(needs_traffic_light_padding, |this| {
this.pl(px(TRAFFIC_LIGHT_PADDING)) this.pl(px(TRAFFIC_LIGHT_PADDING))
}) })
@@ -539,7 +539,7 @@ impl TabGroupSkin {
this.rounded_l_none() this.rounded_l_none()
.border_l_2() .border_l_2()
.border_r_0() .border_r_0()
.border_color(cx.theme().border) .border_color(cx.theme().drop_line)
}) })
.on_drop({ .on_drop({
let group = TabGroupContext::clone(group); let group = TabGroupContext::clone(group);
@@ -569,7 +569,7 @@ impl TabGroupSkin {
h_flex() h_flex()
.h(TABBAR_HEIGHT) .h(TABBAR_HEIGHT)
.w_full() .w_full()
.bg(cx.theme().panel_background) .bg(cx.theme().surface)
.child(bar.flex_1()) .child(bar.flex_1())
.child(window_controls()) .child(window_controls())
.into_any_element() .into_any_element()
@@ -718,7 +718,7 @@ impl TabGroupRenderer for TabGroupSkin {
.child( .child(
div() div()
.size_full() .size_full()
.bg(cx.theme().panel_background) .bg(cx.theme().surface)
.overflow_hidden() .overflow_hidden()
.child(panel.cached(StyleRefinement::default().v_flex().size_full())), .child(panel.cached(StyleRefinement::default().v_flex().size_full())),
) )
@@ -759,10 +759,10 @@ impl TabGroupRenderer for TabGroupSkin {
.top(top) .top(top)
.w(width) .w(width)
.h(height) .h(height)
.rounded(cx.theme().radius_lg) .rounded(px(panel_radius()))
.border_1() .border_1()
.border_color(cx.theme().element_disabled) .border_color(cx.theme().drop_line)
.bg(cx.theme().drop_target_background) .bg(cx.theme().drop_target)
.into_any_element(), .into_any_element(),
) )
} }
+3 -3
View File
@@ -1,7 +1,7 @@
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
AnyElement, App, ElementId, InteractiveElement as _, IntoElement, ParentElement, RenderOnce, AnyElement, App, ElementId, InteractiveElement as _, IntoElement, ParentElement, RenderOnce,
StyleRefinement, Styled, Window, div, relative, StyleRefinement, Styled, Window, div, px, relative,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use theme::ActiveTheme; use theme::ActiveTheme;
@@ -95,7 +95,7 @@ impl RenderOnce for GroupBox {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement { fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
let (bg, has_paddings) = match self.variant { let (bg, has_paddings) = match self.variant {
GroupBoxVariant::Normal => (None, false), GroupBoxVariant::Normal => (None, false),
GroupBoxVariant::Fill => (Some(cx.theme().surface_background), true), GroupBoxVariant::Fill => (Some(cx.theme().surface), true),
}; };
v_flex() v_flex()
@@ -120,7 +120,7 @@ impl RenderOnce for GroupBox {
.text_color(cx.theme().text) .text_color(cx.theme().text)
.when(has_paddings, |this| this.p_2()) .when(has_paddings, |this| this.p_2())
.gap_4() .gap_4()
.rounded(cx.theme().radius_lg) .rounded(px(theme::panel_radius()))
.children(self.children), .children(self.children),
) )
} }
+1 -1
View File
@@ -252,7 +252,7 @@ impl From<Icon> for AnyElement {
impl Render for Icon { impl Render for Icon {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let text_color = self.text_color.unwrap_or_else(|| cx.theme().icon); let text_color = self.text_color.unwrap_or_else(|| cx.theme().text_muted);
let text_size = window.text_style().font_size.to_pixels(window.rem_size()); let text_size = window.text_style().font_size.to_pixels(window.rem_size());
let has_base_size = self.style.size.width.is_some() || self.style.size.height.is_some(); let has_base_size = self.style.size.width.is_some() || self.style.size.height.is_some();
+1 -1
View File
@@ -11,5 +11,5 @@ pub(crate) fn clear_button(cx: &App) -> Button {
.ghost() .ghost()
.xsmall() .xsmall()
.tab_stop(false) .tab_stop(false)
.text_color(cx.theme().icon_muted) .text_color(cx.theme().text_faint)
} }
+8 -8
View File
@@ -6,7 +6,7 @@ use gpui::{
}; };
use gpui_base::InputBase; use gpui_base::InputBase;
use gpui_base::input::{InputBaseState, InputEditorStyle, InputMode, InputModeKind, TextareaMode}; use gpui_base::input::{InputBaseState, InputEditorStyle, InputMode, InputModeKind, TextareaMode};
use theme::ActiveTheme; use theme::{ActiveTheme, button_radius};
use crate::indicator::Indicator; use crate::indicator::Indicator;
use crate::input::clear_button; use crate::input::clear_button;
@@ -15,9 +15,9 @@ use crate::{Sizable, Size, StyleSized, StyledExt, h_flex, v_flex};
/// The background of an input frame, which reads muted while the input is disabled. /// The background of an input frame, which reads muted while the input is disabled.
fn input_background(disabled: bool, cx: &App) -> Hsla { fn input_background(disabled: bool, cx: &App) -> Hsla {
if disabled { if disabled {
cx.theme().surface_background cx.theme().surface
} else { } else {
cx.theme().elevated_surface_background cx.theme().input_bg
} }
} }
@@ -26,11 +26,11 @@ fn input_editor_style(cx: &App) -> InputEditorStyle {
let theme = cx.theme(); let theme = cx.theme();
InputEditorStyle { InputEditorStyle {
foreground: theme.text, foreground: theme.text,
muted_foreground: theme.text_muted, muted_foreground: theme.text_faint,
background: theme.elevated_surface_background, background: theme.input_bg,
border: theme.border, border: theme.border_faint,
selection: theme.selection, selection: theme.selection,
caret: theme.cursor, caret: theme.caret,
..InputEditorStyle::default() ..InputEditorStyle::default()
} }
} }
@@ -171,7 +171,7 @@ impl<M: InputModeKind> RenderOnce for Input<M> {
.when(self.appearance, |this| { .when(self.appearance, |this| {
this.bg(background) this.bg(background)
.when(self.disabled, |this| this.opacity(0.5)) .when(self.disabled, |this| this.opacity(0.5))
.rounded(cx.theme().radius) .rounded(px(button_radius()))
}) })
.tab_index(0) .tab_index(0)
.gap(gap_x) .gap(gap_x)
+2 -2
View File
@@ -171,9 +171,9 @@ impl RenderOnce for Kbd {
fn render(self, _: &mut gpui::Window, cx: &mut gpui::App) -> impl gpui::IntoElement { fn render(self, _: &mut gpui::Window, cx: &mut gpui::App) -> impl gpui::IntoElement {
div() div()
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border_faint)
.text_color(cx.theme().text_muted) .text_color(cx.theme().text_muted)
.bg(cx.theme().surface_background) .bg(cx.theme().surface_raised)
.py_0p5() .py_0p5()
.px_1() .px_1()
.min_w_5() .min_w_5()
+17 -3
View File
@@ -1,7 +1,8 @@
use std::ops::Range; use std::ops::Range;
use gpui::{ use gpui::{
AnyElement, App, ElementId, IntoElement, SharedString, StyleRefinement, Styled as _, Window, AnyElement, App, ElementId, HighlightStyle, IntoElement, SharedString, StyleRefinement,
Styled as _, Window,
}; };
use gpui_base::{TextView, TextViewStyle}; use gpui_base::{TextView, TextViewStyle};
use theme::ActiveTheme as _; use theme::ActiveTheme as _;
@@ -63,14 +64,27 @@ impl RenderedText {
pub fn element(&self, id: ElementId, _window: &Window, cx: &App) -> AnyElement { pub fn element(&self, id: ElementId, _window: &Window, cx: &App) -> AnyElement {
let theme = cx.theme(); let theme = cx.theme();
let code_block = StyleRefinement::default().font_family(code_font_family()); let code_block = StyleRefinement::default().font_family(code_font_family());
let muted_heading = theme.text_muted;
TextView::markdown(id, self.text.clone()) TextView::markdown(id, self.text.clone())
.style( .style(
TextViewStyle::default() TextViewStyle::default()
.with_foreground(theme.text) .with_foreground(theme.text)
.with_muted_foreground(theme.text_muted) .with_muted_foreground(theme.text_muted)
.with_link(theme.text_accent) // Deeply nested headings read as secondary text.
.with_code_background(theme.elevated_surface_background) .with_heading(move |level| {
if level >= 4 {
StyleRefinement::default().text_color(muted_heading)
} else {
StyleRefinement::default()
}
})
.with_link(theme.accent)
.with_code_background(theme.code_wash)
.with_inline_code(HighlightStyle {
color: Some(theme.code_text),
..Default::default()
})
.with_border(theme.border) .with_border(theme.border)
.with_code_block(code_block) .with_code_block(code_block)
.with_dark(theme.is_dark()), .with_dark(theme.is_dark()),
+5 -5
View File
@@ -101,12 +101,12 @@ impl RenderOnce for MenuItemElement {
}) })
.when(!self.disabled, |this| { .when(!self.disabled, |this| {
this.group_hover(self.group_name, |this| { this.group_hover(self.group_name, |this| {
this.bg(cx.theme().secondary_background) this.bg(cx.theme().element_hover)
.text_color(cx.theme().secondary_foreground) .text_color(cx.theme().text)
}) })
.when(self.selected, |this| { .when(self.selected, |this| {
this.bg(cx.theme().secondary_background) this.bg(cx.theme().element_active)
.text_color(cx.theme().secondary_foreground) .text_color(cx.theme().text)
}) })
.when_some(self.on_click, |this, on_click| { .when_some(self.on_click, |this, on_click| {
this.on_mouse_down(MouseButton::Left, move |_, _, cx| { this.on_mouse_down(MouseButton::Left, move |_, _, cx| {
@@ -115,7 +115,7 @@ impl RenderOnce for MenuItemElement {
.on_click(on_click) .on_click(on_click)
}) })
}) })
.when(self.disabled, |this| this.text_color(cx.theme().text_muted)) .when(self.disabled, |this| this.text_color(cx.theme().text_faint))
.children(self.children) .children(self.children)
} }
} }
+5 -4
View File
@@ -577,7 +577,7 @@ impl PopupMenu {
checked: bool, checked: bool,
icon: Option<Icon>, icon: Option<Icon>,
_: &mut Window, _: &mut Window,
_: &mut Context<Self>, cx: &mut Context<Self>,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement> {
if !has_icon { if !has_icon {
return None; return None;
@@ -586,7 +586,7 @@ impl PopupMenu {
let icon = if let Some(icon) = icon { let icon = if let Some(icon) = icon {
icon.clone() icon.clone()
} else if checked { } else if checked {
Icon::new(IconName::Check) Icon::new(IconName::Check).text_color(cx.theme().accent)
} else { } else {
Icon::empty() Icon::empty()
}; };
@@ -657,7 +657,7 @@ impl PopupMenu {
.my_0p5() .my_0p5()
.mx_neg_1() .mx_neg_1()
.border_b(px(2.)) .border_b(px(2.))
.border_color(cx.theme().border) .border_color(cx.theme().border_faint)
.disabled(true), .disabled(true),
PopupMenuItem::Label(label) => this.disabled(true).cursor_default().child( PopupMenuItem::Label(label) => this.disabled(true).cursor_default().child(
h_flex().cursor_default().items_center().gap_x_1().child( h_flex().cursor_default().items_center().gap_x_1().child(
@@ -790,7 +790,8 @@ impl Render for PopupMenu {
let options = RenderOptions { let options = RenderOptions {
has_left_icon, has_left_icon,
radius: cx.theme().radius.min(px(8.)), // Items sit p_1 (4px) inside the surface plate; keep corners concentric.
radius: px(theme::inset_radius(theme::surface_radius(), 4.0)),
}; };
v_flex() v_flex()
+3 -3
View File
@@ -192,7 +192,7 @@ impl RenderOnce for MessageRow {
h_flex() h_flex()
.gap_2() .gap_2()
.text_sm() .text_sm()
.text_color(cx.theme().text_placeholder) .text_color(cx.theme().text_dim)
.when_some(author, |this, author| { .when_some(author, |this, author| {
this.child(div().font_semibold().child(author)) this.child(div().font_semibold().child(author))
}) })
@@ -212,7 +212,7 @@ impl RenderOnce for MessageRow {
.when_some(on_double_click, |this, listener| { .when_some(on_double_click, |this, listener| {
this.on_double_click(listener) this.on_double_click(listener)
}) })
.hover(|this| this.bg(cx.theme().surface_background)) .hover(|this| this.bg(cx.theme().element_hover))
.into_any_element() .into_any_element()
} }
} }
@@ -305,7 +305,7 @@ impl RenderOnce for WelcomeMessage {
this.child( this.child(
div() div()
.text_xs() .text_xs()
.text_color(cx.theme().text_placeholder) .text_color(cx.theme().text_faint)
.child(message), .child(message),
) )
}), }),
+10 -6
View File
@@ -4,7 +4,7 @@ use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
AnyElement, App, ClickEvent, ElementId, InteractiveElement, Interactivity, IntoElement, AnyElement, App, ClickEvent, ElementId, InteractiveElement, Interactivity, IntoElement,
ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement,
Styled, Window, div, Styled, Window, div, px,
}; };
use theme::ActiveTheme; use theme::ActiveTheme;
@@ -103,6 +103,11 @@ impl Styled for Nav {
impl RenderOnce for Nav { impl RenderOnce for Nav {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let clickable = self.on_click.is_some() || self.clickable; let clickable = self.on_click.is_some() || self.clickable;
let text_color = if self.selected {
cx.theme().text
} else {
cx.theme().text_muted
};
v_flex().h_10().w_full().items_center().child( v_flex().h_10().w_full().items_center().child(
h_flex() h_flex()
@@ -111,7 +116,8 @@ impl RenderOnce for Nav {
.w_full() .w_full()
.px_1p5() .px_1p5()
.gap_1p5() .gap_1p5()
.rounded(cx.theme().radius_lg) .rounded(px(theme::button_radius()))
.text_color(text_color)
.when_some(self.prefix, |this, prefix| this.child(prefix)) .when_some(self.prefix, |this, prefix| this.child(prefix))
.child( .child(
h_flex() h_flex()
@@ -125,10 +131,8 @@ impl RenderOnce for Nav {
) )
.when(clickable, |this| { .when(clickable, |this| {
this.cursor_pointer() this.cursor_pointer()
.hover(|this| this.bg(cx.theme().ghost_element_hover)) .hover(|this| this.bg(cx.theme().element_hover))
.when(self.selected, |this| { .when(self.selected, |this| this.bg(cx.theme().element_active))
this.bg(cx.theme().ghost_element_active)
})
}) })
.when_some(self.on_click, |this, handler| { .when_some(self.on_click, |this, handler| {
this.on_click(move |event, window, cx| handler(event, window, cx)) this.on_click(move |event, window, cx| handler(event, window, cx))
+10 -7
View File
@@ -4,7 +4,7 @@ use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
AnyElement, App, ClickEvent, ElementId, InteractiveElement, Interactivity, IntoElement, AnyElement, App, ClickEvent, ElementId, InteractiveElement, Interactivity, IntoElement,
ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, StyleRefinement,
Styled, Window, div, Styled, Window, div, px,
}; };
use theme::ActiveTheme; use theme::ActiveTheme;
@@ -86,6 +86,11 @@ impl Styled for NavItem {
impl RenderOnce for NavItem { impl RenderOnce for NavItem {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let clickable = self.on_click.is_some(); let clickable = self.on_click.is_some();
let text_color = if self.selected {
cx.theme().text
} else {
cx.theme().text_muted
};
h_flex() h_flex()
.id(self.id) .id(self.id)
@@ -94,8 +99,8 @@ impl RenderOnce for NavItem {
.py_1() .py_1()
.w_full() .w_full()
.gap_2() .gap_2()
.rounded(cx.theme().radius) .rounded(px(theme::button_radius()))
.text_color(cx.theme().text) .text_color(text_color)
.child(self.icon) .child(self.icon)
.child( .child(
div() div()
@@ -110,10 +115,8 @@ impl RenderOnce for NavItem {
}) })
.when(clickable, |this| { .when(clickable, |this| {
this.cursor_pointer() this.cursor_pointer()
.hover(|this| this.bg(cx.theme().ghost_element_hover)) .hover(|this| this.bg(cx.theme().element_hover))
.when(self.selected, |this| { .when(self.selected, |this| this.bg(cx.theme().element_active))
this.bg(cx.theme().ghost_element_active)
})
}) })
.when_some(self.on_click, |this, handler| { .when_some(self.on_click, |this, handler| {
this.on_click(move |event, window, cx| handler(event, window, cx)) this.on_click(move |event, window, cx| handler(event, window, cx))
+11 -9
View File
@@ -41,10 +41,10 @@ pub enum NotificationKind {
impl NotificationKind { impl NotificationKind {
fn icon(&self, cx: &App) -> Icon { fn icon(&self, cx: &App) -> Icon {
let (name, color) = match self { let (name, color) = match self {
Self::Info => (IconName::Info, cx.theme().icon), Self::Info => (IconName::Info, cx.theme().text_muted),
Self::Success => (IconName::CheckCircle, cx.theme().icon_accent), Self::Success => (IconName::CheckCircle, cx.theme().success),
Self::Warning => (IconName::Warning, cx.theme().text_warning), Self::Warning => (IconName::Warning, cx.theme().warning),
Self::Error => (IconName::CloseCircle, cx.theme().danger_foreground), Self::Error => (IconName::CloseCircle, cx.theme().on_accent),
}; };
Icon::new(name).with_size(Size::Medium).text_color(color) Icon::new(name).with_size(Size::Medium).text_color(color)
} }
@@ -279,12 +279,12 @@ impl Render for Notification {
}; };
let background = match self.kind { let background = match self.kind {
Some(NotificationKind::Error) => cx.theme().danger_background, Some(NotificationKind::Error) => cx.theme().danger_strong,
_ => cx.theme().surface_background, _ => cx.theme().surface_overlay,
}; };
let text_color = match self.kind { let text_color = match self.kind {
Some(NotificationKind::Error) => cx.theme().danger_foreground, Some(NotificationKind::Error) => cx.theme().on_accent,
_ => cx.theme().text, _ => cx.theme().text,
}; };
@@ -305,8 +305,10 @@ impl Render for Notification {
.border_color(cx.theme().border) .border_color(cx.theme().border)
.bg(background) .bg(background)
.text_color(text_color) .text_color(text_color)
.rounded(cx.theme().radius_lg) .rounded(px(theme::surface_radius()))
.when(cx.theme().shadow, |this| this.shadow_md()) .when(cx.theme().shadow, |this| {
this.shadow(theme::surface_shadows())
})
.p_2() .p_2()
.gap_2() .gap_2()
.justify_start() .justify_start()
+3 -3
View File
@@ -12,15 +12,15 @@ pub(crate) fn resize_handle_appearance() -> ResizeHandleRenderer {
Rc::new( Rc::new(
|context: &ResizeHandleContext, _: &mut Window, cx: &mut App| { |context: &ResizeHandleContext, _: &mut Window, cx: &mut App| {
let color = if context.is_active() { let color = if context.is_active() {
cx.theme().border_selected cx.theme().border_strong
} else { } else {
cx.theme().border cx.theme().element_hover
}; };
let axis = context.axis(); let axis = context.axis();
Some( Some(
div() div()
.bg(cx.theme().border_variant) .bg(cx.theme().border_faint)
.group_hover("handle", move |this| this.bg(color)) .group_hover("handle", move |this| this.bg(color))
.when(axis.is_horizontal(), |this| this.h_full().w(HANDLE_SIZE)) .when(axis.is_horizontal(), |this| this.h_full().w(HANDLE_SIZE))
.when(axis.is_vertical(), |this| this.w_full().h(HANDLE_SIZE)) .when(axis.is_vertical(), |this| this.w_full().h(HANDLE_SIZE))
+7 -18
View File
@@ -4,14 +4,14 @@ use std::rc::Rc;
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
AnyView, App, AppContext, Bounds, Context, CursorStyle, Decorations, ElementId, Entity, AnyView, App, AppContext, Bounds, Context, CursorStyle, Decorations, ElementId, Entity,
FocusHandle, HitboxBehavior, Hsla, InteractiveElement, IntoElement, MouseButton, FocusHandle, HitboxBehavior, InteractiveElement, IntoElement, MouseButton, ParentElement as _,
ParentElement as _, Pixels, Point, Render, ResizeEdge, Size, Styled, Tiling, WeakFocusHandle, Pixels, Point, Render, ResizeEdge, Size, Styled, Tiling, WeakFocusHandle, Window, canvas, div,
Window, canvas, div, point, px, size, point, px, size,
}; };
use gpui_base::TextSelectionLayer; use gpui_base::TextSelectionLayer;
use theme::{ use theme::{
ActiveTheme, CLIENT_SIDE_DECORATION_BORDER, CLIENT_SIDE_DECORATION_ROUNDING, ActiveTheme, CLIENT_SIDE_DECORATION_BORDER, CLIENT_SIDE_DECORATION_ROUNDING,
CLIENT_SIDE_DECORATION_SHADOW, CLIENT_SIDE_DECORATION_SHADOW, surface_shadows,
}; };
use crate::dialog::Dialog; use crate::dialog::Dialog;
@@ -354,19 +354,8 @@ impl Render for Root {
.when(!tiling.right, |div| { .when(!tiling.right, |div| {
div.border_r(CLIENT_SIDE_DECORATION_BORDER) div.border_r(CLIENT_SIDE_DECORATION_BORDER)
}) })
.when(!tiling.is_tiled(), |div| { .when(!tiling.is_tiled() && cx.theme().shadow, |div| {
div.shadow(vec![gpui::BoxShadow { div.shadow(surface_shadows())
color: Hsla {
h: 0.,
s: 0.,
l: 0.,
a: 0.4,
},
blur_radius: CLIENT_SIDE_DECORATION_SHADOW / 2.,
spread_radius: px(0.),
offset: point(px(0.0), px(0.0)),
inset: false,
}])
}), }),
}) })
.on_mouse_move(|_e, _, cx| { .on_mouse_move(|_e, _, cx| {
@@ -374,7 +363,7 @@ impl Render for Root {
}) })
.size_full() .size_full()
.font_family(font_family) .font_family(font_family)
.bg(cx.theme().surface_background) .bg(cx.theme().bg)
.text_color(cx.theme().text) .text_color(cx.theme().text)
.child(TextSelectionLayer) .child(TextSelectionLayer)
.child(self.view.clone()), .child(self.view.clone()),
+7 -5
View File
@@ -1,6 +1,6 @@
use gpui::{App, Div, Pixels, Refineable, StyleRefinement, Styled, div, px}; use gpui::{App, Div, Pixels, Refineable, StyleRefinement, Styled, div, px};
pub use gpui_base::component_traits::{Disableable, Selectable}; pub use gpui_base::component_traits::{Disableable, Selectable};
use theme::ActiveTheme; use theme::{ActiveTheme, surface_radius, surface_shadows};
/// Returns a `Div` as horizontal flex layout. /// Returns a `Div` as horizontal flex layout.
pub fn h_flex() -> Div { pub fn h_flex() -> Div {
@@ -14,7 +14,7 @@ pub fn v_flex() -> Div {
/// Returns a `Div` as divider. /// Returns a `Div` as divider.
pub fn divider(cx: &App) -> Div { pub fn divider(cx: &App) -> Div {
div().my_1().w_full().h_px().bg(cx.theme().border_variant) div().my_1().w_full().h_px().bg(cx.theme().border_faint)
} }
macro_rules! font_weight { macro_rules! font_weight {
@@ -53,11 +53,13 @@ pub trait StyledExt: Styled + Sized {
/// Set as Popover style /// Set as Popover style
#[inline] #[inline]
fn popover_style(self, cx: &mut App) -> Self { fn popover_style(self, cx: &mut App) -> Self {
self.bg(cx.theme().background) let shadows = cx.theme().shadow.then(surface_shadows).unwrap_or_default();
self.bg(cx.theme().surface_overlay)
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.shadow_md() .shadow(shadows)
.rounded(cx.theme().radius_lg) .rounded(px(surface_radius()))
} }
} }
+11 -5
View File
@@ -4,7 +4,7 @@ use std::time::Duration;
use gpui::prelude::FluentBuilder as _; use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
App, ElementId, IntoElement, ParentElement as _, RenderOnce, SharedString, Styled as _, Window, App, ElementId, IntoElement, ParentElement as _, RenderOnce, SharedString, Styled as _, Window,
div, px, white, div, px, transparent_black,
}; };
use gpui_base::{Spring, Switch as BaseSwitch, SwitchThumb, SwitchTrack, spring}; use gpui_base::{Spring, Switch as BaseSwitch, SwitchThumb, SwitchTrack, spring};
use theme::ActiveTheme; use theme::ActiveTheme;
@@ -63,11 +63,17 @@ impl RenderOnce for Switch {
let on_click = self.on_click.clone(); let on_click = self.on_click.clone();
let bg = if checked { let bg = if checked {
cx.theme().element_background cx.theme().accent_strong
} else { } else {
cx.theme().elevated_surface_background cx.theme().input_bg
};
let toggle_bg = cx.theme().on_solid;
// The border is structural (it insets the thumb); it only paints when off.
let track_border = if checked {
transparent_black()
} else {
cx.theme().border
}; };
let toggle_bg = white();
let bg_width = px(36.); let bg_width = px(36.);
let bg_height = px(20.); let bg_height = px(20.);
@@ -119,7 +125,7 @@ impl RenderOnce for Switch {
.flex() .flex()
.items_center() .items_center()
.border(inset) .border(inset)
.border_color(cx.theme().border_transparent) .border_color(track_border)
.bg(bg) .bg(bg)
.cursor_pointer() .cursor_pointer()
.child( .child(
+10 -12
View File
@@ -3,7 +3,7 @@ use std::rc::Rc;
use gpui::prelude::FluentBuilder as _; use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
AnyElement, App, ClickEvent, Div, InteractiveElement, IntoElement, MouseButton, ParentElement, AnyElement, App, ClickEvent, Div, InteractiveElement, IntoElement, MouseButton, ParentElement,
RenderOnce, SharedString, StatefulInteractiveElement, Styled, Window, div, RenderOnce, SharedString, StatefulInteractiveElement, Styled, Window, div, px,
}; };
use theme::ActiveTheme; use theme::ActiveTheme;
@@ -145,9 +145,9 @@ impl RenderOnce for Tab {
let foreground = if disabled { let foreground = if disabled {
cx.theme().text_muted cx.theme().text_muted
} else if selected { } else if selected {
cx.theme().tab_active_foreground cx.theme().text
} else { } else {
cx.theme().tab_foreground cx.theme().text_muted
}; };
let content = h_flex() let content = h_flex()
@@ -173,13 +173,13 @@ impl RenderOnce for Tab {
this.text_xs() this.text_xs()
.flex_1() .flex_1()
.h_6() .h_6()
.rounded(cx.theme().radius) .rounded(px(theme::button_radius()))
.when(selected && !disabled, |this| { .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(cx.theme().shadow, |this| this.shadow_sm())
}) })
.when(!selected && !disabled, |this| { .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| { .when(!segmented, |this| {
@@ -189,15 +189,13 @@ impl RenderOnce for Tab {
.gap_1() .gap_1()
.px_1p5() .px_1p5()
.text_sm() .text_sm()
.rounded(cx.theme().radius) .rounded(px(theme::button_radius()))
.overflow_hidden() .overflow_hidden()
.when(selected && !disabled, |this| { .when(selected && !disabled, |this| this.bg(cx.theme().bg))
this.bg(cx.theme().tab_background)
})
.when(!selected && !disabled, |this| { .when(!selected && !disabled, |this| {
this.hover(|this| { this.hover(|this| {
this.bg(cx.theme().tab_hover_background) this.bg(cx.theme().element_hover)
.text_color(cx.theme().tab_active_foreground) .text_color(cx.theme().text)
}) })
}) })
}) })
+2 -2
View File
@@ -122,9 +122,9 @@ impl RenderOnce for TabBar {
.min_w_0() .min_w_0()
.refine_style(&self.style) .refine_style(&self.style)
.when(segmented, |this| { .when(segmented, |this| {
this.bg(cx.theme().tab_background) this.bg(cx.theme().surface)
.p_0p5() .p_0p5()
.rounded(cx.theme().radius) .rounded(px(theme::button_radius()))
}) })
.when_some(self.prefix, |this, prefix| this.child(prefix)) .when_some(self.prefix, |this, prefix| this.child(prefix))
.child( .child(
+6 -6
View File
@@ -4,7 +4,7 @@ use gpui::{
RenderOnce, Stateful, StatefulInteractiveElement as _, Styled, Window, WindowControlArea, div, RenderOnce, Stateful, StatefulInteractiveElement as _, Styled, Window, WindowControlArea, div,
px, px,
}; };
use theme::ActiveTheme; use theme::{ActiveTheme, plate_active};
use crate::{Icon, IconName, Sizable as _, h_flex}; use crate::{Icon, IconName, Sizable as _, h_flex};
@@ -70,7 +70,7 @@ impl ControlIcon {
#[inline] #[inline]
fn hover_fg(&self, cx: &App) -> Hsla { fn hover_fg(&self, cx: &App) -> Hsla {
if self.is_close() { if self.is_close() {
cx.theme().danger_foreground cx.theme().on_accent
} else { } else {
cx.theme().text cx.theme().text
} }
@@ -79,18 +79,18 @@ impl ControlIcon {
#[inline] #[inline]
fn hover_bg(&self, cx: &App) -> Hsla { fn hover_bg(&self, cx: &App) -> Hsla {
if self.is_close() { if self.is_close() {
cx.theme().danger_background cx.theme().danger_strong
} else { } else {
cx.theme().ghost_element_hover cx.theme().element_hover
} }
} }
#[inline] #[inline]
fn active_bg(&self, cx: &mut App) -> Hsla { fn active_bg(&self, cx: &mut App) -> Hsla {
if self.is_close() { if self.is_close() {
cx.theme().danger_active plate_active(cx.theme().danger_strong)
} else { } else {
cx.theme().ghost_element_active cx.theme().element_active
} }
} }
} }
+4 -4
View File
@@ -1,10 +1,10 @@
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled, App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
Window, relative, Window, px, relative,
}; };
use gpui_base::Tooltip as BaseTooltip; use gpui_base::Tooltip as BaseTooltip;
use theme::ActiveTheme; use theme::{ActiveTheme, control_radius};
pub struct Tooltip { pub struct Tooltip {
text: SharedString, text: SharedString,
@@ -24,9 +24,9 @@ impl Render for Tooltip {
.p_1p5() .p_1p5()
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.bg(cx.theme().surface_background) .bg(cx.theme().surface_overlay)
.when(cx.theme().shadow, |this| this.shadow_sm()) .when(cx.theme().shadow, |this| this.shadow_sm())
.rounded(cx.theme().radius) .rounded(px(control_radius()))
.text_xs() .text_xs()
.text_color(cx.theme().text) .text_color(cx.theme().text)
.line_height(relative(1.25)) .line_height(relative(1.25))
+75 -36
View File
@@ -281,51 +281,90 @@ Keep public APIs (D2). Per file, replace old token reads with new tokens,
radii with ratio functions, ad-hoc spacing with `SPACE` steps where it is a radii with ratio functions, ad-hoc spacing with `SPACE` steps where it is a
real deviation, and state washes with the paint helpers. real deviation, and state washes with the paint helpers.
- [ ] `button.rs` — variant table: Primary → `solid`/`on_solid` + - [x] `button.rs` — variant table: Primary → `solid`/`on_solid` +
`surface_raised_hover`-style plate hover; Secondary → `surface_raised_hover`-style plate hover; Secondary →
`surface_raised` + `border` + `text`; Danger → `danger_strong` + `surface_raised` + `border` + `text`; Danger → `danger_strong` +
`on_accent`; Warning → `warning_muted` chip treatment; Ghost → `on_accent`; Warning → `warning_muted` chip treatment; Ghost →
transparent + `element_hover`/`element_active`; Custom stays (sources transparent + `element_hover`/`element_active`; Custom stays (sources
defaults from new tokens). Size → bezel `ControlSize` ladder values via defaults from new tokens). Size → bezel `ControlSize` ladder values via
the existing `Size` enum. Radius: `button_radius()`, `bubble_radius()` the existing `Size` enum. Radius: `button_radius()`, `bubble_radius()`
when `rounded`. when `rounded`. *(Size ladder heights kept — bezel's 24px control
- [ ] `input/` — `input_bg`, `border_faint` resting / `border_strong` focus, heights are a consumer-visible layout change, deferred.)*
`ring`, `caret`, `selection`, `text_faint` placeholder. - [x] `input/` — `input_bg`, `border_faint` resting / `border_strong` focus,
- [ ] `dialog.rs` — `surface_dialog` over `scrim()`, `surface_radius()`, `ring`, `caret`, `selection`, `text_faint` placeholder. *(coop's Input
frame shadows. paints no frame border/ring of its own — focus mechanics untouched;
- [ ] `popover.rs`, `menu/` — `surface_overlay`, hairline border, `InputEditorStyle::border` now `border_faint`, placeholder reaches
`popover_surface` stub (D6: plain wash for now). gpui-base's `muted_foreground`, now `text_faint`.)*
- [ ] `tab.rs` — mapping table row: `bg` active plane, `element_hover` - [x] `dialog.rs` — `surface_dialog` over `scrim(SCRIM_ALPHA_DARK)`,
hover, `text_muted`/`text` labels, `border_faint` separators. `surface_radius()`, `surface_shadows()` (entrance animation scales the
- [ ] `nav.rs`, `nav_item.rs` — `element_hover`/`element_active` states, helper's shadow alphas).
`accent` selection markers. - [x] `popover.rs`, `menu/` — `surface_overlay`, hairline border,
- [ ] `title_bar.rs` — `surface`; drag handlers unchanged; height stays 36. `popover_surface` stub (D6: plain wash for now). *(The floating plate
- [ ] `tooltip.rs` — `surface_overlay` plate, `text` label. is `StyledExt::popover_style` in styled.rs; popover.rs itself paints no
- [ ] `switch.rs` — on: `accent_strong` track + `on_solid` knob; off: theme values. Menu item corners are concentric:
`inset_radius(surface_radius(), 4)`.)*
- [x] `tab.rs` — mapping table row: `bg` active plane, `element_hover`
hover, `text_muted`/`text` labels, `border_faint` separators. *(No
separator was painted before; none added — structure frozen. Segmented
track is `surface`.)*
- [x] `nav.rs`, `nav_item.rs` — `element_hover`/`element_active` states,
`accent` selection markers. *(Resting labels are now `text_muted` —
intentional visible change; radius 12→8.)*
- [x] `title_bar.rs` — the crate never read `title_bar`/`title_bar_inactive`
(consumers paint the strip); close-button danger hover reskinned to
`danger_strong`/`on_accent`/`plate_active`. Drag handlers and heights
untouched.
- [x] `tooltip.rs` — `surface_overlay` plate, `text` label,
`control_radius()`.
- [x] `switch.rs` — on: `accent_strong` track + `on_solid` knob; off:
`input_bg` track + `border`. `input_bg` track + `border`.
- [ ] `indicator.rs`, `kbd.rs` — indicator gets `success`/`busy`/`danger` - [x] `indicator.rs`, `kbd.rs` — indicator turned out to be the loading
dots; kbd: `surface_raised` + `border_faint` + `text_muted`. spinner and paints no theme values (no status dots exist in `crates/ui`
- [ ] `avatar.rs` — `border_faint` ring; keep blob behavior. — the `success`/`busy`/`danger` mapping lands at consumer call sites in
- [ ] `message.rs` — `bubble_radius()` on bubbles, `text_dim` for file-path / Phase 3). kbd: `surface_raised` + `border_faint` + `text_muted`.
secondary labels, `success`/`busy`/`danger` delivery states, `band` for - [x] `avatar.rs` — no ring/border is painted today; dropped the
composer strips. `ghost_element_background` underlay. Blob behavior kept.
- [ ] `markdown.rs` — `code_text`/`code_wash`, `SyntaxPalette`, - [x] `message.rs` — `text_dim` on the author/timestamp row, `text_faint`
`text_muted` headings hierarchy. welcome body, `element_hover` row wash. *(No bubbles, delivery states,
- [ ] `notification.rs` — `surface_overlay` plate + semantic accents. composer strips or report banners live in this file — those are
- [ ] `group_box.rs` — `panel_radius()`, `border_faint`, `band` header. consumer-side, Phase 3.)*
- [ ] `dock/`, `resizable/` — `drop_target`, `drop_line`, `border_faint`. - [x] `markdown.rs` — `code_text`/`code_wash` (added `with_inline_code`),
- [ ] `scroll/` — scrollbar paints from gpui-base tokens; verify heading hierarchy (`with_heading`: h1–h3 `text`, h4–h6 `text_muted`),
`ScrollbarMode` setting still lands via `sync_base`. links `accent`. *(Fenced-code highlighting comes from gpui-base's theme
- [ ] `root.rs` — `bg` + `border` window frame, frame shadows. via `sync_base`; `SyntaxPalette` stays unconsumed until a coop-side
- [ ] `icon.rs` — tones from text tokens; keep the `IconName` set as-is. highlighter exists.)*
- [ ] `styled.rs` — `divider()` → `border_faint` / `hairline()`; - [x] `notification.rs` — `surface_overlay` plate + `surface_radius()` +
`popover_style()` → `surface_overlay` + `surface_radius()`. Keep `surface_shadows()`; error is a full `danger_strong` plate with
`on_accent`, success/warning icons `success`/`warning`.
- [x] `group_box.rs` — `surface` plate, `panel_radius()`. *(No border or
header strip is painted today; adding them is a design change, deferred
to Phase 3/4 review.)*
- [x] `dock/`, `resizable/` — `drop_target`, `drop_line`, `border_faint`.
*(Tab-insertion line and drop-region outline both use `drop_line` now —
slightly more prominent than the old muted outline, intentional. Drag
preview/empty-space drag-over also reskinned.)*
- [x] `scroll/` — verified: zero theme reads; scrollbar paint comes from
gpui-base via `sync_base`, `ScrollbarMode` still lands.
- [x] `root.rs` — `bg` plane, `surface_shadows()` on the window frame (now
gated on `cx.theme().shadow`); decoration consts untouched.
- [x] `icon.rs` — default tone `text_muted` (was `icon`); `IconName` set and
APIs unchanged.
- [x] `styled.rs` — `divider()` → `border_faint`; `popover_style()` →
`surface_overlay` + `px(surface_radius())` + `surface_shadows()` gated
on `cx.theme().shadow` (was always-on `shadow_md`). Keep
`h_flex`/`v_flex` names (bezel's `stack::row`/`column` equivalents). `h_flex`/`v_flex` names (bezel's `stack::row`/`column` equivalents).
- [ ] `animation.rs` — leave as-is this pass; note bezel's named-motion - [x] `animation.rs` — left as-is this pass; bezel's named-motion catalog is
catalog as follow-up. a follow-up.
Validation: `cargo check -p ui`, run desktop, walk every component in Outcome: `theme::plate_hover`/`plate_active` were made public (wrappers over
light/dark against Phase 0 screenshots. the crate-internal `*_for` helpers) so `crates/ui` can reskin opaque plates.
Zero legacy-token reads remain in `crates/ui` (the Phase 3 grep already
passes inside this crate); `cargo check -p ui`, `cargo check --workspace`,
`cargo test -p theme` (11 tests) and `cargo clippy -p ui -p theme` are green.
Public APIs, element structure, sizes and heights unchanged (D2, D7).
Validation remaining: run desktop, walk every component in light/dark
against the Phase 0 screenshots.
### Phase 3 — Migrate consumers ### Phase 3 — Migrate consumers