update theme
This commit is contained in:
@@ -1244,7 +1244,7 @@ impl ChatPanel {
|
||||
.w_full()
|
||||
.px_2()
|
||||
.border_l_2()
|
||||
.border_color(cx.theme().accent.active)
|
||||
.border_color(cx.theme().accent.strong)
|
||||
.text_sm()
|
||||
.child(div().font_semibold().child(author.name()))
|
||||
.child(
|
||||
@@ -1647,7 +1647,7 @@ impl ChatPanel {
|
||||
.border_1()
|
||||
.border_color(cx.theme().border)
|
||||
.rounded(cx.theme().radius)
|
||||
.child(Icon::new(IconName::Lock).text_color(cx.theme().accent.primary))
|
||||
.child(Icon::new(IconName::Lock).text_color(cx.theme().accent.strong))
|
||||
.child(
|
||||
v_flex()
|
||||
.min_w_0()
|
||||
@@ -1753,7 +1753,7 @@ impl ChatPanel {
|
||||
.w_full()
|
||||
.pl_2()
|
||||
.border_l_2()
|
||||
.border_color(cx.theme().accent.active)
|
||||
.border_color(cx.theme().accent.strong)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
|
||||
@@ -180,8 +180,8 @@ pub(crate) fn render_activity(ix: usize, activity: &Activity, cx: &App) -> AnyEl
|
||||
|
||||
fn badge(activity: &Activity, cx: &App) -> AnyElement {
|
||||
let (icon, color) = match activity.kind {
|
||||
Kind::GroupJoinRequest => (IconName::Login, cx.theme().accent.primary),
|
||||
Kind::GroupPutUser => (IconName::Login, cx.theme().accent.primary),
|
||||
Kind::GroupJoinRequest => (IconName::Login, cx.theme().accent.strong),
|
||||
Kind::GroupPutUser => (IconName::Login, cx.theme().accent.strong),
|
||||
Kind::GroupLeaveRequest => (IconName::Logout, cx.theme().danger),
|
||||
Kind::GroupRemoveUser => (IconName::Ban, cx.theme().danger),
|
||||
_ => (IconName::Info, cx.theme().text_faint),
|
||||
|
||||
@@ -241,7 +241,7 @@ fn coop_dark() -> ThemeVariant {
|
||||
appearance: Appearance::Dark,
|
||||
treatment: SurfaceTreatment::Frosted,
|
||||
background: "#060606",
|
||||
shell: "#0d0d0d",
|
||||
shell: "#16161b",
|
||||
raised: "#343438",
|
||||
card: "#0e0e0e",
|
||||
text: "#e8e8ea",
|
||||
@@ -274,18 +274,18 @@ fn coop_light() -> ThemeVariant {
|
||||
name: "Coop Light",
|
||||
appearance: Appearance::Light,
|
||||
treatment: SurfaceTreatment::Frosted,
|
||||
background: "#ffffff",
|
||||
shell: "#f3f3f5",
|
||||
raised: "#ededf0",
|
||||
background: "#fffdf4",
|
||||
shell: "#f7f3e8",
|
||||
raised: "#ede8d8",
|
||||
card: "#ffffff",
|
||||
text: "#303035",
|
||||
muted: "#62626a",
|
||||
faint: "#797981",
|
||||
accent: "#a19200",
|
||||
text: "#33302a",
|
||||
muted: "#6d675a",
|
||||
faint: "#87816f",
|
||||
accent: "#FFE629",
|
||||
danger: "#dc2626",
|
||||
warning: "#a16207",
|
||||
success: "#15803d",
|
||||
terminal_background: "#fafafa",
|
||||
terminal_background: "#fbf8ee",
|
||||
ansi: ANSI_LIGHT,
|
||||
syntax: [
|
||||
"#6b7280", "#5b43e8", "#15803d", "#a16207", "#7e22ce", "#2563eb", "#be185d", "#303035",
|
||||
|
||||
@@ -29,7 +29,7 @@ pub fn init(cx: &mut App) {
|
||||
log::warn!("theme {}: {}", issue.variant_id, issue.message);
|
||||
}
|
||||
|
||||
Theme::sync_system_appearance(None, cx);
|
||||
Theme::change(Appearance::default(), None, cx);
|
||||
Theme::sync_scrollbar_appearance(cx);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ pub fn sync_base(cx: &mut App) {
|
||||
tokens.destructive_foreground = accent.on_danger;
|
||||
tokens.border = colors.border;
|
||||
tokens.input = colors.input;
|
||||
tokens.ring = accent.primary;
|
||||
tokens.ring = accent.strong;
|
||||
tokens.selection = accent.selection;
|
||||
}
|
||||
|
||||
|
||||
+20
-13
@@ -109,10 +109,11 @@ impl Color {
|
||||
}
|
||||
|
||||
pub fn best_on_color(self) -> Self {
|
||||
if Self::WHITE.contrast(self) >= Self::BLACK.contrast(self) {
|
||||
Self::WHITE
|
||||
} else {
|
||||
// Dark surfaces carry white text even where black would contrast more.
|
||||
if self.luminance() > 0.3 {
|
||||
Self::BLACK
|
||||
} else {
|
||||
Self::WHITE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +276,7 @@ impl AccentPreset {
|
||||
|
||||
pub fn color(self, appearance: Appearance) -> Color {
|
||||
let (dark, light) = match self {
|
||||
Self::Coop => ("#FFE629", "#a19200"),
|
||||
Self::Coop => ("#FFE629", "#FFE629"),
|
||||
Self::Orange => ("#fb923c", "#c2410c"),
|
||||
Self::Amber => ("#fbbf24", "#a16207"),
|
||||
Self::Green => ("#4ade80", "#15803d"),
|
||||
@@ -320,11 +321,17 @@ pub struct AccentRoles {
|
||||
|
||||
impl AccentRoles {
|
||||
pub fn derive(primary: Color, appearance: Appearance, background: Color) -> Self {
|
||||
let primary = primary.ensure_contrast(background, 3.0);
|
||||
// Light mode keeps the raw brand accent for fills; `strong` backs strokes at 3:1.
|
||||
let (primary, mut strong) = if appearance.is_dark() {
|
||||
let primary = primary.ensure_contrast(background, 3.0);
|
||||
(primary, primary)
|
||||
} else {
|
||||
(primary, primary.ensure_contrast(background, 3.0))
|
||||
};
|
||||
let on = primary.best_on_color();
|
||||
let mut strong = primary;
|
||||
if on.contrast(strong) < 4.5 {
|
||||
strong = strong.ensure_contrast(on, 4.5);
|
||||
// 3:1 pairing so white-on-dark accents don't force the fill darker.
|
||||
if on.contrast(strong) < 3.0 {
|
||||
strong = strong.ensure_contrast(on, 3.0);
|
||||
}
|
||||
let light = primary.mix(
|
||||
if appearance.is_dark() {
|
||||
@@ -528,8 +535,8 @@ impl ThemeRegistry {
|
||||
validate_contrast(
|
||||
&mut issues,
|
||||
variant,
|
||||
"accent",
|
||||
variant.accent.primary,
|
||||
"accent-strong",
|
||||
variant.accent.strong,
|
||||
variant.colors.background,
|
||||
3.0,
|
||||
);
|
||||
@@ -539,7 +546,7 @@ impl ThemeRegistry {
|
||||
"on-accent",
|
||||
variant.accent.on,
|
||||
variant.accent.strong,
|
||||
4.5,
|
||||
3.0,
|
||||
);
|
||||
validate_contrast(
|
||||
&mut issues,
|
||||
@@ -667,11 +674,11 @@ mod tests {
|
||||
for preset in AccentPreset::ALL {
|
||||
let roles = AccentRoles::derive(preset.color(appearance), appearance, background);
|
||||
assert!(
|
||||
roles.primary.contrast(background) >= 3.0,
|
||||
roles.strong.contrast(background) >= 3.0,
|
||||
"{appearance:?} {preset:?}"
|
||||
);
|
||||
assert!(
|
||||
roles.on.contrast(roles.strong) >= 4.5,
|
||||
roles.on.contrast(roles.strong) >= 3.0,
|
||||
"{appearance:?} {preset:?}"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ fn hsla(color: Color) -> Hsla {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ResolvedAccentRoles {
|
||||
pub primary: Hsla,
|
||||
/// Accent for strokes, icons, and text on the background; meets 3:1 contrast.
|
||||
pub strong: Hsla,
|
||||
pub wash: Hsla,
|
||||
pub on: Hsla,
|
||||
pub selection: Hsla,
|
||||
@@ -32,6 +34,7 @@ impl ResolvedAccentRoles {
|
||||
let wash_background = accent.wash.blend_over(background);
|
||||
Self {
|
||||
primary: hsla(accent.primary),
|
||||
strong: hsla(accent.strong),
|
||||
wash: hsla(accent.wash),
|
||||
on: hsla(accent.on),
|
||||
selection: hsla(accent.selection),
|
||||
|
||||
@@ -10,15 +10,6 @@ use crate::model::{
|
||||
use crate::resolved::{ResolvedAccentRoles, ResolvedColors};
|
||||
use crate::{NotificationSettings, PlatformKind, ScrollbarMode, sync_base};
|
||||
|
||||
impl From<gpui::WindowAppearance> for Appearance {
|
||||
fn from(appearance: gpui::WindowAppearance) -> Self {
|
||||
match appearance {
|
||||
gpui::WindowAppearance::Dark | gpui::WindowAppearance::VibrantDark => Self::Dark,
|
||||
gpui::WindowAppearance::Light | gpui::WindowAppearance::VibrantLight => Self::Light,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Theme {
|
||||
pub variant: Arc<ThemeVariant>,
|
||||
@@ -99,15 +90,6 @@ impl Theme {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sync_system_appearance(window: Option<&mut Window>, cx: &mut App) {
|
||||
let appearance = window
|
||||
.as_ref()
|
||||
.map(|window| window.appearance())
|
||||
.unwrap_or_else(|| cx.window_appearance());
|
||||
|
||||
Self::change(appearance, window, cx);
|
||||
}
|
||||
|
||||
pub fn sync_scrollbar_appearance(cx: &mut App) {
|
||||
Theme::global_mut(cx).scrollbar_mode = if cx.should_auto_hide_scrollbars() {
|
||||
ScrollbarMode::Scrolling
|
||||
|
||||
@@ -465,7 +465,7 @@ impl TabGroupSkin {
|
||||
let bar = TabBar::new("tab-bar")
|
||||
.track_scroll(&self.scroll_handle)
|
||||
.h(TABBAR_HEIGHT)
|
||||
.bg(cx.theme().shell)
|
||||
.bg(cx.theme().background)
|
||||
.when(needs_traffic_light_padding, |this| {
|
||||
this.pl(px(TRAFFIC_LIGHT_PADDING))
|
||||
})
|
||||
@@ -567,7 +567,7 @@ impl TabGroupSkin {
|
||||
h_flex()
|
||||
.h(TABBAR_HEIGHT)
|
||||
.w_full()
|
||||
.bg(cx.theme().shell)
|
||||
.bg(cx.theme().background)
|
||||
.child(bar.flex_1())
|
||||
.child(window_controls())
|
||||
.into_any_element()
|
||||
@@ -717,7 +717,7 @@ impl TabGroupRenderer for TabGroupSkin {
|
||||
.child(
|
||||
div()
|
||||
.size_full()
|
||||
.bg(cx.theme().shell)
|
||||
.bg(cx.theme().background)
|
||||
.overflow_hidden()
|
||||
.child(panel.cached(StyleRefinement::default().v_flex().size_full())),
|
||||
)
|
||||
@@ -760,7 +760,7 @@ impl TabGroupRenderer for TabGroupSkin {
|
||||
.h(height)
|
||||
.rounded(cx.theme().radius_lg)
|
||||
.border_1()
|
||||
.border_color(cx.theme().accent.primary.opacity(0.3))
|
||||
.border_color(cx.theme().accent.strong.opacity(0.3))
|
||||
.bg(cx.theme().accent.selection)
|
||||
.into_any_element(),
|
||||
)
|
||||
|
||||
@@ -69,7 +69,7 @@ impl RenderedText {
|
||||
TextViewStyle::default()
|
||||
.with_foreground(theme.text)
|
||||
.with_muted_foreground(theme.text_muted)
|
||||
.with_link(theme.accent.primary)
|
||||
.with_link(theme.accent.strong)
|
||||
.with_code_background(theme.raised)
|
||||
.with_border(theme.border)
|
||||
.with_code_block(code_block)
|
||||
|
||||
@@ -46,7 +46,7 @@ impl NotificationKind {
|
||||
.text_color(cx.theme().text_muted),
|
||||
Self::Success => Icon::new(IconName::CheckCircle)
|
||||
.with_size(Size::Medium)
|
||||
.text_color(cx.theme().accent.primary),
|
||||
.text_color(cx.theme().accent.strong),
|
||||
Self::Warning => Icon::new(IconName::Warning)
|
||||
.with_size(Size::Medium)
|
||||
.text_color(cx.theme().warning),
|
||||
|
||||
@@ -12,7 +12,7 @@ pub(crate) fn resize_handle_appearance() -> ResizeHandleRenderer {
|
||||
Rc::new(
|
||||
|context: &ResizeHandleContext, _: &mut Window, cx: &mut App| {
|
||||
let color = if context.is_active() {
|
||||
cx.theme().accent.primary
|
||||
cx.theme().accent.strong
|
||||
} else {
|
||||
cx.theme().border
|
||||
};
|
||||
|
||||
@@ -533,7 +533,7 @@ fn status_badge(status: Option<bool>, cx: &App) -> Div {
|
||||
if let Some(status) = status {
|
||||
this.child(Icon::new(IconName::CheckCircle).small().text_color({
|
||||
if status {
|
||||
cx.theme().accent.primary
|
||||
cx.theme().accent.strong
|
||||
} else {
|
||||
cx.theme().text_faint
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use nostr_sdk::prelude::*;
|
||||
use serde::Deserialize;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use state::{NostrRegistry, StateEvent};
|
||||
use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry, ThemeVariant};
|
||||
use theme::{ActiveTheme, SIDEBAR_WIDTH, ThemeRegistry, ThemeVariant};
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::dock::{self, DockArea, DockLayout, DockPlacement, Panel, PanelHandle};
|
||||
use ui::notification::{Notification, NotificationKind};
|
||||
@@ -82,13 +82,6 @@ impl Workspace {
|
||||
|
||||
let mut subscriptions = smallvec![];
|
||||
|
||||
subscriptions.push(
|
||||
// Observe system appearance and update theme
|
||||
cx.observe_window_appearance(window, |_this, window, cx| {
|
||||
Theme::sync_system_appearance(Some(window), cx);
|
||||
}),
|
||||
);
|
||||
|
||||
subscriptions.push(
|
||||
// Subscribe to the nostr events
|
||||
cx.subscribe_in(&nostr, window, move |_this, _state, event, window, cx| {
|
||||
|
||||
@@ -336,7 +336,7 @@ impl Render for Sidebar {
|
||||
.text_xs()
|
||||
.font_semibold()
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child(Indicator::new().small().color(cx.theme().accent.primary))
|
||||
.child(Indicator::new().small().color(cx.theme().accent.strong))
|
||||
.child("Getting messages..."),
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user