Derive theme gradients and add solid paint controls
This commit is contained in:
1 parent
20395007a5
commit
831ac3a77f
18 files changed
+604
-20
No files matched your search
@@ -954,6 +954,14 @@ impl App {
|
||||
fn change(&mut self, edit: Edit) -> Task<Message> {
|
||||
match self.draft.edit(&edit) {
|
||||
Ok(()) => {
|
||||
// A shared style selection applies to both appearances while
|
||||
// retaining their authored gradient endpoints.
|
||||
for unset in visuals::paint_style_overrides(&self.draft, &edit) {
|
||||
if self.draft.edit(&unset).is_ok() {
|
||||
self.pending.push(unset);
|
||||
}
|
||||
}
|
||||
|
||||
// When a gradient exists, changing Accent also changes its
|
||||
// leading stop; otherwise the visible focus border would stay
|
||||
// on the old palette despite the control saying it changed.
|
||||
|
||||
@@ -742,6 +742,20 @@ pub fn fields(page: Page) -> Vec<Field> {
|
||||
"Focus rings and selected controls. Use a hex color.",
|
||||
"#3D7BE6",
|
||||
),
|
||||
choice(
|
||||
"theme.focus_ring.style",
|
||||
"Accent style",
|
||||
"Window focus borders and selected controls. Gradients use the theme colors unless overridden.",
|
||||
"auto",
|
||||
&[("auto", "Gradient"), ("solid", "Solid")],
|
||||
),
|
||||
choice(
|
||||
"theme.border.style",
|
||||
"Inactive border style",
|
||||
"Gradients retain the border color's transparency.",
|
||||
"auto",
|
||||
&[("auto", "Gradient"), ("solid", "Solid")],
|
||||
),
|
||||
choice(
|
||||
"theme.material.style",
|
||||
"Surface style",
|
||||
|
||||
@@ -137,6 +137,21 @@ pub fn toggle_split(snapshot: &Snapshot, enabled: bool, active: ferese_config::t
|
||||
edits
|
||||
}
|
||||
|
||||
pub fn paint_style_overrides(snapshot: &Snapshot, edit: &Edit) -> Vec<Edit> {
|
||||
let Edit::Set(path, _) = edit else { return vec![] };
|
||||
let section = match path.as_str() {
|
||||
"theme.focus_ring.style" => "focus_ring",
|
||||
"theme.border.style" => "border",
|
||||
_ => return vec![],
|
||||
};
|
||||
["light", "dark"]
|
||||
.into_iter()
|
||||
.map(|kind| format!("theme.{kind}.{section}.style"))
|
||||
.filter(|path| snapshot.item(path).is_some())
|
||||
.map(Edit::Unset)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn preset(index: usize) -> Vec<Edit> {
|
||||
let Some(preset) = PRESETS.get(index) else {
|
||||
@@ -244,6 +259,44 @@ mod tests {
|
||||
snapshot
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shared_style_controls_replace_scoped_styles_without_deleting_endpoints() {
|
||||
let mut snapshot = Snapshot::parse(
|
||||
r##"theme {
|
||||
family catppuccin
|
||||
light { focus-ring { style solid; gradient { from "#123456"; to "#654321"; }; }; }
|
||||
dark { focus-ring { style solid; gradient { from "#ABCDEF"; to "#FEDCBA"; }; }; }
|
||||
}"##
|
||||
.into(),
|
||||
)
|
||||
.unwrap();
|
||||
for (style, enabled) in [("auto", true), ("solid", false), ("auto", true)] {
|
||||
let edit = set("theme.focus_ring.style", style);
|
||||
for unset in paint_style_overrides(&snapshot, &edit) {
|
||||
snapshot.edit(&unset).unwrap();
|
||||
}
|
||||
|
||||
snapshot.edit(&edit).unwrap();
|
||||
for (mode, from) in [("light", "#123456"), ("dark", "#ABCDEF")] {
|
||||
snapshot.edit(&set("theme.mode", mode)).unwrap();
|
||||
let theme = ferese_config::theme::resolve(
|
||||
&snapshot.doc,
|
||||
std::path::Path::new("/config"),
|
||||
"2026-09-30T12:00:00Z".parse().unwrap(),
|
||||
|_| unreachable!(),
|
||||
)
|
||||
.unwrap()
|
||||
.theme;
|
||||
assert_eq!(theme.tokens.focus_ring.gradient.is_some(), enabled);
|
||||
if enabled {
|
||||
assert_eq!(theme.tokens.focus_ring.gradient.unwrap().from, from);
|
||||
}
|
||||
|
||||
assert!(snapshot.item(&format!("theme.{mode}.focus_ring.gradient")).is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn contrast(a: Color, b: Color) -> f32 {
|
||||
ferese_theme::contrast(a, b)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user