Files
Ely-GPUI-Components/examples/gallery/pages/forms/choices.rs
T

215 lines
7.0 KiB
Rust

use ely_gpui_component::{
forms::{
CheckState, Checkbox, CheckboxCard, CheckboxGroup, Choice, RadioCard, RadioGroup, Switch,
},
primitives::IconName,
};
use gpui::{App, Entity, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
use crate::{
probe::probe,
ui::{code, section, specimen},
};
pub(super) fn keep<T: 'static>(
key: &'static str,
init: impl FnOnce() -> T,
window: &mut Window,
cx: &mut App,
) -> Entity<T> {
window.use_keyed_state(key, cx, move |_, _| init())
}
pub(super) fn set<T: 'static>(state: &Entity<T>, value: T, cx: &mut App) {
state.update(cx, |state, cx| {
*state = value;
cx.notify();
});
}
fn values(list: &[&'static str]) -> Vec<SharedString> {
list.iter()
.map(|value| SharedString::from(*value))
.collect()
}
pub fn checkboxes(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let channels = [
Choice::new("email", "Email"),
Choice::new("push", "Push"),
Choice::new("sms", "Text message").disabled(),
];
let open: Vec<SharedString> = channels
.iter()
.filter(|choice| !choice.disabled)
.map(|choice| choice.value.clone())
.collect();
let on = keep("check-channels", || values(&["email"]), window, cx);
let now = on.read(cx).clone();
let parent = match now.len() {
0 => CheckState::Off,
n if n == open.len() => CheckState::On,
_ => CheckState::Mixed,
};
let (all, some) = (on.clone(), on.clone());
section(
"Checkbox / CheckboxGroup",
"On, off, or mixed when a parent's children disagree. The check pops in.",
cx,
)
.child(probe(
"checks",
div()
.flex()
.flex_col()
.gap_2()
.w(px(280.0))
.child(
Checkbox::new("check-all", parent)
.label("All notifications")
.on_change(move |on, _, cx| {
set(&all, if on { open.clone() } else { Vec::new() }, cx)
}),
)
.child(
div().pl_6().child(
CheckboxGroup::new("check-group", channels)
.selected(now)
.on_change(move |next, _, cx| set(&some, next.to_vec(), cx)),
),
),
))
.child(code("Checkbox::new(id, CheckState::Mixed)", cx))
}
pub fn radios(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let plan = keep("radio-plan", || SharedString::from("pro"), window, cx);
let density = keep(
"radio-density",
|| SharedString::from("standard"),
window,
cx,
);
let (plan_now, density_now) = (plan.read(cx).clone(), density.read(cx).clone());
section(
"Radio / RadioGroup",
"One Tab stop per group; the arrow keys move the choice.",
cx,
)
.child(
div()
.flex()
.flex_col()
.gap_6()
.child(specimen(
"plan",
probe(
"radios",
RadioGroup::new(
"radio-plan",
[
Choice::new("free", "Free"),
Choice::new("pro", "Pro"),
Choice::new("team", "Team"),
Choice::new("enterprise", "Enterprise").disabled(),
],
)
.selected(plan_now)
.on_change(move |value, _, cx| set(&plan, value.clone(), cx)),
),
cx,
))
.child(specimen(
"density, in a row",
RadioGroup::new(
"radio-density",
[
Choice::new("compact", "Compact"),
Choice::new("standard", "Standard"),
Choice::new("comfortable", "Comfortable"),
],
)
.horizontal()
.selected(density_now)
.on_change(move |value, _, cx| set(&density, value.clone(), cx)),
cx,
)),
)
}
pub fn cards(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let space = keep("card-space", || SharedString::from("personal"), window, cx);
let backup = keep("card-backup", || true, window, cx);
let (space_now, backup_now) = (space.read(cx).clone(), *backup.read(cx));
let (personal, team) = (space.clone(), space);
section(
"CheckboxCard / RadioCard",
"Larger targets that explain a choice. The chosen border turns to ink.",
cx,
)
.child(probe(
"cards",
div()
.flex()
.gap_3()
.w(px(640.0))
.child(
div().flex_1().child(
RadioCard::new("card-personal", space_now == "personal", "Personal")
.description("Just you. Notes stay on this Mac.")
.icon(IconName::User)
.on_select(move |_, cx| set(&personal, "personal".into(), cx)),
),
)
.child(
div().flex_1().child(
RadioCard::new("card-team", space_now == "team", "Team")
.description("Shared with everyone you invite.")
.icon(IconName::Users)
.on_select(move |_, cx| set(&team, "team".into(), cx)),
),
),
))
.child(
div().w(px(640.0)).child(
CheckboxCard::new("card-backup", backup_now, "Back up nightly")
.description("Copies change sets to the cloud at 2 AM.")
.icon(IconName::Cloud)
.on_change(move |on, _, cx| set(&backup, on, cx)),
),
)
}
pub fn switches(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let wifi = keep("switch-wifi", || true, window, cx);
let sync = keep("switch-sync", || false, window, cx);
let (wifi_now, sync_now) = (*wifi.read(cx), *sync.read(cx));
section(
"Switch / Toggle",
"Takes effect at once. The thumb slides with a little overshoot.",
cx,
)
.child(probe(
"switches",
div()
.flex()
.flex_col()
.gap_3()
.child(
Switch::new("switch-wifi", wifi_now)
.label("Wi-Fi")
.on_change(move |on, _, cx| set(&wifi, on, cx)),
)
.child(
Switch::new("switch-sync", sync_now)
.label("Sync over cellular")
.on_change(move |on, _, cx| set(&sync, on, cx)),
)
.child(
Switch::new("switch-locked", true)
.label("Managed by your admin")
.disabled(true),
),
))
}