add popover
This commit is contained in:
@@ -36,6 +36,9 @@ pub mod avatar;
|
|||||||
#[cfg(feature = "input")]
|
#[cfg(feature = "input")]
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
|
||||||
|
#[cfg(feature = "popover")]
|
||||||
|
pub mod popover;
|
||||||
|
|
||||||
/// Initializes everything the components need at startup.
|
/// Initializes everything the components need at startup.
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
gpui_native_theme::Theme::init(cx);
|
gpui_native_theme::Theme::init(cx);
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
//! Semantic color roles. This module is the only place in the workspace
|
//! Semantic color roles. This module is the only place in the workspace
|
||||||
//! allowed to hold color literals.
|
//! allowed to hold color literals.
|
||||||
|
|
||||||
use gpui::{Hsla, rgb};
|
use gpui::{Hsla, hsla, rgb};
|
||||||
|
|
||||||
fn hex(hex: u32) -> Hsla {
|
fn hex(hex: u32) -> Hsla {
|
||||||
rgb(hex).into()
|
rgb(hex).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The dim scrim behind modal layers; always a translucent black.
|
||||||
|
pub(crate) fn scrim(alpha: f32) -> Hsla {
|
||||||
|
hsla(0., 0., 0., alpha)
|
||||||
|
}
|
||||||
|
|
||||||
/// The semantic color roles components paint from.
|
/// The semantic color roles components paint from.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct ColorTokens {
|
pub struct ColorTokens {
|
||||||
@@ -28,6 +33,8 @@ pub struct ColorTokens {
|
|||||||
pub input: Hsla,
|
pub input: Hsla,
|
||||||
pub ring: Hsla,
|
pub ring: Hsla,
|
||||||
pub selection: Hsla,
|
pub selection: Hsla,
|
||||||
|
/// The scrim behind modal layers; translucent in every theme.
|
||||||
|
pub overlay: Hsla,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColorTokens {
|
impl ColorTokens {
|
||||||
@@ -52,6 +59,7 @@ impl ColorTokens {
|
|||||||
input: hex(0xe4e4e7),
|
input: hex(0xe4e4e7),
|
||||||
ring: hex(0x93c5fd),
|
ring: hex(0x93c5fd),
|
||||||
selection: hex(0xdbeafe),
|
selection: hex(0xdbeafe),
|
||||||
|
overlay: scrim(0.25),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +84,7 @@ impl ColorTokens {
|
|||||||
input: hex(0x27272a),
|
input: hex(0x27272a),
|
||||||
ring: hex(0x1d4ed8),
|
ring: hex(0x1d4ed8),
|
||||||
selection: hex(0x1e3a8a),
|
selection: hex(0x1e3a8a),
|
||||||
|
overlay: scrim(0.45),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ pub struct ThemeDefinition {
|
|||||||
pub input: Option<String>,
|
pub input: Option<String>,
|
||||||
pub ring: Option<String>,
|
pub ring: Option<String>,
|
||||||
pub selection: Option<String>,
|
pub selection: Option<String>,
|
||||||
|
pub overlay: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThemeDefinition {
|
impl ThemeDefinition {
|
||||||
@@ -107,6 +108,10 @@ impl ThemeDefinition {
|
|||||||
pub fn selection(&self) -> Option<Hsla> {
|
pub fn selection(&self) -> Option<Hsla> {
|
||||||
parse_hex(self.selection.as_deref()?)
|
parse_hex(self.selection.as_deref()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn overlay(&self) -> Option<Hsla> {
|
||||||
|
parse_hex(self.overlay.as_deref()?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `#rgb` or `#rrggbb` into an opaque color.
|
/// Parses `#rgb` or `#rrggbb` into an opaque color.
|
||||||
|
|||||||
+77
-1
@@ -20,7 +20,8 @@ pub use ramps::{AccentShades, Oklch};
|
|||||||
pub use resolve::{Ramps, ResolvedTheme};
|
pub use resolve::{Ramps, ResolvedTheme};
|
||||||
pub use system::{AccessibilityPreferences, PartialPalette, SourceKind, SystemTheme};
|
pub use system::{AccessibilityPreferences, PartialPalette, SourceKind, SystemTheme};
|
||||||
|
|
||||||
use gpui::{App, Global, Pixels, WindowAppearance, px};
|
use gpui::{App, Global, Hsla, Pixels, WindowAppearance, px};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// Light or dark, resolved from the system appearance.
|
/// Light or dark, resolved from the system appearance.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Deserialize)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Deserialize)]
|
||||||
@@ -47,6 +48,9 @@ pub struct Theme {
|
|||||||
pub colors: ColorTokens,
|
pub colors: ColorTokens,
|
||||||
pub ramps: Ramps,
|
pub ramps: Ramps,
|
||||||
pub radius: Radius,
|
pub radius: Radius,
|
||||||
|
pub elevations: Elevations,
|
||||||
|
/// Overlay transition timing; gpui's animation primitives do the rest.
|
||||||
|
pub motion: Motion,
|
||||||
/// The platform's native root font size; rem-based sizing scales with it.
|
/// The platform's native root font size; rem-based sizing scales with it.
|
||||||
pub root_font_size: Pixels,
|
pub root_font_size: Pixels,
|
||||||
pub sizes: SizeTable,
|
pub sizes: SizeTable,
|
||||||
@@ -61,6 +65,8 @@ pub struct Radius {
|
|||||||
/// Small controls: checkbox and radio indicators.
|
/// Small controls: checkbox and radio indicators.
|
||||||
pub sm: Pixels,
|
pub sm: Pixels,
|
||||||
pub control: Pixels,
|
pub control: Pixels,
|
||||||
|
/// Floating layers: popovers, menus, dialogs.
|
||||||
|
pub overlay: Pixels,
|
||||||
/// Pill and circle shapes.
|
/// Pill and circle shapes.
|
||||||
pub full: Pixels,
|
pub full: Pixels,
|
||||||
}
|
}
|
||||||
@@ -70,11 +76,79 @@ impl Default for Radius {
|
|||||||
Self {
|
Self {
|
||||||
sm: px(4.),
|
sm: px(4.),
|
||||||
control: px(6.),
|
control: px(6.),
|
||||||
|
overlay: px(10.),
|
||||||
full: px(9999.),
|
full: px(9999.),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// One drop shadow of a floating layer, transcribed from the platform's
|
||||||
|
/// native overlay shadows.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Elevation {
|
||||||
|
pub offset_y: Pixels,
|
||||||
|
pub blur_radius: Pixels,
|
||||||
|
pub spread_radius: Pixels,
|
||||||
|
/// Translucent black, like every native overlay shadow.
|
||||||
|
pub color: Hsla,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Elevation {
|
||||||
|
/// The gpui shadow list an overlay panel paints with.
|
||||||
|
pub fn shadows(self) -> Vec<gpui::BoxShadow> {
|
||||||
|
vec![gpui::BoxShadow {
|
||||||
|
color: self.color,
|
||||||
|
offset: gpui::point(px(0.), self.offset_y),
|
||||||
|
blur_radius: self.blur_radius,
|
||||||
|
spread_radius: self.spread_radius,
|
||||||
|
inset: false,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The drop shadows of each floating layer class.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Elevations {
|
||||||
|
/// Popovers and menus ride above content on a tight shadow.
|
||||||
|
pub popover: Elevation,
|
||||||
|
/// Modal dialogs sit higher with a wider one.
|
||||||
|
pub dialog: Elevation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Elevations {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
popover: Elevation {
|
||||||
|
offset_y: px(4.),
|
||||||
|
blur_radius: px(24.),
|
||||||
|
spread_radius: px(0.),
|
||||||
|
color: colors::scrim(0.3),
|
||||||
|
},
|
||||||
|
dialog: Elevation {
|
||||||
|
offset_y: px(8.),
|
||||||
|
blur_radius: px(40.),
|
||||||
|
spread_radius: px(0.),
|
||||||
|
color: colors::scrim(0.35),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Overlay transition timings; the platform refines these per phase.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Motion {
|
||||||
|
/// The enter transition of popovers, menus, and dialogs.
|
||||||
|
pub overlay: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Motion {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
overlay: Duration::from_millis(200),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A named control size class.
|
/// A named control size class.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub enum Size {
|
pub enum Size {
|
||||||
@@ -170,6 +244,8 @@ impl Theme {
|
|||||||
colors: resolved.colors,
|
colors: resolved.colors,
|
||||||
ramps: resolved.ramps,
|
ramps: resolved.ramps,
|
||||||
radius: resolved.radius,
|
radius: resolved.radius,
|
||||||
|
elevations: resolved.elevations,
|
||||||
|
motion: resolved.motion,
|
||||||
root_font_size: resolved.root_font_size,
|
root_font_size: resolved.root_font_size,
|
||||||
sizes: resolved.sizes,
|
sizes: resolved.sizes,
|
||||||
accessibility: resolved.accessibility,
|
accessibility: resolved.accessibility,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::definition::ThemeDefinition;
|
use crate::definition::ThemeDefinition;
|
||||||
use crate::ramps::{AccentShades, Oklch, contrast_foreground, derive_shades, mix};
|
use crate::ramps::{AccentShades, Oklch, contrast_foreground, derive_shades, mix};
|
||||||
use crate::system::SystemTheme;
|
use crate::system::SystemTheme;
|
||||||
use crate::{ColorTokens, Radius, SizeTable, ThemeVariant};
|
use crate::{ColorTokens, Elevations, Motion, Radius, SizeTable, ThemeVariant};
|
||||||
use gpui::px;
|
use gpui::px;
|
||||||
|
|
||||||
/// Derived state shades for the colors that get pressed and hovered.
|
/// Derived state shades for the colors that get pressed and hovered.
|
||||||
@@ -19,6 +19,8 @@ pub struct ResolvedTheme {
|
|||||||
pub colors: ColorTokens,
|
pub colors: ColorTokens,
|
||||||
pub ramps: Ramps,
|
pub ramps: Ramps,
|
||||||
pub radius: Radius,
|
pub radius: Radius,
|
||||||
|
pub elevations: Elevations,
|
||||||
|
pub motion: Motion,
|
||||||
/// The platform's native root font size; the fallback theme uses 16.
|
/// The platform's native root font size; the fallback theme uses 16.
|
||||||
pub root_font_size: gpui::Pixels,
|
pub root_font_size: gpui::Pixels,
|
||||||
pub sizes: SizeTable,
|
pub sizes: SizeTable,
|
||||||
@@ -123,6 +125,11 @@ pub(crate) fn resolve(
|
|||||||
system_palette.selection,
|
system_palette.selection,
|
||||||
base.selection,
|
base.selection,
|
||||||
),
|
),
|
||||||
|
overlay: pick(
|
||||||
|
def_color(|d| d.overlay()),
|
||||||
|
system_palette.overlay,
|
||||||
|
base.overlay,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let accessibility = system.accessibility;
|
let accessibility = system.accessibility;
|
||||||
@@ -172,6 +179,8 @@ pub(crate) fn resolve(
|
|||||||
},
|
},
|
||||||
colors,
|
colors,
|
||||||
radius,
|
radius,
|
||||||
|
elevations: Elevations::default(),
|
||||||
|
motion: Motion::default(),
|
||||||
root_font_size,
|
root_font_size,
|
||||||
sizes,
|
sizes,
|
||||||
accessibility,
|
accessibility,
|
||||||
@@ -274,6 +283,49 @@ mod tests {
|
|||||||
assert!((resolved.sizes.small.input_height - expected_small).abs() < px(0.01));
|
assert!((resolved.sizes.small.input_height - expected_small).abs() < px(0.01));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn overlay_is_translucent_and_overridable() {
|
||||||
|
let light = resolve(
|
||||||
|
&system(ThemeVariant::Light, PartialPalette::default(), None),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let dark = resolve(
|
||||||
|
&system(ThemeVariant::Dark, PartialPalette::default(), None),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Both scrims are translucent black; dark is denser for contrast.
|
||||||
|
assert!(light.colors.overlay.a > 0.0 && light.colors.overlay.a < 0.5);
|
||||||
|
assert!(dark.colors.overlay.a > light.colors.overlay.a);
|
||||||
|
|
||||||
|
let def = ThemeDefinition::parse_toml("overlay = \"#000000\"").unwrap();
|
||||||
|
let overridden = resolve(
|
||||||
|
&system(ThemeVariant::Light, PartialPalette::default(), None),
|
||||||
|
Some(&def),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
assert_eq!(overridden.colors.overlay, hsla(0x000000));
|
||||||
|
assert_eq!(overridden.colors.overlay.a, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn elevations_and_motion_resolve_with_defaults() {
|
||||||
|
let resolved = resolve(
|
||||||
|
&system(ThemeVariant::Dark, PartialPalette::default(), None),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
// The popover shadow is softer and tighter than the dialog's.
|
||||||
|
assert!(resolved.elevations.popover.blur_radius < resolved.elevations.dialog.blur_radius);
|
||||||
|
assert!(resolved.motion.overlay > std::time::Duration::ZERO);
|
||||||
|
let shadows = resolved.elevations.popover.shadows();
|
||||||
|
assert_eq!(shadows.len(), 1);
|
||||||
|
assert!(!shadows[0].inset);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn system_colors_override_the_base_but_leave_the_rest_intact() {
|
fn system_colors_override_the_base_but_leave_the_rest_intact() {
|
||||||
let palette = PartialPalette {
|
let palette = PartialPalette {
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ impl MacosSource {
|
|||||||
input: Self::color_to_hsla(&NSColor::controlBackgroundColor()),
|
input: Self::color_to_hsla(&NSColor::controlBackgroundColor()),
|
||||||
ring: Self::color_to_hsla(&NSColor::keyboardFocusIndicatorColor()),
|
ring: Self::color_to_hsla(&NSColor::keyboardFocusIndicatorColor()),
|
||||||
selection: Self::color_to_hsla(&NSColor::selectedTextBackgroundColor()),
|
selection: Self::color_to_hsla(&NSColor::selectedTextBackgroundColor()),
|
||||||
|
overlay: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ pub struct PartialPalette {
|
|||||||
pub input: Option<Hsla>,
|
pub input: Option<Hsla>,
|
||||||
pub ring: Option<Hsla>,
|
pub ring: Option<Hsla>,
|
||||||
pub selection: Option<Hsla>,
|
pub selection: Option<Hsla>,
|
||||||
|
/// No platform states a scrim color; preset and user files override it.
|
||||||
|
pub overlay: Option<Hsla>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A normalized snapshot of the running system's theme.
|
/// A normalized snapshot of the running system's theme.
|
||||||
|
|||||||
+3
-2
@@ -150,7 +150,7 @@ Omarchy `colors.toml` maps almost 1:1: `lighter_background` → `surface`, `dark
|
|||||||
|
|
||||||
The set stays role-minimal and grows one concept at a time, driven by the unit that needs it. Known planned additions:
|
The set stays role-minimal and grows one concept at a time, driven by the unit that needs it. Known planned additions:
|
||||||
|
|
||||||
- **Overlay scrim + shadow/elevation tokens** — with the overlay units (Popover/Dialog/Menu, unit 11+); §5.5's popup elevation promise. No current role covers the modality backdrop.
|
- ~~**Overlay scrim + shadow/elevation tokens**~~ — ✅ landed with unit 11 (2026-10-29): `colors.overlay` (translucent-black scrim, denser in dark; TOML-overridable; no platform states one), `Radius.overlay` (10 pt), `Elevations.popover`/`dialog` (transcribed NSPopover-class shadows, builder → `Vec<BoxShadow>`), and `Motion.overlay` (200 ms enter transition). Popover consumes elevation + motion; the scrim waits for Dialog.
|
||||||
- **`success` / `warning` roles** — with the first severity-bearing component (Toast, badges, validation); the Omarchy mapping above already anticipates them.
|
- **`success` / `warning` roles** — with the first severity-bearing component (Toast, badges, validation); the Omarchy mapping above already anticipates them.
|
||||||
- **`knob` / control-fill role** — only if Slider (unit 7) confirms the Switch's borrowed roles (`primary_foreground` thumb, `border` off-track) as a second consumer; until then no expansion.
|
- **`knob` / control-fill role** — only if Slider (unit 7) confirms the Switch's borrowed roles (`primary_foreground` thumb, `border` off-track) as a second consumer; until then no expansion.
|
||||||
|
|
||||||
@@ -208,7 +208,8 @@ Each row is one review unit: build it, show it in the gallery, review, then move
|
|||||||
| 8 | core | Progress | Determinate + indeterminate. |
|
| 8 | core | Progress | Determinate + indeterminate. |
|
||||||
| 9 | core | Avatar | Initials; image slot later. |
|
| 9 | core | Avatar | Initials; image slot later. |
|
||||||
| 10 | core | Input (single-line) then multiline, NumberInput | String buffer + `unicode-segmentation` word movement; the field owns its own selection. May seed `crates/editor`. Single-line finishing pass: §6.2. |
|
| 10 | core | Input (single-line) then multiline, NumberInput | String buffer + `unicode-segmentation` word movement; the field owns its own selection. May seed `crates/editor`. Single-line finishing pass: §6.2. |
|
||||||
| 11+ | core | Popover, Tooltip, Menu, Dialog, AlertDialog, Sheet, Toast | One unit each, same gate. |
|
| 11 | core | Popover | ✅ Landed (2026-10-29). First overlay. Controlled `open` + `on_change` (Rc-shared handler); `trigger`/`content` element closures; panel = surface + `Radius.overlay` + `Elevations.popover` + border, role Dialog with label; `anchored()` + `deferred()` (window-overflow flip for free); enter fade via gpui `with_animation` at `Motion.overlay` (respects reduce-motion); claims keyboard focus while open; escape and click-outside dismiss (outside clicks swallowed). No scrim — native macOS popover model; the overlay token waits for Dialog. Known v1 gaps: no exit animation, trigger aria-expanded left to the app |
|
||||||
|
| 11+ | core | Tooltip, Menu, Dialog, AlertDialog, Sheet, Toast | One unit each, same gate. Menu reuses the popover shell + `Radius.overlay`/`Elevations.popover`; Dialog consumes `colors.overlay` (scrim) + `Elevations.dialog` |
|
||||||
| then | data (new) | List, Table, Tree, Tabs, Sidebar | Created on demand, same gate. |
|
| then | data (new) | List, Table, Tree, Tabs, Sidebar | Created on demand, same gate. |
|
||||||
| then | pickers or data | Calendar/DatePicker, TimeField, ColorPicker | Decide at unit time. |
|
| then | pickers or data | Calendar/DatePicker, TimeField, ColorPicker | Decide at unit time. |
|
||||||
| editor | editor (new) | Text/code editor, syntax highlighting (D12) | Same gate. |
|
| editor | editor (new) | Text/code editor, syntax highlighting (D12) | Same gate. |
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use gpui_native_core::checkbox::Checkbox;
|
|||||||
use gpui_native_core::common::{Sizable as _, h_flex, v_flex};
|
use gpui_native_core::common::{Sizable as _, h_flex, v_flex};
|
||||||
use gpui_native_core::input::{Input, InputState};
|
use gpui_native_core::input::{Input, InputState};
|
||||||
use gpui_native_core::link::Link;
|
use gpui_native_core::link::Link;
|
||||||
|
use gpui_native_core::popover::Popover;
|
||||||
use gpui_native_core::progress::Progress;
|
use gpui_native_core::progress::Progress;
|
||||||
use gpui_native_core::radio::{Radio, RadioGroup};
|
use gpui_native_core::radio::{Radio, RadioGroup};
|
||||||
use gpui_native_core::slider::Slider;
|
use gpui_native_core::slider::Slider;
|
||||||
@@ -27,6 +28,7 @@ struct Gallery {
|
|||||||
toggle_pressed: bool,
|
toggle_pressed: bool,
|
||||||
volume: f32,
|
volume: f32,
|
||||||
input_state: Entity<InputState>,
|
input_state: Entity<InputState>,
|
||||||
|
popover_open: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for Gallery {
|
impl Render for Gallery {
|
||||||
@@ -275,6 +277,47 @@ impl Render for Gallery {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.child(
|
||||||
|
v_flex()
|
||||||
|
.gap_2()
|
||||||
|
.child(section_label(
|
||||||
|
"popover · native ref — NSPopover, WinUI Flyout, Adwaita Popover",
|
||||||
|
colors,
|
||||||
|
))
|
||||||
|
.child({
|
||||||
|
let gallery = gallery.clone();
|
||||||
|
Popover::new("gallery-popover")
|
||||||
|
.open(self.popover_open)
|
||||||
|
.on_change(move |open, _, cx| {
|
||||||
|
gallery.update(cx, |gallery, cx| {
|
||||||
|
gallery.popover_open = open;
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.trigger(|_, _| {
|
||||||
|
Button::new("gallery-popover-trigger")
|
||||||
|
.label("Options")
|
||||||
|
.variant(ButtonVariant::Secondary)
|
||||||
|
.into_any_element()
|
||||||
|
})
|
||||||
|
.content(move |_, _| {
|
||||||
|
v_flex()
|
||||||
|
.gap_1()
|
||||||
|
.w(px(240.))
|
||||||
|
.p_2()
|
||||||
|
.child(section_label("appearance", colors))
|
||||||
|
.child(
|
||||||
|
Checkbox::new("gallery-popover-telemetry")
|
||||||
|
.label("Enable telemetry"),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("gallery-popover-crash")
|
||||||
|
.label("Send crash reports"),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
@@ -627,6 +670,7 @@ fn main() {
|
|||||||
toggle_pressed: false,
|
toggle_pressed: false,
|
||||||
volume: 40.0,
|
volume: 40.0,
|
||||||
input_state,
|
input_state,
|
||||||
|
popover_open: false,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user