feat(ui): refine Graphite visuals and center navigation content

This commit is contained in:
aria committed 2026-10-28 04:09:10 +09:00
1 parent cc3b6f903f
commit 1e34ec47ad
14 files changed
+646 -121

No files matched your search

+126 -25
View File
@@ -116,14 +116,24 @@ pub fn settings_input(p: Palette) -> theme::TextInput {
let appearance = move |focused: bool, hovered: bool| cosmic::widget::text_input::Appearance {
shape: Some(BorderShape::Continuous),
outline: None,
background: mix(p.card, p.text, if hovered { 0.06 } else { 0.035 }).into(),
background: mix(p.background, p.card, if hovered { 0.55 } else { 0.35 }).into(),
border_radius: p.radius.min(7.).into(),
border_width: 1.,
border_offset: None,
border_color: if focused {
p.accent
} else {
mix(p.card, p.text, if hovered { 0.26 } else { 0.18 })
mix(
p.card,
p.text,
if p.high_contrast {
0.5
} else if hovered {
0.20
} else {
0.10
},
)
},
icon_color: Some(p.muted),
text_color: Some(p.text),
@@ -166,25 +176,52 @@ fn styled_button(
opacity: f32,
focus_visible: bool,
) -> theme::Button {
let style = move |hover: bool, focused: bool| {
let background = if selected {
mix(p.sidebar, p.accent, if hover { 0.24 } else { 0.17 })
} else if hover {
if navigation {
mix(p.card, crate::surface_shade(p.sidebar), 0.06)
} else {
mix(p.card, p.text, 0.08)
}
} else if navigation {
let style = move |hover: bool, focused: bool, pressed: bool| {
let resting = if navigation {
p.sidebar
} else {
mix(p.card, p.text, 0.035)
mix(p.background, p.card, 0.5)
};
let (background, on) = if selected {
crate::accent_pair(background, p.text)
let selected_strength = if navigation { 0.09 } else { 0.10 };
let background = if selected && navigation {
mix(
resting,
p.text,
if pressed {
0.16
} else if hover {
0.13
} else {
selected_strength
},
)
} else if selected {
mix(
resting,
p.accent,
if pressed {
0.20
} else if hover {
0.16
} else {
selected_strength
},
)
} else if hover {
mix(resting, p.text, if pressed { 0.09 } else { 0.055 })
} else {
(background, p.text)
resting
};
let mut on = crate::foreground(background, p.text);
if p.high_contrast && crate::contrast(background, on) < 7. {
on = if crate::contrast(background, Color::BLACK)
>= crate::contrast(background, Color::WHITE)
{
Color::BLACK
} else {
Color::WHITE
};
}
let mut background = background;
background.a *= if hover && opacity < 1.0 {
@@ -193,9 +230,15 @@ fn styled_button(
opacity
};
let fill = if selected {
let fill = if selected && !navigation {
p.selected_background(
if hover { 0.24 } else { 0.17 },
if pressed {
0.20
} else if hover {
0.16
} else {
0.10
},
background.a,
on,
background,
@@ -211,11 +254,23 @@ fn styled_button(
text_color: Some(on),
icon_color: Some(on),
border_radius: p.radius.min(9.).into(),
border_width: if selected || !navigation { 1. } else { 0. },
border_width: if !navigation || (selected && p.high_contrast) {
1.
} else {
0.
},
border_color: if selected {
p.accent
if p.high_contrast {
p.accent
} else {
mix(background, p.accent, 0.40)
}
} else if !navigation {
mix(p.card, p.text, 0.18)
mix(
background,
p.text,
if p.high_contrast { 0.50 } else { 0.10 },
)
} else {
Color::TRANSPARENT
},
@@ -227,10 +282,17 @@ fn styled_button(
};
theme::Button::Custom {
active: Box::new(move |focused, _| style(false, focused)),
hovered: Box::new(move |focused, _| style(true, focused)),
pressed: Box::new(move |focused, _| style(true, focused)),
disabled: Box::new(move |_| style(false, false)),
active: Box::new(move |focused, _| style(false, focused, false)),
hovered: Box::new(move |focused, _| style(true, focused, false)),
pressed: Box::new(move |focused, _| style(true, focused, true)),
disabled: Box::new(move |_| {
let mut disabled = style(false, false, false);
if !selected {
disabled.text_color = Some(p.muted);
disabled.icon_color = Some(p.muted);
}
disabled
}),
}
}
@@ -433,6 +495,45 @@ pub fn filled_button(fill: Color, foreground: Color, radius: f32, opacity: f32)
mod tests {
use super::*;
#[test]
fn navigation_selection_is_quiet_but_keyboard_focus_and_press_are_explicit() {
use cosmic::widget::button::Catalog;
for preset in ferese_config::presets::PRESETS {
let mut resolved = ferese_config::theme::default_theme();
resolved.appearance = preset.appearance;
resolved.tokens = ferese_config::theme::preset(preset.id, preset.appearance).unwrap();
for high_contrast in [false, true] {
resolved.accessibility.increase_contrast = high_contrast;
let palette = Palette::from_resolved(&resolved);
let native = palette.native_theme();
for selected in [false, true] {
let class = navigation_style(palette, selected);
let resting = native.active(false, selected, &class);
let focus = native.active(true, selected, &class);
assert_eq!(resting.outline_width, 0.);
assert_eq!(focus.outline_width, 2.);
assert_eq!(
resting.border_width,
if selected && high_contrast { 1. } else { 0. }
);
let Some(Background::Color(fill)) = resting.background else {
panic!("navigation should not be a gradient")
};
assert!(
crate::contrast(fill, resting.text_color.unwrap())
>= if high_contrast { 7. } else { 4.5 },
"{}",
preset.id
);
assert_ne!(
native.hovered(false, selected, &class).background,
native.pressed(false, selected, &class).background
);
}
}
}
}
#[test]
fn hiding_modal_focus_preserves_button_borders_and_materials() {
use cosmic::widget::button::Catalog;