commit bf1b2f48dc2ee605b80ea220d31e52aa050361ff
parent 42884064df5846d1ba214c3e5c6608ee62b20ef9
Author: triesap <triesap@radroots.dev>
Date: Thu, 22 Jan 2026 17:03:45 +0000
app: wire theme selection
- read stored color mode and seed select value
- apply and persist theme changes on select
- expose theme storage helpers in app
- add system option to appearance list
Diffstat:
3 files changed, 52 insertions(+), 6 deletions(-)
diff --git a/app/src/lib.rs b/app/src/lib.rs
@@ -69,6 +69,8 @@ pub use ui_demo::RadrootsAppUiDemoPage;
pub use theme::{
app_theme_apply_mode,
app_theme_init,
+ app_theme_read_mode,
+ app_theme_store_mode,
app_theme_mode_from_value,
app_theme_mode_to_name,
RadrootsAppThemeError,
diff --git a/app/src/settings.rs b/app/src/settings.rs
@@ -3,6 +3,13 @@
use leptos::ev::MouseEvent;
use leptos::prelude::*;
+use crate::{
+ app_theme_apply_mode,
+ app_theme_mode_from_value,
+ app_theme_read_mode,
+ app_theme_store_mode,
+ RadrootsAppThemeMode,
+};
use radroots_app_ui_components::{
RadrootsAppUiList,
RadrootsAppUiListIcon,
@@ -50,8 +57,15 @@ fn settings_label(value: &str, classes: Option<&str>) -> RadrootsAppUiListLabelV
#[component]
pub fn RadrootsAppSettingsPage() -> impl IntoView {
- let color_mode_callback = Callback::new(move |_value: String| {
+ let initial_mode = app_theme_read_mode().unwrap_or(RadrootsAppThemeMode::System);
+ let color_mode_value = initial_mode.as_str().to_string();
+ let color_mode_callback = Callback::new(move |value: String| {
log_settings_action("settings_color_mode");
+ let Some(mode) = app_theme_mode_from_value(&value) else {
+ return;
+ };
+ let _ = app_theme_store_mode(mode);
+ let _ = app_theme_apply_mode(mode);
});
let appearance_list = RadrootsAppUiList {
id: Some("settings-appearance".to_string()),
@@ -68,9 +82,14 @@ pub fn RadrootsAppSettingsPage() -> impl IntoView {
list: Some(vec![Some(RadrootsAppUiListItem {
kind: RadrootsAppUiListItemKind::Select(RadrootsAppUiListSelect {
field: RadrootsAppUiListSelectField {
- value: "light".to_string(),
+ value: color_mode_value,
options: vec![
RadrootsAppUiListSelectOption {
+ label: "System".to_string(),
+ value: "system".to_string(),
+ classes: None,
+ },
+ RadrootsAppUiListSelectOption {
label: "Light".to_string(),
value: "light".to_string(),
classes: None,
diff --git a/app/src/theme.rs b/app/src/theme.rs
@@ -117,12 +117,33 @@ fn app_theme_read_storage() -> Option<String> {
None
}
-pub fn app_theme_init() -> RadrootsAppThemeResult<&'static str> {
- let prefers_dark = app_theme_prefers_dark();
- let mode = app_theme_read_storage()
+#[cfg(target_arch = "wasm32")]
+fn app_theme_write_storage(value: &str) -> RadrootsAppThemeResult<()> {
+ let window = web_sys::window().ok_or(RadrootsAppThemeError::Unavailable)?;
+ let storage = window
+ .local_storage()
+ .map_err(|_| RadrootsAppThemeError::Storage)?
+ .ok_or(RadrootsAppThemeError::Storage)?;
+ storage
+ .set_item(APP_THEME_STORAGE_KEY, value)
+ .map_err(|_| RadrootsAppThemeError::Storage)?;
+ Ok(())
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+fn app_theme_write_storage(_value: &str) -> RadrootsAppThemeResult<()> {
+ Ok(())
+}
+
+pub fn app_theme_read_mode() -> Option<RadrootsAppThemeMode> {
+ app_theme_read_storage()
.as_deref()
.and_then(app_theme_mode_from_value)
- .unwrap_or(RadrootsAppThemeMode::System);
+}
+
+pub fn app_theme_init() -> RadrootsAppThemeResult<&'static str> {
+ let prefers_dark = app_theme_prefers_dark();
+ let mode = app_theme_read_mode().unwrap_or(RadrootsAppThemeMode::System);
let theme_name = app_theme_mode_to_name(mode, prefers_dark);
app_theme_apply_name(theme_name)?;
Ok(theme_name)
@@ -135,6 +156,10 @@ pub fn app_theme_apply_mode(mode: RadrootsAppThemeMode) -> RadrootsAppThemeResul
Ok(name)
}
+pub fn app_theme_store_mode(mode: RadrootsAppThemeMode) -> RadrootsAppThemeResult<()> {
+ app_theme_write_storage(mode.as_str())
+}
+
#[cfg(test)]
mod tests {
use super::{