feat: add support for dark / light mode switching and simultaneouscustom light / dark mode themes
This commit is contained in:
parent
a91deacff5
commit
b1b32b867c
9 changed files with 186 additions and 21 deletions
|
|
@ -28,7 +28,7 @@ fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
let write_each_config_field = fields.iter().map(|field| {
|
let write_each_config_field = fields.iter().map(|field| {
|
||||||
let field_name = &field.ident;
|
let field_name = &field.ident;
|
||||||
quote! {
|
quote! {
|
||||||
config.set(stringify!(#field_name), &self.#field_name)?;
|
cosmic_config::ConfigSet::set(config, stringify!(#field_name), &self.#field_name)?;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
let field_name = &field.ident;
|
let field_name = &field.ident;
|
||||||
let field_type = &field.ty;
|
let field_type = &field.ty;
|
||||||
quote! {
|
quote! {
|
||||||
match config.get::<#field_type>(stringify!(#field_name)) {
|
match cosmic_config::ConfigGet::get::<#field_type>(config, stringify!(#field_name)) {
|
||||||
Ok(#field_name) => default.#field_name = #field_name,
|
Ok(#field_name) => default.#field_name = #field_name,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
|
|
@ -60,13 +60,13 @@ fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
|
|
||||||
let gen = quote! {
|
let gen = quote! {
|
||||||
impl CosmicConfigEntry for #name {
|
impl CosmicConfigEntry for #name {
|
||||||
fn write_entry(&self, config: &Config) -> Result<(), cosmic_config::Error> {
|
fn write_entry(&self, config: &cosmic_config::Config) -> Result<(), cosmic_config::Error> {
|
||||||
let tx = config.transaction();
|
let tx = config.transaction();
|
||||||
#(#write_each_config_field)*
|
#(#write_each_config_field)*
|
||||||
tx.commit()
|
tx.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_entry(config: &Config) -> Result<Self, (Vec<cosmic_config::Error>, Self)> {
|
fn get_entry(config: &cosmic_config::Config) -> Result<Self, (Vec<cosmic_config::Error>, Self)> {
|
||||||
let mut default = Self::default();
|
let mut default = Self::default();
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -390,8 +390,6 @@ async fn start_listening<
|
||||||
Ok(w) => w,
|
Ok(w) => w,
|
||||||
Err(_) => return ConfigState::Failed,
|
Err(_) => return ConfigState::Failed,
|
||||||
};
|
};
|
||||||
let msg = T::get_entry(&config);
|
|
||||||
_ = output.send((id, msg)).await;
|
|
||||||
|
|
||||||
match T::get_entry(&config) {
|
match T::get_entry(&config) {
|
||||||
Ok(t) => {
|
Ok(t) => {
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,4 @@ serde = { version = "1.0.129", features = ["derive"] }
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
csscolorparser = {version = "0.6.2", features = ["serde"]}
|
csscolorparser = {version = "0.6.2", features = ["serde"]}
|
||||||
cosmic-config = { path = "../cosmic-config/", default-features = false, features = ["subscription"] }
|
cosmic-config = { path = "../cosmic-config/", default-features = false, features = ["subscription", "macro"] }
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
pub use corner::*;
|
pub use corner::*;
|
||||||
pub use cosmic_palette::*;
|
pub use cosmic_palette::*;
|
||||||
pub use derivation::*;
|
pub use derivation::*;
|
||||||
|
pub use mode::*;
|
||||||
pub use spacing::*;
|
pub use spacing::*;
|
||||||
pub use theme::*;
|
pub use theme::*;
|
||||||
|
|
||||||
mod corner;
|
mod corner;
|
||||||
mod cosmic_palette;
|
mod cosmic_palette;
|
||||||
mod derivation;
|
mod derivation;
|
||||||
|
mod mode;
|
||||||
mod spacing;
|
mod spacing;
|
||||||
mod theme;
|
mod theme;
|
||||||
|
|
|
||||||
46
cosmic-theme/src/model/mode.rs
Normal file
46
cosmic-theme/src/model/mode.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry};
|
||||||
|
|
||||||
|
/// ID for the ThemeMode config
|
||||||
|
pub const THEME_MODE_ID: &str = "com.system76.CosmicTheme.Mode";
|
||||||
|
|
||||||
|
/// The config for cosmic theme dark / light settings
|
||||||
|
#[derive(
|
||||||
|
Debug, Clone, Copy, PartialEq, Eq, cosmic_config::cosmic_config_derive::CosmicConfigEntry,
|
||||||
|
)]
|
||||||
|
pub struct ThemeMode {
|
||||||
|
/// The theme dark mode setting.
|
||||||
|
pub is_dark: bool,
|
||||||
|
/// The theme auto-switch dark and light mode setting.
|
||||||
|
pub auto_switch: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ThemeMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
is_dark: true,
|
||||||
|
auto_switch: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThemeMode {
|
||||||
|
/// Check if the theme is currently using dark mode
|
||||||
|
pub fn is_dark(config: &Config) -> Result<bool, cosmic_config::Error> {
|
||||||
|
config.get::<bool>("is_dark")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// version of the theme
|
||||||
|
pub fn version() -> u64 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set auto-switch from light to dark mode
|
||||||
|
pub fn set_auto_switch(config: &Config, value: bool) -> Result<(), cosmic_config::Error> {
|
||||||
|
config.set("auto_switch", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the config for the theme mode
|
||||||
|
pub fn config() -> Result<Config, cosmic_config::Error> {
|
||||||
|
Config::new(THEME_MODE_ID, Self::version())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,24 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
composite::over, steps::*, Component, Container, CornerRadii, CosmicPalette,
|
composite::over, steps::*, Component, Container, CornerRadii, CosmicPalette,
|
||||||
CosmicPaletteInner, Spacing, DARK_PALETTE, LIGHT_PALETTE, NAME,
|
CosmicPaletteInner, Spacing, ThemeMode, DARK_PALETTE, LIGHT_PALETTE, NAME,
|
||||||
};
|
};
|
||||||
use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry};
|
use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry};
|
||||||
use palette::{IntoColor, Srgb, Srgba};
|
use palette::{IntoColor, Srgb, Srgba};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
|
/// ID for the current dark ThemeBuilder config
|
||||||
|
pub const DARK_THEME_BUILDER_ID: &str = "com.system76.CosmicTheme.Dark.Builder";
|
||||||
|
|
||||||
|
/// ID for the current dark Theme config
|
||||||
|
pub const DARK_THEME_ID: &str = "com.system76.CosmicTheme.Dark";
|
||||||
|
|
||||||
|
/// ID for the current light ThemeBuilder config
|
||||||
|
pub const LIGHT_THEME_BUILDER_ID: &str = "com.system76.CosmicTheme.Light.Builder";
|
||||||
|
|
||||||
|
/// ID for the current light Theme config
|
||||||
|
pub const LIGHT_THEME_ID: &str = "com.system76.CosmicTheme.Light";
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
/// Theme layer type
|
/// Theme layer type
|
||||||
pub enum Layer {
|
pub enum Layer {
|
||||||
|
|
@ -66,7 +78,7 @@ pub struct Theme<C> {
|
||||||
pub is_high_contrast: bool,
|
pub is_high_contrast: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CosmicConfigEntry for Theme<Srgba> {
|
impl cosmic_config::CosmicConfigEntry for Theme<Srgba> {
|
||||||
fn write_entry(&self, config: &Config) -> Result<(), cosmic_config::Error> {
|
fn write_entry(&self, config: &Config) -> Result<(), cosmic_config::Error> {
|
||||||
let self_ = self.clone();
|
let self_ = self.clone();
|
||||||
// TODO do as transaction
|
// TODO do as transaction
|
||||||
|
|
@ -176,6 +188,16 @@ impl<C> Theme<C> {
|
||||||
pub fn id() -> &'static str {
|
pub fn id() -> &'static str {
|
||||||
NAME
|
NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the config for the current dark theme
|
||||||
|
pub fn dark_config() -> Result<Config, cosmic_config::Error> {
|
||||||
|
Config::new(DARK_THEME_ID, Self::version())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the config for the current light theme
|
||||||
|
pub fn light_config() -> Result<Config, cosmic_config::Error> {
|
||||||
|
Config::new(LIGHT_THEME_ID, Self::version())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Theme<Srgba> {
|
impl Theme<Srgba> {
|
||||||
|
|
@ -410,6 +432,20 @@ impl Theme<Srgba> {
|
||||||
pub fn radius_xl(&self) -> [f32; 4] {
|
pub fn radius_xl(&self) -> [f32; 4] {
|
||||||
self.corner_radii.radius_xl
|
self.corner_radii.radius_xl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get the active theme
|
||||||
|
pub fn get_active() -> Result<Self, (Vec<cosmic_config::Error>, Self)> {
|
||||||
|
let config =
|
||||||
|
Config::new(Self::id(), Self::version()).map_err(|e| (vec![e], Self::default()))?;
|
||||||
|
let is_dark = ThemeMode::is_dark(&config).map_err(|e| (vec![e], Self::default()))?;
|
||||||
|
let config = if is_dark {
|
||||||
|
Self::dark_config()
|
||||||
|
} else {
|
||||||
|
Self::light_config()
|
||||||
|
}
|
||||||
|
.map_err(|e| (vec![e], Self::default()))?;
|
||||||
|
Self::get_entry(&config)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> From<CosmicPalette<C>> for Theme<Srgba>
|
impl<C> From<CosmicPalette<C>> for Theme<Srgba>
|
||||||
|
|
@ -422,7 +458,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for building customized themes
|
/// Helper for building customized themes
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize, cosmic_config::cosmic_config_derive::CosmicConfigEntry)]
|
||||||
pub struct ThemeBuilder {
|
pub struct ThemeBuilder {
|
||||||
palette: CosmicPalette<Srgba>,
|
palette: CosmicPalette<Srgba>,
|
||||||
spacing: Spacing,
|
spacing: Spacing,
|
||||||
|
|
@ -890,4 +926,19 @@ impl ThemeBuilder {
|
||||||
theme.corner_radii = corner_radii;
|
theme.corner_radii = corner_radii;
|
||||||
theme
|
theme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the builder for the dark config
|
||||||
|
pub fn dark_config() -> Result<Config, cosmic_config::Error> {
|
||||||
|
Config::new(DARK_THEME_BUILDER_ID, Self::version())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the builder for the light config
|
||||||
|
pub fn light_config() -> Result<Config, cosmic_config::Error> {
|
||||||
|
Config::new(LIGHT_THEME_BUILDER_ID, Self::version())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// version of the theme builder
|
||||||
|
pub fn version() -> u64 {
|
||||||
|
1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use cosmic_config::CosmicConfigEntry;
|
||||||
|
use cosmic_theme::ThemeMode;
|
||||||
|
|
||||||
use crate::Theme;
|
use crate::Theme;
|
||||||
|
|
||||||
/// Status of the nav bar and its panels.
|
/// Status of the nav bar and its panels.
|
||||||
|
|
@ -49,6 +52,9 @@ pub struct Core {
|
||||||
/// Last known system theme
|
/// Last known system theme
|
||||||
pub(super) system_theme: Theme,
|
pub(super) system_theme: Theme,
|
||||||
|
|
||||||
|
/// Theme mode
|
||||||
|
pub(super) system_theme_mode: ThemeMode,
|
||||||
|
|
||||||
pub(super) title: String,
|
pub(super) title: String,
|
||||||
|
|
||||||
pub window: Window,
|
pub window: Window,
|
||||||
|
|
@ -70,6 +76,16 @@ impl Default for Core {
|
||||||
scale_factor: 1.0,
|
scale_factor: 1.0,
|
||||||
title: String::new(),
|
title: String::new(),
|
||||||
system_theme: crate::theme::active(),
|
system_theme: crate::theme::active(),
|
||||||
|
system_theme_mode: ThemeMode::config()
|
||||||
|
.map(|c| {
|
||||||
|
ThemeMode::get_entry(&c).unwrap_or_else(|(errors, mode)| {
|
||||||
|
for e in errors {
|
||||||
|
tracing::error!("{e}");
|
||||||
|
}
|
||||||
|
mode
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
window: Window {
|
window: Window {
|
||||||
context_title: String::new(),
|
context_title: String::new(),
|
||||||
header_title: String::new(),
|
header_title: String::new(),
|
||||||
|
|
@ -169,4 +185,15 @@ impl Core {
|
||||||
self.window.width = new_width;
|
self.window.width = new_width;
|
||||||
self.is_condensed_update();
|
self.is_condensed_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the current system theme
|
||||||
|
pub fn system_theme(&self) -> &Theme {
|
||||||
|
&self.system_theme
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
/// Get the current system theme mode
|
||||||
|
pub fn system_theme_mode(&self) -> ThemeMode {
|
||||||
|
self.system_theme_mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use super::{command, Application, ApplicationExt, Core, Subscription};
|
||||||
use crate::theme::{self, Theme, ThemeType, THEME};
|
use crate::theme::{self, Theme, ThemeType, THEME};
|
||||||
use crate::widget::nav_bar;
|
use crate::widget::nav_bar;
|
||||||
use crate::{keyboard_nav, Element};
|
use crate::{keyboard_nav, Element};
|
||||||
|
use cosmic_theme::ThemeMode;
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
use iced::event::wayland::{self, WindowEvent};
|
use iced::event::wayland::{self, WindowEvent};
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
|
|
@ -44,6 +45,8 @@ pub enum Message {
|
||||||
ToggleNavBarCondensed,
|
ToggleNavBarCondensed,
|
||||||
/// Notification of system theme changes.
|
/// Notification of system theme changes.
|
||||||
SystemThemeChange(Theme),
|
SystemThemeChange(Theme),
|
||||||
|
/// Notification of system theme mode changes.
|
||||||
|
SystemThemeModeChange(ThemeMode),
|
||||||
/// Updates the tracked window geometry.
|
/// Updates the tracked window geometry.
|
||||||
WindowResize(window::Id, u32, u32),
|
WindowResize(window::Id, u32, u32),
|
||||||
/// Tracks updates to window state.
|
/// Tracks updates to window state.
|
||||||
|
|
@ -152,9 +155,27 @@ where
|
||||||
keyboard_nav::subscription()
|
keyboard_nav::subscription()
|
||||||
.map(Message::KeyboardNav)
|
.map(Message::KeyboardNav)
|
||||||
.map(super::Message::Cosmic),
|
.map(super::Message::Cosmic),
|
||||||
theme::subscription(0)
|
theme::subscription(0, self.app.core().system_theme_mode.is_dark)
|
||||||
.map(Message::SystemThemeChange)
|
.map(Message::SystemThemeChange)
|
||||||
.map(super::Message::Cosmic),
|
.map(super::Message::Cosmic),
|
||||||
|
cosmic_config::config_subscription::<_, cosmic_theme::ThemeMode>(
|
||||||
|
0,
|
||||||
|
cosmic_theme::THEME_MODE_ID.into(),
|
||||||
|
cosmic_theme::ThemeMode::version(),
|
||||||
|
)
|
||||||
|
.map(|(_, u)| {
|
||||||
|
tracing::error!("{u:?}");
|
||||||
|
match u {
|
||||||
|
Ok(t) => Message::SystemThemeModeChange(t),
|
||||||
|
Err((errors, t)) => {
|
||||||
|
for e in errors {
|
||||||
|
tracing::error!("{e}");
|
||||||
|
}
|
||||||
|
Message::SystemThemeModeChange(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(super::Message::Cosmic),
|
||||||
window_events.map(super::Message::Cosmic),
|
window_events.map(super::Message::Cosmic),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +316,7 @@ impl<T: Application> Cosmic<T> {
|
||||||
THEME.with(move |t| {
|
THEME.with(move |t| {
|
||||||
let mut cosmic_theme = t.borrow_mut();
|
let mut cosmic_theme = t.borrow_mut();
|
||||||
|
|
||||||
// Anly apply update if the theme is set to load a system theme
|
// Only apply update if the theme is set to load a system theme
|
||||||
if let ThemeType::System(_) = cosmic_theme.theme_type {
|
if let ThemeType::System(_) = cosmic_theme.theme_type {
|
||||||
cosmic_theme.set_theme(theme.theme_type);
|
cosmic_theme.set_theme(theme.theme_type);
|
||||||
}
|
}
|
||||||
|
|
@ -310,6 +331,10 @@ impl<T: Application> Cosmic<T> {
|
||||||
self.app.on_app_exit();
|
self.app.on_app_exit();
|
||||||
return self.close();
|
return self.close();
|
||||||
}
|
}
|
||||||
|
Message::SystemThemeModeChange(mode) => {
|
||||||
|
let core = self.app.core_mut();
|
||||||
|
core.system_theme_mode = mode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iced::Command::none()
|
iced::Command::none()
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
//! Contains the [`Theme`] type and its widget stylesheet implementations.
|
//! Contains the [`Theme`] type and its widget stylesheet implementations.
|
||||||
|
|
||||||
pub mod style;
|
pub mod style;
|
||||||
|
use cosmic_theme::ThemeMode;
|
||||||
pub use style::*;
|
pub use style::*;
|
||||||
|
|
||||||
use cosmic_config::config_subscription;
|
use cosmic_config::config_subscription;
|
||||||
use cosmic_config::CosmicConfigEntry;
|
use cosmic_config::CosmicConfigEntry;
|
||||||
use cosmic_theme::util::CssColor;
|
|
||||||
use cosmic_theme::Component;
|
use cosmic_theme::Component;
|
||||||
use cosmic_theme::LayeredTheme;
|
use cosmic_theme::LayeredTheme;
|
||||||
use iced_futures::Subscription;
|
use iced_futures::Subscription;
|
||||||
|
|
@ -68,10 +68,15 @@ pub fn is_high_contrast() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Watches for changes to the system's theme preference.
|
/// Watches for changes to the system's theme preference.
|
||||||
pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
pub fn subscription(id: u64, is_dark: bool) -> Subscription<crate::theme::Theme> {
|
||||||
config_subscription::<u64, crate::cosmic_theme::Theme<Srgba>>(
|
config_subscription::<_, crate::cosmic_theme::Theme<Srgba>>(
|
||||||
id,
|
(id, is_dark),
|
||||||
crate::cosmic_theme::NAME.into(),
|
if is_dark {
|
||||||
|
cosmic_theme::DARK_THEME_ID
|
||||||
|
} else {
|
||||||
|
cosmic_theme::LIGHT_THEME_ID
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
crate::cosmic_theme::Theme::<Srgba>::version(),
|
crate::cosmic_theme::Theme::<Srgba>::version(),
|
||||||
)
|
)
|
||||||
.map(|(_, res)| {
|
.map(|(_, res)| {
|
||||||
|
|
@ -88,10 +93,21 @@ pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
||||||
|
|
||||||
/// Loads the preferred system theme from `cosmic-config`.
|
/// Loads the preferred system theme from `cosmic-config`.
|
||||||
pub fn system_preference() -> Theme {
|
pub fn system_preference() -> Theme {
|
||||||
let Ok(helper) = crate::cosmic_config::Config::new(
|
let Ok(mode_config) = ThemeMode::config() else {
|
||||||
crate::cosmic_theme::NAME,
|
return Theme::dark();
|
||||||
crate::cosmic_theme::Theme::<CssColor>::version(),
|
};
|
||||||
) else {
|
|
||||||
|
let Ok(is_dark) = ThemeMode::is_dark(&mode_config) else {
|
||||||
|
return Theme::dark();
|
||||||
|
};
|
||||||
|
|
||||||
|
let helper = if is_dark {
|
||||||
|
crate::cosmic_theme::Theme::<Srgba>::dark_config()
|
||||||
|
} else {
|
||||||
|
crate::cosmic_theme::Theme::<Srgba>::light_config()
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(helper) = helper else {
|
||||||
return Theme::dark();
|
return Theme::dark();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue