app

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

commit 5cbc36e2720b81422942fc419cfeb465052c01af
parent f364dde6de8d44c0cdf8d92bb0b674b4c7708604
Author: triesap <tyson@radroots.org>
Date:   Fri,  6 Feb 2026 11:52:52 +0000

app: adjust navigation and settings title

- add settings gear icon and topbar layout

- move ui demo route to /test and remove old nav

- add settings icon key for lucide

- tune settings title sizing and casing

Diffstat:
Mapp/src/app.rs | 26+++++++++++++++++---------
Mapp/src/settings.rs | 32++++++++++++++++++++++++++++++--
Mcrates/ui-components/src/icon.rs | 16++++++++++++++--
3 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/app/src/app.rs b/app/src/app.rs @@ -17,6 +17,8 @@ use radroots_app_ui_components::{ RadrootsAppUiButtonLayoutAction, RadrootsAppUiButtonLayoutBackAction, RadrootsAppUiButtonLayoutPair, + RadrootsAppUiIcon, + RadrootsAppUiIconKey, RadrootsAppUiSpinner, }; use uuid::Uuid; @@ -716,7 +718,7 @@ fn SetupPage() -> impl IntoView { </header> <footer id="app-setup-intro-footer" - class="absolute bottom-0 left-0 flex flex-col h-[20rem] w-full px-10 gap-2 justify-start items-center" + class="absolute bottom-0 left-0 flex flex-col h-[20rem] w-full gap-2 justify-start items-center" > <p id="app-setup-intro-kicker" @@ -1616,12 +1618,18 @@ fn AppShell() -> impl IntoView { if gate.show_app { return view! { <div id="app-shell"> - <nav id="app-nav" aria-label=t!("app.nav.primary_aria") style="display:flex;gap:12px;margin-bottom:12px;"> - <A href="/" exact=true>{t!("app.nav.home")}</A> - <A href="/logs">{t!("app.nav.logs")}</A> - <A href="/ui">{t!("app.nav.ui")}</A> - <A href="/settings">{t!("app.nav.settings")}</A> - </nav> + <div + id="app-topbar" + class="flex items-center justify-end px-4 pt-4" + > + <A + href="/settings" + attr:aria-label=t!("app.nav.settings") + attr:class="inline-flex h-9 w-9 items-center justify-center rounded-full" + > + <RadrootsAppUiIcon key=RadrootsAppUiIconKey::Settings size=20 /> + </A> + </div> <Routes fallback=|| view! { <main id="app-not-found" class="app-page app-page-fixed"> @@ -1630,8 +1638,8 @@ fn AppShell() -> impl IntoView { } > <Route path=path!("") view=HomePage /> - <Route path=path!("logs") view=RadrootsAppLogsPage /> - <Route path=path!("ui") view=RadrootsAppUiDemoPage /> + <Route path=path!("settings/logs") view=RadrootsAppLogsPage /> + <Route path=path!("test") view=RadrootsAppUiDemoPage /> <Route path=path!("settings/status") view=RadrootsAppSettingsStatusPage diff --git a/app/src/settings.rs b/app/src/settings.rs @@ -152,6 +152,7 @@ pub fn RadrootsAppSettingsPage() -> impl IntoView { hide_offset: false, styles: None, }; + let logs_navigate = navigate.clone(); let actions_list = RadrootsAppUiList { id: Some("settings-actions".to_string()), view: Some("settings".to_string()), @@ -187,6 +188,30 @@ pub fn RadrootsAppSettingsPage() -> impl IntoView { Some(RadrootsAppUiListItem { kind: RadrootsAppUiListItemKind::Touch(RadrootsAppUiListTouch { label: RadrootsAppUiListLabel { + left: vec![settings_label(t!("app.nav.logs"), 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(Callback::new(move |_| { + logs_navigate("/settings/logs", Default::default()); + })), + }), + 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( t!("app.settings.actions.logout"), Some("capitalize"), @@ -261,8 +286,11 @@ pub fn RadrootsAppSettingsPage() -> impl IntoView { }; view! { <main id="app-settings" class="app-page app-page-scroll" style="padding: 16px;"> - <header id="app-settings-header" style="font: var(--type-title2); margin-bottom: 12px;"> - <h1 id="app-settings-title">{t!("app.settings.title")}</h1> + <header + id="app-settings-header" + style="font-family: var(--font-sans); font-size: 34px; line-height: 41px; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 12px;" + > + <h1 id="app-settings-title" class="capitalize">{t!("app.settings.title")}</h1> </header> <section id="app-settings-content" style="display:flex;flex-direction:column;gap:16px;"> <RadrootsAppUiListView basis=appearance_list /> diff --git a/crates/ui-components/src/icon.rs b/crates/ui-components/src/icon.rs @@ -1,6 +1,6 @@ #![forbid(unsafe_code)] -use icondata::{Icon, LuChevronRight, LuChevronsUpDown, LuPlus}; +use icondata::{Icon, LuChevronRight, LuChevronsUpDown, LuPlus, LuSettings}; use leptos::prelude::*; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -8,6 +8,7 @@ pub enum RadrootsAppUiIconKey { CaretRight, CaretUpDown, Plus, + Settings, } impl RadrootsAppUiIconKey { @@ -16,6 +17,7 @@ impl RadrootsAppUiIconKey { RadrootsAppUiIconKey::CaretRight => "caret-right", RadrootsAppUiIconKey::CaretUpDown => "caret-up-down", RadrootsAppUiIconKey::Plus => "plus", + RadrootsAppUiIconKey::Settings => "settings", } } } @@ -25,6 +27,7 @@ pub fn radroots_app_ui_icon_key_from_name(name: &str) -> Option<RadrootsAppUiIco "caret-right" | "chevron-right" => Some(RadrootsAppUiIconKey::CaretRight), "caret-up-down" | "chevrons-up-down" => Some(RadrootsAppUiIconKey::CaretUpDown), "plus" => Some(RadrootsAppUiIconKey::Plus), + "settings" | "gear" => Some(RadrootsAppUiIconKey::Settings), _ => None, } } @@ -34,6 +37,7 @@ pub fn radroots_app_ui_icon_data(key: RadrootsAppUiIconKey) -> Icon { RadrootsAppUiIconKey::CaretRight => LuChevronRight, RadrootsAppUiIconKey::CaretUpDown => LuChevronsUpDown, RadrootsAppUiIconKey::Plus => LuPlus, + RadrootsAppUiIconKey::Settings => LuSettings, } } @@ -104,12 +108,20 @@ mod tests { radroots_app_ui_icon_key_from_name("plus"), Some(RadrootsAppUiIconKey::Plus) ); + assert_eq!( + radroots_app_ui_icon_key_from_name("settings"), + Some(RadrootsAppUiIconKey::Settings) + ); + assert_eq!( + radroots_app_ui_icon_key_from_name("gear"), + Some(RadrootsAppUiIconKey::Settings) + ); assert_eq!(radroots_app_ui_icon_key_from_name("unknown"), None); } #[test] fn icon_data_resolves() { - let icon = radroots_app_ui_icon_data(RadrootsAppUiIconKey::Plus); + let icon = radroots_app_ui_icon_data(RadrootsAppUiIconKey::Settings); assert!(!icon.data.is_empty()); } }