app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit f28c18b00f595f7f6bc6b2ddbbb19ea195b030ab
parent 53910f99f8219ba117b1ce33944cb12b1c0a16b4
Author: triesap <triesap@radroots.dev>
Date:   Thu, 22 Jan 2026 11:29:45 +0000

app: add settings route

- create settings page with appearance and actions lists

- wire noop callbacks that log action names

- add settings module export for routing

- register /settings in nav and routes

Diffstat:
Mapp/src/app.rs | 3+++
Mapp/src/lib.rs | 2++
Aapp/src/settings.rs | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/app/src/app.rs b/app/src/app.rs @@ -40,6 +40,7 @@ use crate::{ RadrootsAppInitStage, RadrootsAppNotifications, RadrootsAppLogsPage, + RadrootsAppSettingsPage, RadrootsAppUiDemoPage, RadrootsAppTangleClientStub, }; @@ -702,12 +703,14 @@ fn AppShell() -> impl IntoView { <A href="/" exact=true>"home"</A> <A href="/logs">"logs"</A> <A href="/ui">"ui"</A> + <A href="/settings">"settings"</A> <A href="/setup">"setup"</A> </nav> <Routes fallback=|| view! { <div>"not_found"</div> }> <Route path=path!("") view=HomePage /> <Route path=path!("logs") view=RadrootsAppLogsPage /> <Route path=path!("ui") view=RadrootsAppUiDemoPage /> + <Route path=path!("settings") view=RadrootsAppSettingsPage /> <Route path=path!("setup") view=SetupPage /> </Routes> </Show> diff --git a/app/src/lib.rs b/app/src/lib.rs @@ -11,6 +11,7 @@ mod keystore; mod logging; mod logs; mod notifications; +mod settings; mod setup; mod tangle; mod ui_demo; @@ -62,6 +63,7 @@ pub use keystore::{ RadrootsAppKeystoreResult, }; pub use logs::RadrootsAppLogsPage; +pub use settings::RadrootsAppSettingsPage; pub use ui_demo::RadrootsAppUiDemoPage; pub use logging::{ app_log_entry_error, diff --git a/app/src/settings.rs b/app/src/settings.rs @@ -0,0 +1,184 @@ +#![forbid(unsafe_code)] + +use leptos::ev::MouseEvent; +use leptos::prelude::*; + +use radroots_app_ui_components::{ + RadrootsAppUiList, + RadrootsAppUiListIcon, + RadrootsAppUiListItem, + RadrootsAppUiListItemKind, + RadrootsAppUiListLabel, + RadrootsAppUiListLabelText, + RadrootsAppUiListLabelValue, + RadrootsAppUiListLabelValueKind, + RadrootsAppUiListSelect, + RadrootsAppUiListSelectField, + RadrootsAppUiListSelectOption, + RadrootsAppUiListStyles, + RadrootsAppUiListTitle, + RadrootsAppUiListTitleValue, + RadrootsAppUiListTouch, + RadrootsAppUiListTouchEnd, + RadrootsAppUiListView, +}; + +fn log_settings_action(action: &str) { + #[cfg(target_arch = "wasm32")] + { + web_sys::console::log_1(&action.into()); + } + #[cfg(not(target_arch = "wasm32"))] + { + println!("{action}"); + } +} + +fn settings_touch_callback(action: &'static str) -> Callback<MouseEvent> { + Callback::new(move |_| log_settings_action(action)) +} + +fn settings_label(value: &str, classes: Option<&str>) -> RadrootsAppUiListLabelValue { + RadrootsAppUiListLabelValue { + classes_wrap: None, + hide_truncate: false, + value: RadrootsAppUiListLabelValueKind::Text(RadrootsAppUiListLabelText { + value: value.to_string(), + classes: classes.map(str::to_string), + }), + } +} + +#[component] +pub fn RadrootsAppSettingsPage() -> impl IntoView { + let color_mode_callback = Callback::new(move |_value: String| { + log_settings_action("settings_color_mode"); + }); + let appearance_list = RadrootsAppUiList { + id: Some("settings-appearance".to_string()), + view: Some("settings".to_string()), + classes: None, + title: Some(RadrootsAppUiListTitle { + value: RadrootsAppUiListTitleValue::Text("Appearance".to_string()), + classes: None, + mod_value: None, + link: None, + on_click: None, + }), + default_state: None, + list: Some(vec![Some(RadrootsAppUiListItem { + kind: RadrootsAppUiListItemKind::Select(RadrootsAppUiListSelect { + field: RadrootsAppUiListSelectField { + value: "light".to_string(), + options: vec![ + RadrootsAppUiListSelectOption { + label: "Light".to_string(), + value: "light".to_string(), + classes: None, + }, + RadrootsAppUiListSelectOption { + label: "Dark".to_string(), + value: "dark".to_string(), + classes: None, + }, + ], + disabled: false, + classes: None, + id: Some("settings-color-mode".to_string()), + on_change: Some(color_mode_callback), + }, + label: RadrootsAppUiListLabel { + left: vec![settings_label("color mode", Some("capitalize"))], + right: Vec::new(), + }, + display: None, + end: Some(RadrootsAppUiListTouchEnd { + icon: RadrootsAppUiListIcon { + key: "chevrons-up-down".to_string(), + class: None, + }, + on_click: None, + }), + loading: false, + on_click: None, + }), + loading: false, + hide_active: true, + hide_field: false, + full_rounded: false, + offset: None, + })]), + hide_offset: false, + styles: Some(RadrootsAppUiListStyles { + hide_border_top: None, + hide_border_bottom: None, + hide_rounded: None, + set_title_background: Some(true), + set_default_background: None, + }), + }; + let actions_list = RadrootsAppUiList { + id: Some("settings-actions".to_string()), + view: Some("settings".to_string()), + classes: None, + title: None, + default_state: None, + list: Some(vec![ + Some(RadrootsAppUiListItem { + kind: RadrootsAppUiListItemKind::Touch(RadrootsAppUiListTouch { + label: RadrootsAppUiListLabel { + left: vec![settings_label("export database", Some("capitalize"))], + right: Vec::new(), + }, + display: None, + end: Some(RadrootsAppUiListTouchEnd { + icon: RadrootsAppUiListIcon { + key: "caret-right".to_string(), + class: None, + }, + on_click: None, + }), + on_click: Some(settings_touch_callback("settings_export_database")), + }), + loading: false, + hide_active: true, + hide_field: false, + full_rounded: false, + offset: None, + }), + Some(RadrootsAppUiListItem { + kind: RadrootsAppUiListItemKind::Touch(RadrootsAppUiListTouch { + label: RadrootsAppUiListLabel { + left: vec![settings_label("logout", Some("capitalize"))], + right: Vec::new(), + }, + display: None, + end: Some(RadrootsAppUiListTouchEnd { + icon: RadrootsAppUiListIcon { + key: "caret-right".to_string(), + class: None, + }, + on_click: None, + }), + on_click: Some(settings_touch_callback("settings_logout")), + }), + loading: false, + hide_active: true, + hide_field: false, + full_rounded: false, + offset: None, + }), + ]), + hide_offset: false, + styles: None, + }; + view! { + <main style="padding: 16px;"> + <div style="font: var(--type-title2); margin-bottom: 12px;">"settings"</div> + <div style="display:flex;flex-direction:column;gap:16px;"> + <RadrootsAppUiListView basis=appearance_list /> + <RadrootsAppUiListView basis=actions_list /> + </div> + </main> + } +}