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:
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",