app

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

commit 4ff943e0e34a7690fcdc190402ea381a6a26f477
parent a4dd61085139767959e2a8ef9318725c3fab3c7c
Author: triesap <tyson@radroots.org>
Date:   Sun,  7 Jun 2026 14:12:10 -0700

ui: prevent farm textarea first-paint overflow

Diffstat:
Mcrates/desktop/src/window.rs | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 83 insertions(+), 10 deletions(-)

diff --git a/crates/desktop/src/window.rs b/crates/desktop/src/window.rs @@ -547,6 +547,8 @@ pub struct HomeView { selected_account_tab: AccountTab, account_profile_form: Option<AccountProfileFormState>, account_farm_profile_form: Option<AccountFarmProfileFormState>, + account_farm_profile_textarea_wrap_ready: bool, + account_farm_profile_textarea_wrap_requested: bool, relay_client: Option<RadrootsNostrClient>, buyer_workspace_notice: Option<String>, } @@ -669,6 +671,8 @@ impl HomeView { selected_account_tab: AccountTab::default(), account_profile_form: None, account_farm_profile_form: None, + account_farm_profile_textarea_wrap_ready: false, + account_farm_profile_textarea_wrap_requested: false, relay_client: None, buyer_workspace_notice: None, } @@ -5227,8 +5231,10 @@ impl HomeView { account_profile_panel(&form, cx).into_any_element() } AccountTab::FarmDetails => { + self.prepare_account_farm_profile_textarea_wrap(window, cx); let form = self.account_farm_profile_form(window, cx).clone(); - account_farm_profile_panel(&form, cx).into_any_element() + account_farm_profile_panel(&form, self.account_farm_profile_textarea_wrap_ready, cx) + .into_any_element() } AccountTab::Preferences | AccountTab::Security => { account_placeholder_panel(selected_tab.panel_text_key()).into_any_element() @@ -5285,6 +5291,28 @@ impl HomeView { }; form } + + fn prepare_account_farm_profile_textarea_wrap( + &mut self, + window: &mut Window, + cx: &mut Context<Self>, + ) { + if self.account_farm_profile_textarea_wrap_ready + || self.account_farm_profile_textarea_wrap_requested + { + return; + } + + self.account_farm_profile_textarea_wrap_requested = true; + cx.spawn_in(window, async move |this, cx| { + Timer::after(Duration::from_millis(16)).await; + let _ = this.update(cx, |this, cx| { + this.account_farm_profile_textarea_wrap_ready = true; + cx.notify(); + }); + }) + .detach(); + } } #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -9259,13 +9287,42 @@ fn account_form_text_input(input: &Entity<InputState>) -> impl IntoElement { .w_full() } -fn account_form_text_area_input(input: &Entity<InputState>) -> impl IntoElement { - app_text_input(input, false) - .with_size(Size::Small) - .text_size(px(APP_UI_THEME.foundation.typography.settings_row_text_px)) - .font_weight(gpui::FontWeight::NORMAL) - .rounded(px(ACCOUNT_FORM_CONTROL_RADIUS_PX)) +fn account_form_text_area_input_with_wrapped_preview( + input: &Entity<InputState>, + is_wrap_ready: bool, + cx: &mut Context<HomeView>, +) -> impl IntoElement { + let preview = input.read(cx).value(); + + div() + .relative() .w_full() + .child( + app_text_input(input, false) + .with_size(Size::Small) + .text_size(px(APP_UI_THEME.foundation.typography.settings_row_text_px)) + .font_weight(gpui::FontWeight::NORMAL) + .rounded(px(ACCOUNT_FORM_CONTROL_RADIUS_PX)) + .w_full() + .opacity(if is_wrap_ready { 1.0 } else { 0.0 }), + ) + .when(!is_wrap_ready, |this| { + this.child( + div() + .absolute() + .top_0() + .left_0() + .right_0() + .px(px(8.0)) + .py(px(2.0)) + .line_height(relative(1.25)) + .whitespace_normal() + .text_size(px(APP_UI_THEME.foundation.typography.settings_row_text_px)) + .font_weight(gpui::FontWeight::NORMAL) + .text_color(rgb(APP_UI_THEME.foundation.text.primary)) + .child(preview), + ) + }) } fn account_profile_select_input(select: &Entity<AccountProfileSelectState>) -> impl IntoElement { @@ -9292,6 +9349,7 @@ fn account_farm_profile_select_input( fn account_farm_profile_panel( form: &AccountFarmProfileFormState, + is_textarea_wrap_ready: bool, cx: &mut Context<HomeView>, ) -> impl IntoElement { app_stack_v(APP_UI_THEME.shells.home_stack_gap_px) @@ -9306,7 +9364,11 @@ fn account_farm_profile_panel( div() .flex_1() .min_w_0() - .child(account_farm_profile_main_card(form)), + .child(account_farm_profile_main_card( + form, + is_textarea_wrap_ready, + cx, + )), ) .child( app_stack_v(APP_UI_THEME.shells.home_stack_gap_px) @@ -9319,7 +9381,11 @@ fn account_farm_profile_panel( .child(account_farm_profile_action_row(cx)) } -fn account_farm_profile_main_card(form: &AccountFarmProfileFormState) -> impl IntoElement { +fn account_farm_profile_main_card( + form: &AccountFarmProfileFormState, + is_textarea_wrap_ready: bool, + cx: &mut Context<HomeView>, +) -> impl IntoElement { account_farm_profile_card( app_stack_v(APP_UI_THEME.shells.home_stack_gap_px) .w_full() @@ -9370,6 +9436,8 @@ fn account_farm_profile_main_card(form: &AccountFarmProfileFormState) -> impl In .child(account_farm_profile_text_area_field( AppTextKey::AccountFarmDetailsAboutFarmLabel, &form.about_farm_input, + is_textarea_wrap_ready, + cx, )) .child( div() @@ -9445,8 +9513,13 @@ fn account_farm_profile_select_field( fn account_farm_profile_text_area_field( label_key: AppTextKey, input: &Entity<InputState>, + is_wrap_ready: bool, + cx: &mut Context<HomeView>, ) -> impl IntoElement { - account_profile_labeled_control(label_key, account_form_text_area_input(input)) + account_profile_labeled_control( + label_key, + account_form_text_area_input_with_wrapped_preview(input, is_wrap_ready, cx), + ) } fn account_farm_profile_completeness_card() -> impl IntoElement {