app

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

commit 3595b85a04d4dd9fe1dfd5a5fbb0d5fd23547a93
parent cd17631851a68c8ed8867932e8458c7d7f7d262b
Author: triesap <tyson@radroots.org>
Date:   Fri, 17 Apr 2026 17:36:54 +0000

app: add placeholder settings panels

- replace the centered settings placeholder with scrollable accounts, settings, and about cards
- move placeholder labels and values into shared ui text row builders
- extend the typed key registry and english catalog for app-owned settings copy
- cover the new panel copy with ui tests for localized placeholder rows

Diffstat:
Mcrates/launchers/desktop/src/window.rs | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mcrates/shared/i18n/src/keys.rs | 33+++++++++++++++++++++++++++++++++
Mcrates/shared/ui/src/lib.rs | 6+++++-
Mcrates/shared/ui/src/text.rs | 101++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mi18n/locales/en/messages.json | 33+++++++++++++++++++++++++++++++++
5 files changed, 297 insertions(+), 29 deletions(-)

diff --git a/crates/launchers/desktop/src/window.rs b/crates/launchers/desktop/src/window.rs @@ -1,12 +1,14 @@ use gpui::{ - Context, InteractiveElement, IntoElement, ParentElement, Render, StatefulInteractiveElement, - Styled, Window, div, px, rgb, + AnyElement, Context, InteractiveElement, IntoElement, ParentElement, Render, + StatefulInteractiveElement, Styled, Window, div, px, rgb, }; use radroots_app_core::AppRuntimeSnapshot; use radroots_app_i18n::AppTextKey; use radroots_app_ui::{ APP_UI_THEME, LabelValueRow, app_card, app_shared_text, app_window_shell, label_value_list, - runtime_metadata_rows, section_divider, utility_title_row, + runtime_metadata_rows, section_divider, settings_about_build_rows, settings_about_status_rows, + settings_account_profile_rows, settings_account_runtime_rows, settings_preferences_device_rows, + settings_preferences_general_rows, utility_title_row, }; use crate::menus::OpenSettingsWindow; @@ -43,6 +45,14 @@ impl SettingsPanelViewKey { Self::About => AppTextKey::SettingsNavAbout, } } + + fn summary_key(self) -> AppTextKey { + match self { + Self::Accounts => AppTextKey::SettingsAccountsSummary, + Self::Settings => AppTextKey::SettingsPreferencesSummary, + Self::About => AppTextKey::SettingsAboutSummary, + } + } } pub struct HomeView { @@ -223,6 +233,118 @@ impl SettingsWindowView { this.select_view(view, cx); })) } + + fn summary_card(&self, view: SettingsPanelViewKey) -> impl IntoElement { + app_card( + div() + .w_full() + .flex() + .flex_col() + .gap(px(APP_UI_THEME.layout.home_stack_gap_px)) + .child(utility_title_row(app_shared_text(view.label_key()))) + .child(section_divider()) + .child( + div() + .w_full() + .text_size(px(APP_UI_THEME.typography.body_text_px)) + .text_color(rgb(APP_UI_THEME.text.secondary)) + .child(app_shared_text(view.summary_key())), + ), + ) + } + + fn detail_card(&self, title: AppTextKey, rows: Vec<LabelValueRow>) -> impl IntoElement { + app_card( + div() + .w_full() + .flex() + .flex_col() + .gap(px(APP_UI_THEME.layout.home_stack_gap_px)) + .child(utility_title_row(app_shared_text(title))) + .child(section_divider()) + .child(label_value_list(rows)), + ) + } + + fn accounts_panel(&self) -> impl IntoElement { + div() + .id("settings-panel-scroll") + .size_full() + .overflow_y_scroll() + .child( + div() + .w_full() + .p(px(APP_UI_THEME.layout.settings_content_padding_px)) + .flex() + .flex_col() + .gap(px(APP_UI_THEME.layout.home_stack_gap_px)) + .child(self.summary_card(SettingsPanelViewKey::Accounts)) + .child(self.detail_card( + AppTextKey::SettingsAccountsProfileTitle, + settings_account_profile_rows(), + )) + .child(self.detail_card( + AppTextKey::SettingsAccountsRuntimeTitle, + settings_account_runtime_rows(), + )), + ) + } + + fn settings_panel(&self) -> impl IntoElement { + div() + .id("settings-panel-scroll") + .size_full() + .overflow_y_scroll() + .child( + div() + .w_full() + .p(px(APP_UI_THEME.layout.settings_content_padding_px)) + .flex() + .flex_col() + .gap(px(APP_UI_THEME.layout.home_stack_gap_px)) + .child(self.summary_card(SettingsPanelViewKey::Settings)) + .child(self.detail_card( + AppTextKey::SettingsPreferencesGeneralTitle, + settings_preferences_general_rows(), + )) + .child(self.detail_card( + AppTextKey::SettingsPreferencesDeviceTitle, + settings_preferences_device_rows(), + )), + ) + } + + fn about_panel(&self) -> impl IntoElement { + div() + .id("settings-panel-scroll") + .size_full() + .overflow_y_scroll() + .child( + div() + .w_full() + .p(px(APP_UI_THEME.layout.settings_content_padding_px)) + .flex() + .flex_col() + .gap(px(APP_UI_THEME.layout.home_stack_gap_px)) + .child(self.summary_card(SettingsPanelViewKey::About)) + .child(self.detail_card( + AppTextKey::SettingsAboutBuildTitle, + settings_about_build_rows(), + )) + .child(self.detail_card( + AppTextKey::SettingsAboutStatusTitle, + settings_about_status_rows(), + )), + ) + } + + fn settings_panel_content(&self) -> AnyElement { + match self.selected_view { + SettingsPanelViewKey::Accounts => self.accounts_panel().into_any_element(), + SettingsPanelViewKey::Settings => self.settings_panel().into_any_element(), + SettingsPanelViewKey::About => self.about_panel().into_any_element(), + } + } } impl Render for SettingsWindowView { @@ -296,30 +418,7 @@ impl Render for SettingsWindowView { .w(px(APP_UI_THEME.layout.divider_thickness_px)) .bg(rgb(APP_UI_THEME.surfaces.divider)), ) - .child( - div() - .flex_1() - .h_full() - .p(px(APP_UI_THEME.layout.settings_content_padding_px)) - .child( - div() - .size_full() - .bg(rgb(APP_UI_THEME.surfaces.panel_background)) - .rounded(px(12.0)) - .child( - div() - .size_full() - .flex() - .items_center() - .justify_center() - .text_size(px(APP_UI_THEME.typography.body_text_px)) - .text_color(rgb(APP_UI_THEME.text.secondary)) - .child(app_shared_text( - self.selected_view.label_key(), - )), - ), - ), - ), + .child(div().flex_1().h_full().child(self.settings_panel_content())), ), ) } diff --git a/crates/shared/i18n/src/keys.rs b/crates/shared/i18n/src/keys.rs @@ -30,6 +30,39 @@ define_app_text_keys! { SettingsNavAccounts => "settings.nav.accounts", SettingsNavSettings => "settings.nav.settings", SettingsNavAbout => "settings.nav.about", + SettingsAccountsSummary => "settings.accounts.summary", + SettingsAccountsProfileTitle => "settings.accounts.profile.title", + SettingsAccountsIdentityLabel => "settings.accounts.identity.label", + SettingsAccountsIdentityValue => "settings.accounts.identity.value", + SettingsAccountsStatusLabel => "settings.accounts.status.label", + SettingsAccountsStatusValue => "settings.accounts.status.value", + SettingsAccountsRuntimeTitle => "settings.accounts.runtime.title", + SettingsAccountsSyncLabel => "settings.accounts.sync.label", + SettingsAccountsSyncValue => "settings.accounts.sync.value", + SettingsAccountsRecoveryLabel => "settings.accounts.recovery.label", + SettingsAccountsRecoveryValue => "settings.accounts.recovery.value", + SettingsPreferencesSummary => "settings.preferences.summary", + SettingsPreferencesGeneralTitle => "settings.preferences.general.title", + SettingsPreferencesLaunchLabel => "settings.preferences.launch.label", + SettingsPreferencesLaunchValue => "settings.preferences.launch.value", + SettingsPreferencesNetworkLabel => "settings.preferences.network.label", + SettingsPreferencesNetworkValue => "settings.preferences.network.value", + SettingsPreferencesDeviceTitle => "settings.preferences.device.title", + SettingsPreferencesNotificationsLabel => "settings.preferences.notifications.label", + SettingsPreferencesNotificationsValue => "settings.preferences.notifications.value", + SettingsPreferencesDiagnosticsLabel => "settings.preferences.diagnostics.label", + SettingsPreferencesDiagnosticsValue => "settings.preferences.diagnostics.value", + SettingsAboutSummary => "settings.about.summary", + SettingsAboutBuildTitle => "settings.about.build.title", + SettingsAboutShellLabel => "settings.about.shell.label", + SettingsAboutShellValue => "settings.about.shell.value", + SettingsAboutLicenseLabel => "settings.about.license.label", + SettingsAboutLicenseValue => "settings.about.license.value", + SettingsAboutStatusTitle => "settings.about.status.title", + SettingsAboutPostureLabel => "settings.about.posture.label", + SettingsAboutPostureValue => "settings.about.posture.value", + SettingsAboutMilestoneLabel => "settings.about.milestone.label", + SettingsAboutMilestoneValue => "settings.about.milestone.value", MetadataCorePackage => "metadata.core_package", MetadataCoreVersion => "metadata.core_version", MetadataCoreAuthors => "metadata.core_authors", diff --git a/crates/shared/ui/src/lib.rs b/crates/shared/ui/src/lib.rs @@ -8,7 +8,11 @@ pub use primitives::{ LabelValueRow, app_card, app_center_stage, app_window_shell, label_value_list, section_divider, utility_title_row, }; -pub use text::{app_shared_text, runtime_metadata_rows}; +pub use text::{ + app_shared_text, runtime_metadata_rows, settings_about_build_rows, settings_about_status_rows, + settings_account_profile_rows, settings_account_runtime_rows, settings_preferences_device_rows, + settings_preferences_general_rows, +}; pub use theme::{ APP_UI_THEME, AppLayoutTokens, AppSurfaceTokens, AppTextTokens, AppTypographyTokens, AppUiTheme, AppWindowTokens, diff --git a/crates/shared/ui/src/text.rs b/crates/shared/ui/src/text.rs @@ -87,10 +87,92 @@ pub fn runtime_metadata_rows(snapshot: &AppRuntimeSnapshot) -> Vec<LabelValueRow ] } +pub fn settings_account_profile_rows() -> Vec<LabelValueRow> { + vec![ + text_row( + AppTextKey::SettingsAccountsIdentityLabel, + AppTextKey::SettingsAccountsIdentityValue, + ), + text_row( + AppTextKey::SettingsAccountsStatusLabel, + AppTextKey::SettingsAccountsStatusValue, + ), + ] +} + +pub fn settings_account_runtime_rows() -> Vec<LabelValueRow> { + vec![ + text_row( + AppTextKey::SettingsAccountsSyncLabel, + AppTextKey::SettingsAccountsSyncValue, + ), + text_row( + AppTextKey::SettingsAccountsRecoveryLabel, + AppTextKey::SettingsAccountsRecoveryValue, + ), + ] +} + +pub fn settings_preferences_general_rows() -> Vec<LabelValueRow> { + vec![ + text_row( + AppTextKey::SettingsPreferencesLaunchLabel, + AppTextKey::SettingsPreferencesLaunchValue, + ), + text_row( + AppTextKey::SettingsPreferencesNetworkLabel, + AppTextKey::SettingsPreferencesNetworkValue, + ), + ] +} + +pub fn settings_preferences_device_rows() -> Vec<LabelValueRow> { + vec![ + text_row( + AppTextKey::SettingsPreferencesNotificationsLabel, + AppTextKey::SettingsPreferencesNotificationsValue, + ), + text_row( + AppTextKey::SettingsPreferencesDiagnosticsLabel, + AppTextKey::SettingsPreferencesDiagnosticsValue, + ), + ] +} + +pub fn settings_about_build_rows() -> Vec<LabelValueRow> { + vec![ + text_row( + AppTextKey::SettingsAboutShellLabel, + AppTextKey::SettingsAboutShellValue, + ), + text_row( + AppTextKey::SettingsAboutLicenseLabel, + AppTextKey::SettingsAboutLicenseValue, + ), + ] +} + +pub fn settings_about_status_rows() -> Vec<LabelValueRow> { + vec![ + text_row( + AppTextKey::SettingsAboutPostureLabel, + AppTextKey::SettingsAboutPostureValue, + ), + text_row( + AppTextKey::SettingsAboutMilestoneLabel, + AppTextKey::SettingsAboutMilestoneValue, + ), + ] +} + fn metadata_row(label: AppTextKey, value: impl Into<String>) -> LabelValueRow { LabelValueRow::new(app_shared_text(label), value.into()) } +fn text_row(label: AppTextKey, value: AppTextKey) -> LabelValueRow { + metadata_row(label, app_text(value)) +} + fn runtime_mode_text(mode: &AppRuntimeMode) -> String { let key = match mode { AppRuntimeMode::Development => AppTextKey::ValueRuntimeModeDevelopment, @@ -106,7 +188,9 @@ mod tests { AppRuntimeSnapshot, }; - use super::runtime_metadata_rows; + use super::{ + runtime_metadata_rows, settings_about_status_rows, settings_preferences_general_rows, + }; #[test] fn runtime_metadata_rows_use_localized_labels() { @@ -138,4 +222,19 @@ mod tests { .any(|row| row.label == "app id" && row.value == "org.radroots.app") ); } + + #[test] + fn settings_placeholder_rows_use_localized_copy() { + let general_rows = settings_preferences_general_rows(); + let about_rows = settings_about_status_rows(); + + assert!( + general_rows + .iter() + .any(|row| row.label == "launch behavior" && row.value == "manual launch only") + ); + assert!(about_rows.iter().any(|row| { + row.label == "next milestone" && row.value == "interactive account flows" + })); + } } diff --git a/i18n/locales/en/messages.json b/i18n/locales/en/messages.json @@ -9,6 +9,39 @@ "settings.nav.accounts": "accounts", "settings.nav.settings": "settings", "settings.nav.about": "about", + "settings.accounts.summary": "prepare local identity, sign-in, and recovery flows for future radroots releases.", + "settings.accounts.profile.title": "profile", + "settings.accounts.identity.label": "local identity", + "settings.accounts.identity.value": "radroots local profile", + "settings.accounts.status.label": "sign-in state", + "settings.accounts.status.value": "not signed in", + "settings.accounts.runtime.title": "runtime", + "settings.accounts.sync.label": "sync posture", + "settings.accounts.sync.value": "single-device placeholder", + "settings.accounts.recovery.label": "recovery", + "settings.accounts.recovery.value": "not configured", + "settings.preferences.summary": "configure app behavior, device defaults, and diagnostics posture as these controls land.", + "settings.preferences.general.title": "general", + "settings.preferences.launch.label": "launch behavior", + "settings.preferences.launch.value": "manual launch only", + "settings.preferences.network.label": "network posture", + "settings.preferences.network.value": "default runtime transport", + "settings.preferences.device.title": "device state", + "settings.preferences.notifications.label": "notifications", + "settings.preferences.notifications.value": "not requested", + "settings.preferences.diagnostics.label": "diagnostics", + "settings.preferences.diagnostics.value": "runtime metadata only", + "settings.about.summary": "this app is a native radroots runtime under active development.", + "settings.about.build.title": "build", + "settings.about.shell.label": "shell", + "settings.about.shell.value": "gpui native macos window", + "settings.about.license.label": "license", + "settings.about.license.value": "gpl-3.0", + "settings.about.status.title": "status", + "settings.about.posture.label": "current posture", + "settings.about.posture.value": "bootstrap placeholder shell", + "settings.about.milestone.label": "next milestone", + "settings.about.milestone.value": "interactive account flows", "metadata.core_package": "core package", "metadata.core_version": "core version", "metadata.core_authors": "core authors",