theme: Add apply_color to theme to support merge a new color into theme color. (#353)
- Fix #334 to keep selected theme color. ## Example <img width="1472" alt="image" src="https://github.com/user-attachments/assets/3a05f58c-2720-436c-8df9-c582871d87d5"> <img width="1472" alt="image" src="https://github.com/user-attachments/assets/5b8db494-1402-4785-8d98-a87173b15284"> <img width="1472" alt="image" src="https://github.com/user-attachments/assets/0305c05b-c2fb-4fea-9a50-5aa00de504fe"> <img width="1472" alt="image" src="https://github.com/user-attachments/assets/91fbb7b6-7494-440d-95bf-2de37d6bbb44">
This commit is contained in:
parent
41c64e2912
commit
1fdcff3b51
3 changed files with 103 additions and 37 deletions
|
|
@ -14,7 +14,7 @@ use ui::{
|
|||
dock::{DockArea, DockAreaState, DockEvent, DockItem, PanelView},
|
||||
h_flex,
|
||||
popup_menu::PopupMenuExt,
|
||||
theme::{ActiveTheme, Colorize as _, Theme},
|
||||
theme::{ActiveTheme, Theme},
|
||||
ContextModal, IconName, Root, Sizable, TitleBar,
|
||||
};
|
||||
|
||||
|
|
@ -40,6 +40,7 @@ pub fn init(_app_state: Arc<AppState>, cx: &mut AppContext) {
|
|||
}
|
||||
|
||||
pub struct StoryWorkspace {
|
||||
theme_color: Option<Hsla>,
|
||||
dock_area: View<DockArea>,
|
||||
locale_selector: View<LocaleSelector>,
|
||||
theme_color_picker: View<ColorPicker>,
|
||||
|
|
@ -96,27 +97,22 @@ impl StoryWorkspace {
|
|||
let mut picker = ColorPicker::new("theme-color-picker", cx)
|
||||
.xsmall()
|
||||
.anchor(AnchorCorner::TopRight)
|
||||
.label("Primary Color");
|
||||
.label("Theme Color");
|
||||
picker.set_value(cx.theme().primary, cx);
|
||||
picker
|
||||
});
|
||||
cx.subscribe(
|
||||
&theme_color_picker,
|
||||
|_, _, ev: &ColorPickerEvent, cx| match ev {
|
||||
|this, _, ev: &ColorPickerEvent, cx| match ev {
|
||||
ColorPickerEvent::Change(color) => {
|
||||
if let Some(color) = color {
|
||||
let theme = cx.global_mut::<Theme>();
|
||||
theme.primary = *color;
|
||||
theme.primary_hover = color.lighten(0.1);
|
||||
theme.primary_active = color.darken(0.1);
|
||||
cx.refresh();
|
||||
}
|
||||
this.set_theme_color(*color, cx);
|
||||
}
|
||||
},
|
||||
)
|
||||
.detach();
|
||||
|
||||
Self {
|
||||
theme_color: None,
|
||||
dock_area,
|
||||
locale_selector,
|
||||
theme_color_picker,
|
||||
|
|
@ -125,6 +121,25 @@ impl StoryWorkspace {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_theme_color(&mut self, color: Option<Hsla>, cx: &mut ViewContext<Self>) {
|
||||
self.theme_color = color;
|
||||
if let Some(color) = self.theme_color {
|
||||
let theme = cx.global_mut::<Theme>();
|
||||
theme.apply_color(color);
|
||||
cx.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
fn change_color_mode(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
|
||||
let mode = match cx.theme().mode.is_dark() {
|
||||
true => ui::theme::ThemeMode::Light,
|
||||
false => ui::theme::ThemeMode::Dark,
|
||||
};
|
||||
|
||||
Theme::change(mode, cx);
|
||||
self.set_theme_color(self.theme_color, cx);
|
||||
}
|
||||
|
||||
fn save_layout(&mut self, dock_area: View<DockArea>, cx: &mut ViewContext<Self>) {
|
||||
self._save_layout_task = Some(cx.spawn(|this, mut cx| async move {
|
||||
Timer::after(Duration::from_secs(10)).await;
|
||||
|
|
@ -336,14 +351,7 @@ impl Render for StoryWorkspace {
|
|||
})
|
||||
.small()
|
||||
.ghost()
|
||||
.on_click(move |_, cx| {
|
||||
let mode = match cx.theme().mode.is_dark() {
|
||||
true => ui::theme::ThemeMode::Light,
|
||||
false => ui::theme::ThemeMode::Dark,
|
||||
};
|
||||
|
||||
Theme::change(mode, cx);
|
||||
}),
|
||||
.on_click(cx.listener(Self::change_color_mode)),
|
||||
)
|
||||
.child(self.locale_selector.clone())
|
||||
.child(
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@ use gpui::{
|
|||
};
|
||||
|
||||
use ui::{
|
||||
button::{Button, ButtonStyled},
|
||||
button_group::ButtonGroup,
|
||||
checkbox::Checkbox,
|
||||
dropdown::{Dropdown, DropdownEvent, DropdownItem, SearchableVec},
|
||||
h_flex,
|
||||
theme::ActiveTheme,
|
||||
v_flex, FocusableCycle, IconName, Selectable, Sizable,
|
||||
v_flex, FocusableCycle, IconName, Sizable,
|
||||
};
|
||||
|
||||
actions!(dropdown_story, [Tab, TabPrev]);
|
||||
|
|
@ -232,22 +231,12 @@ impl Render for DropdownStory {
|
|||
.size_full()
|
||||
.gap_4()
|
||||
.child(
|
||||
ButtonGroup::new("button-group")
|
||||
.primary()
|
||||
.small()
|
||||
.on_click(cx.listener(|this, index: &Vec<usize>, cx| {
|
||||
this.toggle_disabled(index.contains(&1), cx);
|
||||
}))
|
||||
.child(
|
||||
Button::new("Enable")
|
||||
.label("Enable")
|
||||
.selected(!self.disabled),
|
||||
)
|
||||
.child(
|
||||
Button::new("Disable")
|
||||
.label("Disable")
|
||||
.selected(self.disabled),
|
||||
),
|
||||
Checkbox::new("disable-dropdowns")
|
||||
.label("Disabled")
|
||||
.checked(self.disabled)
|
||||
.on_click(cx.listener(|this, checked, cx| {
|
||||
this.toggle_disabled(*checked, cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ pub trait Colorize {
|
|||
fn invert_l(&self) -> Hsla;
|
||||
fn lighten(&self, amount: f32) -> Hsla;
|
||||
fn darken(&self, amount: f32) -> Hsla;
|
||||
fn apply(&self, base_color: Hsla) -> Hsla;
|
||||
}
|
||||
|
||||
impl Colorize for Hsla {
|
||||
|
|
@ -128,6 +129,16 @@ impl Colorize for Hsla {
|
|||
|
||||
Hsla { l, ..*self }
|
||||
}
|
||||
|
||||
/// Return a new color with the same lightness and alpha but different hue and saturation.
|
||||
fn apply(&self, new_color: Hsla) -> Hsla {
|
||||
Hsla {
|
||||
h: new_color.h,
|
||||
s: new_color.s,
|
||||
l: self.l,
|
||||
a: self.a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
@ -331,6 +342,64 @@ impl Theme {
|
|||
pub fn get_global(cx: &AppContext) -> &Self {
|
||||
cx.global::<Self>()
|
||||
}
|
||||
|
||||
pub fn apply_color(&mut self, mask_color: Hsla) {
|
||||
self.title_bar_background = self.title_bar_background.apply(mask_color);
|
||||
self.background = self.background.apply(mask_color);
|
||||
self.foreground = self.foreground.apply(mask_color);
|
||||
self.card = self.card.apply(mask_color);
|
||||
self.card_foreground = self.card_foreground.apply(mask_color);
|
||||
self.popover = self.popover.apply(mask_color);
|
||||
self.popover_foreground = self.popover_foreground.apply(mask_color);
|
||||
self.primary = self.primary.apply(mask_color);
|
||||
self.primary_hover = self.primary_hover.apply(mask_color);
|
||||
self.primary_active = self.primary_active.apply(mask_color);
|
||||
self.primary_foreground = self.primary_foreground.apply(mask_color);
|
||||
self.secondary = self.secondary.apply(mask_color);
|
||||
self.secondary_hover = self.secondary_hover.apply(mask_color);
|
||||
self.secondary_active = self.secondary_active.apply(mask_color);
|
||||
self.secondary_foreground = self.secondary_foreground.apply(mask_color);
|
||||
self.destructive = self.destructive.apply(mask_color);
|
||||
self.destructive_hover = self.destructive_hover.apply(mask_color);
|
||||
self.destructive_active = self.destructive_active.apply(mask_color);
|
||||
self.destructive_foreground = self.destructive_foreground.apply(mask_color);
|
||||
self.muted = self.muted.apply(mask_color);
|
||||
self.muted_foreground = self.muted_foreground.apply(mask_color);
|
||||
self.accent = self.accent.apply(mask_color);
|
||||
self.accent_foreground = self.accent_foreground.apply(mask_color);
|
||||
self.border = self.border.apply(mask_color);
|
||||
self.input = self.input.apply(mask_color);
|
||||
self.ring = self.ring.apply(mask_color);
|
||||
self.selection = self.selection.apply(mask_color);
|
||||
self.scrollbar = self.scrollbar.apply(mask_color);
|
||||
self.scrollbar_thumb = self.scrollbar_thumb.apply(mask_color);
|
||||
self.panel = self.panel.apply(mask_color);
|
||||
self.drag_border = self.drag_border.apply(mask_color);
|
||||
self.drop_target = self.drop_target.apply(mask_color);
|
||||
self.tab_bar = self.tab_bar.apply(mask_color);
|
||||
self.tab = self.tab.apply(mask_color);
|
||||
self.tab_active = self.tab_active.apply(mask_color);
|
||||
self.tab_foreground = self.tab_foreground.apply(mask_color);
|
||||
self.tab_active_foreground = self.tab_active_foreground.apply(mask_color);
|
||||
self.progress_bar = self.progress_bar.apply(mask_color);
|
||||
self.slider_bar = self.slider_bar.apply(mask_color);
|
||||
self.slider_thumb = self.slider_thumb.apply(mask_color);
|
||||
self.list = self.list.apply(mask_color);
|
||||
self.list_even = self.list_even.apply(mask_color);
|
||||
self.list_head = self.list_head.apply(mask_color);
|
||||
self.list_active = self.list_active.apply(mask_color);
|
||||
self.list_hover = self.list_hover.apply(mask_color);
|
||||
self.table = self.table.apply(mask_color);
|
||||
self.table_even = self.table_even.apply(mask_color);
|
||||
self.table_active = self.table_active.apply(mask_color);
|
||||
self.table_hover = self.table_hover.apply(mask_color);
|
||||
self.table_row_border = self.table_row_border.apply(mask_color);
|
||||
self.table_head_foreground = self.table_head_foreground.apply(mask_color);
|
||||
self.link = self.link.apply(mask_color);
|
||||
self.link_hover = self.link_hover.apply(mask_color);
|
||||
self.link_active = self.link_active.apply(mask_color);
|
||||
self.skeleton = self.skeleton.apply(mask_color);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Colors> for Theme {
|
||||
|
|
|
|||
Loading…
Reference in a new issue