Share native theme components and fix dialog backdrop blur
Centralize native palettes, presets, typography, controls, menus, calendar rendering, and icon assets in ferese-theme. Reuse the shared components across the shell, settings, lock screen, authentication prompt, and screen-sharing chooser. Attach themed dialogs to compositor-owned materials, correct backdrop capture and sampling across output transforms, smooth patterned backgrounds, and prevent clipped picker buttons with the configured shell font.
This commit is contained in:
1 parent
362bf79012
commit
b2363a18b0
85 files changed
+2163
-1591
No files matched your search
@@ -0,0 +1,156 @@
|
||||
//! Canonical SVG assets, sizing and semantic tint rules for native Ferese UIs.
|
||||
use cosmic::{
|
||||
iced::{Color, ContentFit, Length},
|
||||
theme,
|
||||
widget::icon,
|
||||
};
|
||||
|
||||
pub const ARROW: &[u8] = include_bytes!("../assets/icons/arrow.svg");
|
||||
pub const BATTERY: &[u8] = include_bytes!("../assets/icons/battery.svg");
|
||||
pub const CHECK: &[u8] = include_bytes!("../assets/icons/check.svg");
|
||||
pub const DISPLAY: &[u8] = include_bytes!("../assets/icons/display.svg");
|
||||
pub const FERESE: &[u8] = include_bytes!("../assets/icons/ferese.svg");
|
||||
pub const OVERVIEW: &[u8] = include_bytes!("../assets/icons/overview.svg");
|
||||
pub const AIRPLANE: &[u8] = include_bytes!("../assets/icons/status/airplane.svg");
|
||||
pub const BATTERY_25: &[u8] = include_bytes!("../assets/icons/status/battery-25.svg");
|
||||
pub const BATTERY_50: &[u8] = include_bytes!("../assets/icons/status/battery-50.svg");
|
||||
pub const BATTERY_75: &[u8] = include_bytes!("../assets/icons/status/battery-75.svg");
|
||||
pub const BATTERY_CHARGING: &[u8] = include_bytes!("../assets/icons/status/battery-charging.svg");
|
||||
pub const BATTERY_EMPTY: &[u8] = include_bytes!("../assets/icons/status/battery-empty.svg");
|
||||
pub const BATTERY_FULL: &[u8] = include_bytes!("../assets/icons/status/battery-full.svg");
|
||||
pub const BLUETOOTH_CONNECTED: &[u8] =
|
||||
include_bytes!("../assets/icons/status/bluetooth-connected.svg");
|
||||
pub const BLUETOOTH_OFF: &[u8] = include_bytes!("../assets/icons/status/bluetooth-off.svg");
|
||||
pub const BLUETOOTH_ON: &[u8] = include_bytes!("../assets/icons/status/bluetooth-on.svg");
|
||||
pub const BRIGHTNESS: &[u8] = include_bytes!("../assets/icons/status/brightness.svg");
|
||||
pub const CALENDAR: &[u8] = include_bytes!("../assets/icons/status/calendar.svg");
|
||||
pub const CHEVRON_DOWN: &[u8] = include_bytes!("../assets/icons/status/chevron-down.svg");
|
||||
pub const CHEVRON_UP: &[u8] = include_bytes!("../assets/icons/status/chevron-up.svg");
|
||||
pub const CLOSE: &[u8] = include_bytes!("../assets/icons/status/close.svg");
|
||||
pub const CONTROL_CENTER: &[u8] = include_bytes!("../assets/icons/status/control-center.svg");
|
||||
pub const DND: &[u8] = include_bytes!("../assets/icons/status/dnd.svg");
|
||||
pub const ETHERNET: &[u8] = include_bytes!("../assets/icons/status/ethernet.svg");
|
||||
pub const LOCK: &[u8] = include_bytes!("../assets/icons/status/lock.svg");
|
||||
pub const MIC_MUTE: &[u8] = include_bytes!("../assets/icons/status/mic-mute.svg");
|
||||
pub const MIC: &[u8] = include_bytes!("../assets/icons/status/mic.svg");
|
||||
pub const MOON: &[u8] = include_bytes!("../assets/icons/status/moon.svg");
|
||||
pub const NOTIFICATIONS_OFF: &[u8] = include_bytes!("../assets/icons/status/notifications-off.svg");
|
||||
pub const NOTIFICATIONS: &[u8] = include_bytes!("../assets/icons/status/notifications.svg");
|
||||
pub const POWER_BALANCED: &[u8] = include_bytes!("../assets/icons/status/power-balanced.svg");
|
||||
pub const POWER_OFF: &[u8] = include_bytes!("../assets/icons/status/power-off.svg");
|
||||
pub const POWER_PERFORMANCE: &[u8] = include_bytes!("../assets/icons/status/power-performance.svg");
|
||||
pub const POWER_SAVER: &[u8] = include_bytes!("../assets/icons/status/power-saver.svg");
|
||||
pub const POWER: &[u8] = include_bytes!("../assets/icons/status/power.svg");
|
||||
pub const RECORD_CANCEL: &[u8] = include_bytes!("../assets/icons/status/record-cancel.svg");
|
||||
pub const RECORD_SAVING: &[u8] = include_bytes!("../assets/icons/status/record-saving.svg");
|
||||
pub const RECORD_STOP: &[u8] = include_bytes!("../assets/icons/status/record-stop.svg");
|
||||
pub const RECORD: &[u8] = include_bytes!("../assets/icons/status/record.svg");
|
||||
pub const RESTART: &[u8] = include_bytes!("../assets/icons/status/restart.svg");
|
||||
pub const SETTINGS: &[u8] = include_bytes!("../assets/icons/status/settings.svg");
|
||||
pub const SUSPEND: &[u8] = include_bytes!("../assets/icons/status/suspend.svg");
|
||||
pub const TRASH: &[u8] = include_bytes!("../assets/icons/status/trash.svg");
|
||||
pub const VOLUME_HIGH: &[u8] = include_bytes!("../assets/icons/status/volume-high.svg");
|
||||
pub const VOLUME_LOW: &[u8] = include_bytes!("../assets/icons/status/volume-low.svg");
|
||||
pub const VOLUME_MEDIUM: &[u8] = include_bytes!("../assets/icons/status/volume-medium.svg");
|
||||
pub const VOLUME_MUTE: &[u8] = include_bytes!("../assets/icons/status/volume-mute.svg");
|
||||
pub const WIFI_FULL: &[u8] = include_bytes!("../assets/icons/status/wifi-full.svg");
|
||||
pub const WIFI_LOW: &[u8] = include_bytes!("../assets/icons/status/wifi-low.svg");
|
||||
pub const WIFI_MEDIUM: &[u8] = include_bytes!("../assets/icons/status/wifi-medium.svg");
|
||||
pub const WIFI_OFF: &[u8] = include_bytes!("../assets/icons/status/wifi-off.svg");
|
||||
pub const VOLUME: &[u8] = include_bytes!("../assets/icons/volume.svg");
|
||||
pub const WIFI: &[u8] = include_bytes!("../assets/icons/wifi.svg");
|
||||
|
||||
pub const APPLICATION: &[u8] = include_bytes!("../../../packaging/icons/ferese.svg");
|
||||
|
||||
pub fn tinted(source: &'static [u8], size: u16, foreground: Color) -> icon::Icon {
|
||||
accented(source, size, foreground, foreground)
|
||||
}
|
||||
|
||||
pub fn symbolic(source: &'static [u8], size: u16) -> icon::Icon {
|
||||
icon::from_svg_bytes(source)
|
||||
.symbolic(true)
|
||||
.icon()
|
||||
.size(size)
|
||||
}
|
||||
|
||||
pub fn accented(source: &'static [u8], size: u16, foreground: Color, accent: Color) -> icon::Icon {
|
||||
let svg = std::str::from_utf8(source).expect("embedded SVG must be UTF-8");
|
||||
// Battery canvases are wider; reserve that space instead of stretching
|
||||
// or clipping them into the square slot used by the other status icons.
|
||||
let aspect = if svg.contains("viewBox=\"0 0 32 24\"") {
|
||||
4.0 / 3.0
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
icon::from_svg_bytes(tint_svg(source, foreground, accent))
|
||||
.symbolic(false)
|
||||
.icon()
|
||||
.size(size)
|
||||
.width(Length::Fixed(f32::from(size) * aspect))
|
||||
.content_fit(ContentFit::Contain)
|
||||
.class(theme::Svg::custom(move |_| {
|
||||
cosmic::iced::widget::svg::Style { color: None }
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn tint_svg(source: &[u8], foreground: Color, accent: Color) -> Vec<u8> {
|
||||
let rgba = |foreground: Color| {
|
||||
format!(
|
||||
"rgba({},{},{},{})",
|
||||
(foreground.r * 255.0).round() as u8,
|
||||
(foreground.g * 255.0).round() as u8,
|
||||
(foreground.b * 255.0).round() as u8,
|
||||
foreground.a,
|
||||
)
|
||||
};
|
||||
std::str::from_utf8(source)
|
||||
.expect("embedded icons must be UTF-8 SVG")
|
||||
.replace("currentColor", &rgba(foreground))
|
||||
// The source artwork's blue swatch is the semantic theme accent.
|
||||
// Battery warning/success swatches remain status colors.
|
||||
.replace("#3d7be6", &rgba(accent))
|
||||
.into_bytes()
|
||||
}
|
||||
|
||||
pub fn outline(path: &str, tint: Color, size: u16) -> icon::Icon {
|
||||
let svg = format!(
|
||||
r##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="{path}" fill="none" stroke="currentColor" stroke-width="1.6"
|
||||
stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>"##,
|
||||
);
|
||||
icon::from_svg_bytes(tint_svg(svg.as_bytes(), tint, tint))
|
||||
.symbolic(false)
|
||||
.icon()
|
||||
.size(size)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use cosmic::iced::Color;
|
||||
#[test]
|
||||
fn icons_use_theme_accent_and_preserve_battery_status_colors() {
|
||||
for (source, accent) in [
|
||||
(super::BATTERY_FULL, "#63c168"),
|
||||
(super::BATTERY_50, "#3d7be6"),
|
||||
(super::BATTERY_25, "#e0654f"),
|
||||
(super::WIFI_FULL, "#3d7be6"),
|
||||
(super::CONTROL_CENTER, "#3d7be6"),
|
||||
] {
|
||||
let svg = String::from_utf8(super::tint_svg(
|
||||
source,
|
||||
Color::from_rgb8(205, 214, 244),
|
||||
Color::from_rgb8(203, 166, 247),
|
||||
))
|
||||
.unwrap();
|
||||
assert!(!svg.contains("currentColor"));
|
||||
assert!(svg.contains("rgba(205,214,244,1)"));
|
||||
assert!(!svg.contains("#3d7be6"));
|
||||
assert!(svg.contains(if accent == "#3d7be6" {
|
||||
"rgba(203,166,247,1)"
|
||||
} else {
|
||||
accent
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user