app

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

commit 7ab5f09a59e52b6b781e99251abdedd38fe16011
parent 1642b29384b1a30e63e53036b71a054ed54647fc
Author: triesap <tyson@radroots.org>
Date:   Sun,  7 Jun 2026 11:22:21 -0700

app: refine settings account dropdown

Diffstat:
Mcrates/desktop/src/source_guards.rs | 13++++++++++++-
Mcrates/desktop/src/window.rs | 72+++++++++++++++++++++++++++++++-----------------------------------------
Mcrates/i18n/src/keys.rs | 3+++
Mcrates/i18n/src/lib.rs | 12++++++++++++
Mcrates/ui/src/lib.rs | 15++++++++-------
Mcrates/ui/src/primitives.rs | 46++++++++++++++++++++++++++++++++++++++++++++--
Mi18n/locales/en/messages.json | 3+++
7 files changed, 113 insertions(+), 51 deletions(-)

diff --git a/crates/desktop/src/source_guards.rs b/crates/desktop/src/source_guards.rs @@ -27,6 +27,8 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[ "6.5", "6.50", "6.500", + " Farm Profile ", + "Farm Profile", "Salad mix", "USD", "/tmp/radroots/data/apps/app", @@ -38,6 +40,7 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[ "account-open-workspace", "account-log-out", "account-more", + "account_1", "buyer", "buyer-detail-add-to-cart", "buyer-detail-back", @@ -177,6 +180,10 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[ "identity", "items need review", "npub1", + "npub1qqqqq...qqqqqq", + "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", + "npub1sxczr...5lkheq", + "npub1sxczrq2dp4jtehcm8mtemj975u5ytf2d7mc6dpuuq3rzkjzr76ls5lkheq", "receipt-clean", "receipt-issue", "guest", @@ -308,6 +315,7 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[ "settings-about-conflict-action", "settings-about-refresh-sync", "settings-about-refresh-sync-disabled", + "settings-account-row", "settings-remove-blackout-period", "settings-remove-fulfillment-window", "settings.farm.load_failed", @@ -322,6 +330,7 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[ "wss://relay.example", "wss://relay.radroots.example", "{currency_code} {dollars}.{cents:02}", + "{prefix}...{suffix}", "{}, {}", "{}: {}", "{} {} {}.", @@ -694,8 +703,10 @@ const REQUIRED_WINDOW_COPY_KEYS: &[&str] = &[ "AppTextKey::SettingsAccountActivationInactive", "AppTextKey::SettingsAccountAddAction", "AppTextKey::SettingsAccountLogOutAction", - "AppTextKey::SettingsAccountMoreActions", "AppTextKey::SettingsAccountOpenWorkspaceAction", + "AppTextKey::SettingsAccountImportFileAction", + "AppTextKey::SettingsAccountImportDatabaseAction", + "AppTextKey::SettingsAccountConnectRemoteBunkerAction", "AppTextKey::SettingsNavFarm", "AppTextKey::SettingsFarmPanelBody", "AppTextKey::SettingsFarmUnavailableBody", diff --git a/crates/desktop/src/window.rs b/crates/desktop/src/window.rs @@ -4,11 +4,7 @@ use gpui::{ Subscription, Timer, Window, WindowBounds, WindowOptions, div, prelude::FluentBuilder, px, relative, rgb, size, }; -use gpui_component::{ - IconName, Root, Sizable, Size, - button::{Button, ButtonCustomVariant, ButtonRounded, ButtonVariants, DropdownButton}, - input::{InputEvent, InputState}, -}; +use gpui_component::{IconName, Root, input::InputEvent, input::InputState, menu::PopupMenuItem}; use radroots_app_i18n::{AppTextKey, app_text}; use radroots_app_remote_signer::{ RadrootsAppRemoteSignerApprovedSession, RadrootsAppRemoteSignerPendingPollOutcome, @@ -35,15 +31,16 @@ use radroots_app_ui::{ app_button_primary as action_button_primary, app_button_primary_disabled as action_button_primary_disabled, app_button_secondary as action_button, app_button_secondary_disabled as action_button_disabled, - app_button_text as text_button, app_checkbox_field, app_cluster, app_detail_row, - app_divider as section_divider, app_focused_detail_view, app_focused_task_view, app_form_field, - app_form_input_text, app_form_section, app_heading_section, app_heading_view, - app_input_text as app_text_input, app_scroll_panel, - app_segment_button_icon as icon_segment_button, app_shared_label_text, app_shared_text, - app_split_shell, app_stack_h, app_stack_v, app_status_indicator as status_indicator, - app_surface_card, app_surface_card_section as home_card, app_surface_panel, - app_surface_sidebar, app_surface_window as app_window_shell, - app_text_badge as settings_badge_text, app_text_body_subtle as home_body_text, app_text_label, + app_button_square_dropdown_secondary as action_dropdown_button, app_button_text as text_button, + app_checkbox_field, app_cluster, app_detail_row, app_divider as section_divider, + app_focused_detail_view, app_focused_task_view, app_form_field, app_form_input_text, + app_form_section, app_heading_section, app_heading_view, app_input_text as app_text_input, + app_scroll_panel, app_segment_button_icon as icon_segment_button, app_shared_label_text, + app_shared_text, app_split_shell, app_stack_h, app_stack_v, + app_status_indicator as status_indicator, app_surface_card, + app_surface_card_section as home_card, app_surface_panel, app_surface_sidebar, + app_surface_window as app_window_shell, app_text_badge as settings_badge_text, + app_text_body_subtle as home_body_text, app_text_label, app_text_label as home_farm_setup_field_label, app_text_value, label_value_list, runtime_metadata_rows, settings_preferences_general_rows, utility_title_row, }; @@ -7574,33 +7571,26 @@ impl SettingsWindowView { } fn settings_account_more_actions_button(cx: &App) -> impl IntoElement { - let sizing = APP_UI_THEME.components.app_button.sizing; - let colors = APP_UI_THEME.components.app_button.secondary_colors; - let hover_background = if colors.hover_changes_background { - colors.hover_background - } else { - colors.background - }; - let neutral_variant = ButtonCustomVariant::new(cx) - .color(rgb(colors.background).into()) - .foreground(rgb(colors.foreground).into()) - .border(gpui::transparent_black()) - .hover(rgb(hover_background).into()) - .active(rgb(colors.active_background).into()); - - DropdownButton::new("account-more") - .button( - Button::new("account-more-anchor") - .tab_stop(false) - .w(px(0.0)) - .overflow_hidden() - .custom(neutral_variant) - .with_size(Size::Size(px(sizing.square_width_px))), - ) - .dropdown_menu(|menu, _, _| menu) - .custom(neutral_variant) - .rounded(ButtonRounded::Size(px(sizing.corner_radius_px))) - .with_size(Size::Size(px(sizing.square_width_px))) + action_dropdown_button( + "account-more", + |menu, _, _| { + menu.item( + PopupMenuItem::new(app_text(AppTextKey::SettingsAccountImportFileAction)) + .on_click(|_, _, _| {}), + ) + .item( + PopupMenuItem::new(app_text(AppTextKey::SettingsAccountImportDatabaseAction)) + .on_click(|_, _, _| {}), + ) + .item( + PopupMenuItem::new(app_text( + AppTextKey::SettingsAccountConnectRemoteBunkerAction, + )) + .on_click(|_, _, _| {}), + ) + }, + cx, + ) } fn settings_account_detail_account( diff --git a/crates/i18n/src/keys.rs b/crates/i18n/src/keys.rs @@ -489,6 +489,9 @@ define_app_text_keys! { SettingsAccountLogOutAction => "settings.account.action.log_out", SettingsAccountMoreActions => "settings.account.action.more_actions", SettingsAccountOpenWorkspaceAction => "settings.account.action.open_workspace", + SettingsAccountImportFileAction => "settings.account.action.import_file", + SettingsAccountImportDatabaseAction => "settings.account.action.import_database", + SettingsAccountConnectRemoteBunkerAction => "settings.account.action.connect_remote_bunker", SettingsViewAccount => "settings.view.account", SettingsViewSettings => "settings.view.settings", SettingsViewAbout => "settings.view.about", diff --git a/crates/i18n/src/lib.rs b/crates/i18n/src/lib.rs @@ -172,6 +172,18 @@ mod tests { app_text(AppTextKey::SettingsAccountOpenWorkspaceAction), "Admin Console" ); + assert_eq!( + app_text(AppTextKey::SettingsAccountImportFileAction), + "Import from file" + ); + assert_eq!( + app_text(AppTextKey::SettingsAccountImportDatabaseAction), + "Import from database" + ); + assert_eq!( + app_text(AppTextKey::SettingsAccountConnectRemoteBunkerAction), + "Connect remote bunker" + ); } #[test] diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs @@ -8,13 +8,14 @@ pub use primitives::{ AppCheckboxFieldSpec, AppFormFieldSpec, AppIconButtonSpec, AppSegmentButtonIconSpec, LabelValueRow, app_button_card, app_button_choice, app_button_compact, app_button_icon, app_button_list_row, app_button_primary, app_button_primary_disabled, app_button_secondary, - app_button_secondary_disabled, app_button_text, app_checkbox_field, app_cluster, - app_detail_row, app_divider, app_focused_detail_view, app_focused_task_view, app_form_field, - app_form_input_text, app_form_section, app_heading_section, app_heading_view, app_input_text, - app_scroll_panel, app_segment_button_icon, app_split_shell, app_stack_h, app_stack_v, - app_status_indicator, app_surface_card, app_surface_card_section, app_surface_panel, - app_surface_sidebar, app_surface_window, app_text_badge, app_text_body, app_text_body_subtle, - app_text_label, app_text_value, label_value_list, utility_title_row, + app_button_secondary_disabled, app_button_square_dropdown_secondary, app_button_text, + app_checkbox_field, app_cluster, app_detail_row, app_divider, app_focused_detail_view, + app_focused_task_view, app_form_field, app_form_input_text, app_form_section, + app_heading_section, app_heading_view, app_input_text, app_scroll_panel, + app_segment_button_icon, app_split_shell, app_stack_h, app_stack_v, app_status_indicator, + app_surface_card, app_surface_card_section, app_surface_panel, app_surface_sidebar, + app_surface_window, app_text_badge, app_text_body, app_text_body_subtle, app_text_label, + app_text_value, label_value_list, utility_title_row, }; pub use text::{ SettingsPreferencesGeneralRowState, app_shared_label_text, app_shared_text, diff --git a/crates/ui/src/primitives.rs b/crates/ui/src/primitives.rs @@ -1,12 +1,13 @@ use gpui::{ - AnyElement, App, ClickEvent, Div, ElementId, Entity, InteractiveElement, IntoElement, + AnyElement, App, ClickEvent, Context, Div, ElementId, Entity, InteractiveElement, IntoElement, ParentElement, SharedString, StatefulInteractiveElement, Styled, Window, div, prelude::FluentBuilder, px, relative, rgb, transparent_black, }; use gpui_component::{ Icon, IconName, Sizable, Size, - button::{Button, ButtonCustomVariant, ButtonRounded, ButtonVariants}, + button::{Button, ButtonCustomVariant, ButtonRounded, ButtonVariants, DropdownButton}, input::{Input, InputState}, + menu::PopupMenu, }; use std::rc::Rc; @@ -711,6 +712,47 @@ pub fn app_button_compact( ) } +pub fn app_button_square_dropdown_secondary( + id: &'static str, + menu: impl Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu + 'static, + cx: &App, +) -> impl IntoElement { + let sizing = APP_UI_THEME.components.app_button.sizing; + let colors = APP_UI_THEME.components.app_button.secondary_colors; + let hover_background = if colors.hover_changes_background { + colors.hover_background + } else { + colors.background + }; + let neutral_variant = ButtonCustomVariant::new(cx) + .color(rgb(colors.background).into()) + .foreground(rgb(colors.foreground).into()) + .border(transparent_black()) + .hover(rgb(hover_background).into()) + .active(rgb(colors.active_background).into()); + + div() + .w(px(sizing.square_width_px)) + .h(px(sizing.height_px)) + .rounded(px(sizing.corner_radius_px)) + .overflow_hidden() + .child( + DropdownButton::new(id) + .button( + Button::new((id, 0usize)) + .tab_stop(false) + .w(px(0.0)) + .overflow_hidden() + .custom(neutral_variant) + .with_size(Size::Size(px(sizing.square_width_px))), + ) + .dropdown_menu(menu) + .custom(neutral_variant) + .rounded(ButtonRounded::Size(px(sizing.corner_radius_px))) + .with_size(Size::Size(px(sizing.square_width_px))), + ) +} + fn app_button_label( button: Button, label: SharedString, diff --git a/i18n/locales/en/messages.json b/i18n/locales/en/messages.json @@ -468,6 +468,9 @@ "settings.account.action.log_out": "Log Out", "settings.account.action.more_actions": "More Actions", "settings.account.action.open_workspace": "Admin Console", + "settings.account.action.import_file": "Import from file", + "settings.account.action.import_database": "Import from database", + "settings.account.action.connect_remote_bunker": "Connect remote bunker", "settings.view.account": "account", "settings.view.settings": "settings", "settings.view.about": "about",