add experimental tags and group experimental settings

This commit is contained in:
2026-11-13 08:25:17 +07:00
parent 8b9c8bd35e
commit 3484c2c71b
5 changed files with 132 additions and 65 deletions
+1
View File
@@ -853,6 +853,7 @@ impl Panel for WalletPanel {
.text_color(cx.theme().muted_foreground), .text_color(cx.theme().muted_foreground),
) )
.child(self.name.clone()) .child(self.name.clone())
.child(ui::experimental_tag(cx))
.into_any_element() .into_any_element()
} }
} }
+54
View File
@@ -60,3 +60,57 @@ pub fn settings_block(
) )
.child(control) .child(control)
} }
/// An amber marker for features that are not ready for prime time.
pub fn experimental_tag(cx: &App) -> Div {
div()
.flex_shrink_0()
.px_1p5()
.rounded_full()
.bg(cx.theme().warning.opacity(0.15))
.text_color(cx.theme().warning)
.text_xs()
.font_medium()
.child("Experimental")
}
/// A [`settings_row`] whose label carries a tag, e.g. [`experimental_tag`].
pub fn settings_row_tagged(
label: impl Into<SharedString>,
tag: Div,
description: impl Into<SharedString>,
control: impl IntoElement,
cx: &App,
) -> Div {
h_flex()
.w_full()
.gap_4()
.items_center()
.justify_between()
.child(
v_flex()
.flex_1()
.min_w_0()
.child(
h_flex()
.gap_1p5()
.items_center()
.child(div().text_sm().font_semibold().child(label.into()))
.child(tag),
)
.child(
div()
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(description.into()),
),
)
.child(
h_flex()
.w_40()
.flex_shrink_0()
.justify_end()
.items_center()
.child(control),
)
}
+5 -3
View File
@@ -19,7 +19,7 @@ use gpui_kit::prelude::FluentBuilder;
use rand::seq::IndexedRandom; use rand::seq::IndexedRandom;
use settings::AppSettings; use settings::AppSettings;
use smallvec::{SmallVec, smallvec}; use smallvec::{SmallVec, smallvec};
use ui::{settings_block, settings_row}; use ui::{experimental_tag, settings_block, settings_row, settings_row_tagged};
use super::settings::{FONT_SIZE_RANGE, RADIUS_RANGE}; use super::settings::{FONT_SIZE_RANGE, RADIUS_RANGE};
@@ -400,8 +400,9 @@ impl Render for Onboarding {
}), }),
cx, cx,
)) ))
.child(settings_row( .child(settings_row_tagged(
"Decoupling Encryption Key", "Decoupling Encryption Key",
experimental_tag(cx),
NIP4E, NIP4E,
Switch::new("onboarding-nip4e").checked(nip4e).on_click( Switch::new("onboarding-nip4e").checked(nip4e).on_click(
move |checked, _window, cx| { move |checked, _window, cx| {
@@ -412,8 +413,9 @@ impl Render for Onboarding {
)); ));
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
let features = features.child(settings_row( let features = features.child(settings_row_tagged(
"Wallet", "Wallet",
experimental_tag(cx),
WALLET, WALLET,
Switch::new("onboarding-wallet") Switch::new("onboarding-wallet")
.checked(AppSettings::get_wallet(cx)) .checked(AppSettings::get_wallet(cx))
+17 -9
View File
@@ -14,6 +14,7 @@ use gpui::{
Subscription, Window, div, Subscription, Window, div,
}; };
use gpui_kit::assets::IconName; use gpui_kit::assets::IconName;
use gpui_kit::base::StyledExt as _;
use gpui_kit::component::button::{Button, ButtonVariants}; use gpui_kit::component::button::{Button, ButtonVariants};
use gpui_kit::component::input::{Input, InputEvent, InputState, NumberInput}; use gpui_kit::component::input::{Input, InputEvent, InputState, NumberInput};
use gpui_kit::component::kbd::Kbd; use gpui_kit::component::kbd::Kbd;
@@ -218,10 +219,10 @@ impl Preferences {
fn render_wallet( fn render_wallet(
&mut self, &mut self,
#[cfg_attr(target_arch = "wasm32", allow(unused_variables))] cx: &mut Context<Self>, #[cfg_attr(target_arch = "wasm32", allow(unused_variables))] cx: &mut Context<Self>,
) -> AnyElement { ) -> Option<AnyElement> {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
{ {
return div().into_any_element(); return None;
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@@ -230,17 +231,18 @@ impl Preferences {
let enabled = AppSettings::get_wallet(cx); let enabled = AppSettings::get_wallet(cx);
let has_wallet = nip60::WalletRegistry::global(cx).read(cx).has_wallet(); let has_wallet = nip60::WalletRegistry::global(cx).read(cx).has_wallet();
Some(
v_flex() v_flex()
.w_full() .w_full()
.gap_3() .gap_3()
.child(settings_row( .child(settings_row(
"Wallet", "Wallet",
"Show the wallet and allow ecash payments.", "Show the wallet and allow ecash payments.",
Switch::new("wallet") Switch::new("wallet").checked(enabled).on_click(
.checked(enabled) move |checked, _window, cx| {
.on_click(move |checked, _window, cx| {
AppSettings::update_wallet(*checked, cx); AppSettings::update_wallet(*checked, cx);
}), },
),
cx, cx,
)) ))
.when(enabled, |this| { .when(enabled, |this| {
@@ -262,7 +264,8 @@ impl Preferences {
cx, cx,
)) ))
}) })
.into_any_element() .into_any_element(),
)
} }
} }
@@ -656,6 +659,11 @@ impl Render for Preferences {
)), )),
) )
.child(Separator::horizontal()) .child(Separator::horizontal())
.child(
v_flex()
.w_full()
.gap_3()
.child(div().text_sm().font_semibold().child("Experimental"))
.child(settings_row( .child(settings_row(
"Decoupling Encryption Key", "Decoupling Encryption Key",
NIP4E, NIP4E,
@@ -682,6 +690,8 @@ impl Render for Preferences {
}), }),
cx, cx,
)) ))
.when_some(self.render_wallet(cx), |this, wallet| this.child(wallet)),
)
.child(Separator::horizontal()) .child(Separator::horizontal())
.child(self.render_speech(cx)) .child(self.render_speech(cx))
.child(self.render_dictation_shortcut(window, cx)) .child(self.render_dictation_shortcut(window, cx))
@@ -703,7 +713,5 @@ impl Render for Preferences {
), ),
cx, cx,
)) ))
.child(Separator::horizontal())
.child(self.render_wallet(cx))
} }
} }
+3 -1
View File
@@ -1056,4 +1056,6 @@ request. Validation after the full batch: `cargo clippy --workspace --all-target
- Element ids: two known residuals documented (inbox.rs contact p-tag dedupe; - Element ids: two known residuals documented (inbox.rs contact p-tag dedupe;
`HashSet<Contact>` equality includes relay/alias, so the same pubkey with a different relay `HashSet<Contact>` equality includes relay/alias, so the same pubkey with a different relay
could render twice in the contact picker). could render twice in the contact picker).
- S1/S2 (task-handle containers, `.ok()`/`let _ =` sweeps) remain open by request. - S1/S2 (task-handle containers, `.ok()`/`let _ =` sweeps): reviewed and **declined** — judged not
worth the churn; the affected sites are benign (entity-dropped-at-shutdown cases) and the
containers are bounded in practice.