forked from reya/gpui-native-kit
add toast and alert overlays to the shell
This commit is contained in:
@@ -63,7 +63,7 @@ badge = []
|
|||||||
input = ["button"]
|
input = ["button"]
|
||||||
clipboard = ["button"]
|
clipboard = ["button"]
|
||||||
popover = []
|
popover = []
|
||||||
scroll_area = []
|
scroll_area = ["scrollbar"]
|
||||||
scrollbar = ["scroll_area"]
|
scrollbar = ["scroll_area"]
|
||||||
segmented = []
|
segmented = []
|
||||||
separator = []
|
separator = []
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ impl RenderOnce for AlertsView {
|
|||||||
div()
|
div()
|
||||||
.relative()
|
.relative()
|
||||||
.w_full()
|
.w_full()
|
||||||
|
.debug_selector(|| "alert-entry".to_string())
|
||||||
.child(entry.alert.clone())
|
.child(entry.alert.clone())
|
||||||
.with_animation(
|
.with_animation(
|
||||||
("alert-enter", id),
|
("alert-enter", id),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use crate::common::v_flex;
|
|||||||
pub type ChangeHandler = Rc<dyn Fn(bool, &mut Window, &mut App)>;
|
pub type ChangeHandler = Rc<dyn Fn(bool, &mut Window, &mut App)>;
|
||||||
type ContentFn = Box<dyn Fn(&mut Window, &mut App) -> AnyElement>;
|
type ContentFn = Box<dyn Fn(&mut Window, &mut App) -> AnyElement>;
|
||||||
type ActionsFn = Box<dyn Fn(&mut Window, &mut App) -> Vec<AnyElement>>;
|
type ActionsFn = Box<dyn Fn(&mut Window, &mut App) -> Vec<AnyElement>>;
|
||||||
|
|
||||||
/// A centred panel over a dim scrim: the platform's modal.
|
/// A centred panel over a dim scrim: the platform's modal.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct Dialog {
|
pub struct Dialog {
|
||||||
|
|||||||
@@ -275,6 +275,7 @@ fn pill(entry: &ToastEntry, toasts: &Entity<Toasts>, cx: &App) -> gpui::Stateful
|
|||||||
|
|
||||||
div()
|
div()
|
||||||
.id(("toast", id))
|
.id(("toast", id))
|
||||||
|
.debug_selector(|| "toast-pill".to_string())
|
||||||
.max_w(px(480.))
|
.max_w(px(480.))
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ gpui = { workspace = true, features = ["test-support"] }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["full"]
|
default = ["full"]
|
||||||
full = ["dock", "resize_handle", "resizable", "shell", "window_controls"]
|
full = ["dock", "resize_handle", "resizable", "shell", "window_controls", "toast", "alert"]
|
||||||
dock = [
|
dock = [
|
||||||
"resize_handle",
|
"resize_handle",
|
||||||
"dep:gpui-native-core",
|
"dep:gpui-native-core",
|
||||||
@@ -36,4 +36,6 @@ shell = [
|
|||||||
"dep:gpui-native-data",
|
"dep:gpui-native-data",
|
||||||
"dep:gpui-native-icons",
|
"dep:gpui-native-icons",
|
||||||
]
|
]
|
||||||
|
toast = ["shell", "gpui-native-core/toast"]
|
||||||
|
alert = ["shell", "gpui-native-core/alert"]
|
||||||
window_controls = ["dep:gpui-native-icons"]
|
window_controls = ["dep:gpui-native-icons"]
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ use gpui::{
|
|||||||
AnyElement, App, AppContext as _, Context, ElementId, Entity, InteractiveElement as _,
|
AnyElement, App, AppContext as _, Context, ElementId, Entity, InteractiveElement as _,
|
||||||
IntoElement, ParentElement as _, Pixels, RenderOnce, Styled as _, Window, div, px,
|
IntoElement, ParentElement as _, Pixels, RenderOnce, Styled as _, Window, div, px,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
use gpui_native_core::alert::{Alert, Alerts, AlertsView};
|
||||||
use gpui_native_core::button::{Button, ButtonVariant};
|
use gpui_native_core::button::{Button, ButtonVariant};
|
||||||
use gpui_native_core::common::{Sizable as _, h_flex, v_flex};
|
use gpui_native_core::common::{Sizable as _, h_flex, v_flex};
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
use gpui_native_core::toast::{Toast, Toasts, ToastsView};
|
||||||
use gpui_native_data::sidebar::Sidebar;
|
use gpui_native_data::sidebar::Sidebar;
|
||||||
use gpui_native_icons::IconRole;
|
use gpui_native_icons::IconRole;
|
||||||
use gpui_native_theme::{ActiveTheme as _, Size};
|
use gpui_native_theme::{ActiveTheme as _, Size};
|
||||||
@@ -29,16 +33,24 @@ pub struct LayoutState {
|
|||||||
right_visible: bool,
|
right_visible: bool,
|
||||||
left_width: Pixels,
|
left_width: Pixels,
|
||||||
right_width: Pixels,
|
right_width: Pixels,
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
toasts: Entity<Toasts>,
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
alerts: Entity<Alerts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutState {
|
impl LayoutState {
|
||||||
/// Creates the state: left sidebar visible, right sidebar hidden.
|
/// Creates the state: left sidebar visible, right sidebar hidden.
|
||||||
pub fn new(cx: &mut App) -> Entity<Self> {
|
pub fn new(cx: &mut App) -> Entity<Self> {
|
||||||
cx.new(|_| Self {
|
cx.new(|cx| Self {
|
||||||
left_visible: true,
|
left_visible: true,
|
||||||
right_visible: false,
|
right_visible: false,
|
||||||
left_width: px(DEFAULT_SIDEBAR_WIDTH),
|
left_width: px(DEFAULT_SIDEBAR_WIDTH),
|
||||||
right_width: px(DEFAULT_SIDEBAR_WIDTH),
|
right_width: px(DEFAULT_SIDEBAR_WIDTH),
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
toasts: cx.new(|_| Toasts::default()),
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
alerts: cx.new(|_| Alerts::default()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +103,42 @@ impl LayoutState {
|
|||||||
(self.right_width - delta).clamp(px(MIN_SIDEBAR_WIDTH), px(MAX_SIDEBAR_WIDTH));
|
(self.right_width - delta).clamp(px(MIN_SIDEBAR_WIDTH), px(MAX_SIDEBAR_WIDTH));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Raises a toast in the shell's overlay. Returns its id.
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
pub fn push_toast(&mut self, toast: Toast, cx: &mut Context<Self>) -> usize {
|
||||||
|
self.toasts.update(cx, |toasts, cx| toasts.push(toast, cx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dismisses one toast by id.
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
pub fn dismiss_toast(&mut self, id: usize, cx: &mut Context<Self>) {
|
||||||
|
self.toasts.update(cx, |toasts, cx| toasts.dismiss(id, cx));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dismisses the toast on screen.
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
pub fn clear_toasts(&mut self, cx: &mut Context<Self>) {
|
||||||
|
self.toasts.update(cx, |toasts, cx| toasts.clear(cx));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pushes an alert onto the shell's stack. Returns its id.
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
pub fn push_alert(&mut self, alert: Alert, cx: &mut Context<Self>) -> usize {
|
||||||
|
self.alerts.update(cx, |alerts, cx| alerts.push(alert, cx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dismisses one alert by id, running its dismiss handler.
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
pub fn dismiss_alert(&mut self, id: usize, cx: &mut Context<Self>) {
|
||||||
|
self.alerts.update(cx, |alerts, cx| alerts.dismiss(id, cx));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dismisses every alert, running each entry's `on_dismiss` handler.
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
pub fn clear_alerts(&mut self, cx: &mut Context<Self>) {
|
||||||
|
self.alerts.update(cx, |alerts, cx| alerts.clear(cx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which sidebar a region or toggle belongs to.
|
/// Which sidebar a region or toggle belongs to.
|
||||||
@@ -241,8 +289,22 @@ impl RenderOnce for Shell {
|
|||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wraps the layout in a window frame.
|
// Wraps the layout in a window frame
|
||||||
frame(layout, window, cx)
|
let mut shell = frame(layout, window, cx);
|
||||||
|
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
{
|
||||||
|
let toasts = state.read(cx).toasts.clone();
|
||||||
|
shell = shell.child(ToastsView::new((id.clone(), "toasts"), toasts));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
{
|
||||||
|
let alerts = state.read(cx).alerts.clone();
|
||||||
|
shell = shell.child(AlertsView::new((id, "alerts"), alerts));
|
||||||
|
}
|
||||||
|
|
||||||
|
shell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,3 +235,88 @@ fn the_right_seam_grows_the_right_sidebar_leftwards() {
|
|||||||
let region = bounds(&mut visual, "test-right").expect("right region missing");
|
let region = bounds(&mut visual, "test-right").expect("right region missing");
|
||||||
assert_eq!(region.size.width, grown);
|
assert_eq!(region.size.width, grown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toasts and alerts live on the shell's [`LayoutState`]; pushing one must
|
||||||
|
/// show up in the rendered shell with no observing or manual overlay.
|
||||||
|
#[cfg(feature = "toast")]
|
||||||
|
mod toasts {
|
||||||
|
use super::*;
|
||||||
|
use gpui_native_core::toast::{Toast, ToastAction};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_pushed_toast_renders_in_the_shell() {
|
||||||
|
let mut cx = TestAppContext::single();
|
||||||
|
let (state, mut visual) = layout_window(&mut cx);
|
||||||
|
|
||||||
|
let id = cx.update(|cx| {
|
||||||
|
state.update(cx, |state, cx| {
|
||||||
|
state.push_toast(
|
||||||
|
Toast::new("Draft deleted").action(ToastAction::new("Undo", |_| {
|
||||||
|
// A real app restores the draft here.
|
||||||
|
})),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
// No redraw, no observation: the shell repaints its own overlay.
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert!(
|
||||||
|
bounds(&mut visual, "toast-pill").is_some(),
|
||||||
|
"the pushed toast must appear in the shell's overlay"
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.update(|cx| {
|
||||||
|
state.update(cx, |state, cx| state.dismiss_toast(id, cx));
|
||||||
|
});
|
||||||
|
cx.run_until_parked();
|
||||||
|
// The fade-out keeps the pill mounted briefly.
|
||||||
|
assert!(
|
||||||
|
bounds(&mut visual, "toast-pill").is_some(),
|
||||||
|
"the dismissed toast must stay mounted through its fade-out"
|
||||||
|
);
|
||||||
|
cx.executor().advance_clock(Duration::from_secs(2));
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert!(
|
||||||
|
bounds(&mut visual, "toast-pill").is_none(),
|
||||||
|
"the dismissed toast must leave the overlay once faded"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alert")]
|
||||||
|
mod alerts {
|
||||||
|
use super::*;
|
||||||
|
use gpui_native_core::alert::{Alert, AlertSeverity};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_pushed_alert_renders_in_the_shell() {
|
||||||
|
let mut cx = TestAppContext::single();
|
||||||
|
let (state, mut visual) = layout_window(&mut cx);
|
||||||
|
|
||||||
|
cx.update(|cx| {
|
||||||
|
state.update(cx, |state, cx| {
|
||||||
|
state.push_alert(
|
||||||
|
Alert::new("shell-alert")
|
||||||
|
.title("Backed up")
|
||||||
|
.severity(AlertSeverity::Info),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert!(
|
||||||
|
bounds(&mut visual, "alert-entry").is_some(),
|
||||||
|
"the pushed alert must appear in the shell's overlay"
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.update(|cx| {
|
||||||
|
state.update(cx, |state, cx| state.clear_alerts(cx));
|
||||||
|
});
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert!(
|
||||||
|
bounds(&mut visual, "alert-entry").is_none(),
|
||||||
|
"cleared alerts must leave the overlay"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use gpui::{
|
|||||||
SharedString, Styled as _, UniformListScrollHandle, WeakEntity, Window, WindowBounds,
|
SharedString, Styled as _, UniformListScrollHandle, WeakEntity, Window, WindowBounds,
|
||||||
WindowOptions, actions, div, list, px, size, uniform_list,
|
WindowOptions, actions, div, list, px, size, uniform_list,
|
||||||
};
|
};
|
||||||
use gpui_native_core::alert::{Alert, AlertSeverity, Alerts, AlertsView};
|
use gpui_native_core::alert::{Alert, AlertSeverity};
|
||||||
use gpui_native_core::avatar::Avatar;
|
use gpui_native_core::avatar::Avatar;
|
||||||
use gpui_native_core::badge::{Badge, BadgeVariant};
|
use gpui_native_core::badge::{Badge, BadgeVariant};
|
||||||
use gpui_native_core::button::{Button, ButtonVariant};
|
use gpui_native_core::button::{Button, ButtonVariant};
|
||||||
@@ -36,7 +36,7 @@ use gpui_native_core::slider::Slider;
|
|||||||
use gpui_native_core::spinner::{Spinner, SpinnerVariant};
|
use gpui_native_core::spinner::{Spinner, SpinnerVariant};
|
||||||
use gpui_native_core::status_dot::{StatusDot, StatusDotVariant};
|
use gpui_native_core::status_dot::{StatusDot, StatusDotVariant};
|
||||||
use gpui_native_core::switch::Switch;
|
use gpui_native_core::switch::Switch;
|
||||||
use gpui_native_core::toast::{Toast, ToastAction, Toasts, ToastsView};
|
use gpui_native_core::toast::{Toast, ToastAction};
|
||||||
use gpui_native_core::toggle::Toggle;
|
use gpui_native_core::toggle::Toggle;
|
||||||
use gpui_native_core::tooltip::Tooltip;
|
use gpui_native_core::tooltip::Tooltip;
|
||||||
use gpui_native_data::list::{List, ListItem};
|
use gpui_native_data::list::{List, ListItem};
|
||||||
@@ -217,8 +217,6 @@ fn gallery_commands() -> Vec<Command> {
|
|||||||
struct Gallery {
|
struct Gallery {
|
||||||
layout_state: Entity<LayoutState>,
|
layout_state: Entity<LayoutState>,
|
||||||
dock_state: Entity<DockState>,
|
dock_state: Entity<DockState>,
|
||||||
alerts: Entity<Alerts>,
|
|
||||||
toasts: Entity<Toasts>,
|
|
||||||
palette: Option<Entity<CommandPaletteState>>,
|
palette: Option<Entity<CommandPaletteState>>,
|
||||||
palette_runs: Vec<SharedString>,
|
palette_runs: Vec<SharedString>,
|
||||||
dialog_open: bool,
|
dialog_open: bool,
|
||||||
@@ -395,8 +393,6 @@ impl Gallery {
|
|||||||
fn register_panels(
|
fn register_panels(
|
||||||
dock: &mut DockState,
|
dock: &mut DockState,
|
||||||
layout_state: Entity<LayoutState>,
|
layout_state: Entity<LayoutState>,
|
||||||
alerts: Entity<Alerts>,
|
|
||||||
toasts: Entity<Toasts>,
|
|
||||||
palette: Entity<CommandPaletteState>,
|
palette: Entity<CommandPaletteState>,
|
||||||
gallery: WeakEntity<Self>,
|
gallery: WeakEntity<Self>,
|
||||||
cx: &mut Context<DockState>,
|
cx: &mut Context<DockState>,
|
||||||
@@ -513,20 +509,20 @@ impl Gallery {
|
|||||||
.into()
|
.into()
|
||||||
}));
|
}));
|
||||||
dock.register_panel(PanelDescriptor::new("alert", "Alert", {
|
dock.register_panel(PanelDescriptor::new("alert", "Alert", {
|
||||||
let alerts = alerts.clone();
|
let layout_state = layout_state.clone();
|
||||||
move |_, cx| {
|
move |_, cx| {
|
||||||
cx.new(|_| AlertDemo {
|
cx.new(|_| AlertDemo {
|
||||||
alerts: alerts.clone(),
|
layout_state: layout_state.clone(),
|
||||||
dismissed: false,
|
dismissed: false,
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
dock.register_panel(PanelDescriptor::new("toast", "Toast", {
|
dock.register_panel(PanelDescriptor::new("toast", "Toast", {
|
||||||
let toasts = toasts.clone();
|
let layout_state = layout_state.clone();
|
||||||
move |_, cx| {
|
move |_, cx| {
|
||||||
cx.new(|_| ToastDemo {
|
cx.new(|_| ToastDemo {
|
||||||
toasts: toasts.clone(),
|
layout_state: layout_state.clone(),
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
@@ -649,8 +645,6 @@ impl Render for Gallery {
|
|||||||
.child(dialog)
|
.child(dialog)
|
||||||
.child(alert_dialog)
|
.child(alert_dialog)
|
||||||
.when_some(self.palette.clone(), |root, palette| root.child(palette))
|
.when_some(self.palette.clone(), |root, palette| root.child(palette))
|
||||||
.child(AlertsView::new("gallery-alerts", self.alerts.clone()))
|
|
||||||
.child(ToastsView::new("gallery-toasts", self.toasts.clone()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2287,16 +2281,16 @@ impl Render for TabsDemo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct AlertDemo {
|
struct AlertDemo {
|
||||||
alerts: Entity<Alerts>,
|
layout_state: Entity<LayoutState>,
|
||||||
dismissed: bool,
|
dismissed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for AlertDemo {
|
impl Render for AlertDemo {
|
||||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
let view = cx.entity();
|
let view = cx.entity();
|
||||||
let alerts_info = self.alerts.clone();
|
let alerts_info = self.layout_state.clone();
|
||||||
let alerts_warning = self.alerts.clone();
|
let alerts_warning = self.layout_state.clone();
|
||||||
let alerts_clear = self.alerts.clone();
|
let alerts_clear = self.layout_state.clone();
|
||||||
let colors = cx.theme().colors;
|
let colors = cx.theme().colors;
|
||||||
|
|
||||||
ScrollArea::new("alert-demo").size_full().p_4().child(
|
ScrollArea::new("alert-demo").size_full().p_4().child(
|
||||||
@@ -2339,8 +2333,8 @@ impl Render for AlertDemo {
|
|||||||
.label("Push info")
|
.label("Push info")
|
||||||
.variant(ButtonVariant::Secondary)
|
.variant(ButtonVariant::Secondary)
|
||||||
.on_click(move |_, _, cx| {
|
.on_click(move |_, _, cx| {
|
||||||
alerts_info.update(cx, |alerts, cx| {
|
alerts_info.update(cx, |state, cx| {
|
||||||
alerts.push(
|
state.push_alert(
|
||||||
Alert::new("alert-demo-pushed-info")
|
Alert::new("alert-demo-pushed-info")
|
||||||
.title("Backed up")
|
.title("Backed up")
|
||||||
.message("Everything is in sync.")
|
.message("Everything is in sync.")
|
||||||
@@ -2355,8 +2349,8 @@ impl Render for AlertDemo {
|
|||||||
.label("Push warning")
|
.label("Push warning")
|
||||||
.variant(ButtonVariant::Secondary)
|
.variant(ButtonVariant::Secondary)
|
||||||
.on_click(move |_, _, cx| {
|
.on_click(move |_, _, cx| {
|
||||||
alerts_warning.update(cx, |alerts, cx| {
|
alerts_warning.update(cx, |state, cx| {
|
||||||
alerts.push(
|
state.push_alert(
|
||||||
Alert::new("alert-demo-pushed-warning")
|
Alert::new("alert-demo-pushed-warning")
|
||||||
.title("Storage almost full")
|
.title("Storage almost full")
|
||||||
.message("1.2 GB remaining on this device.")
|
.message("1.2 GB remaining on this device.")
|
||||||
@@ -2371,7 +2365,7 @@ impl Render for AlertDemo {
|
|||||||
.label("Clear all")
|
.label("Clear all")
|
||||||
.variant(ButtonVariant::Secondary)
|
.variant(ButtonVariant::Secondary)
|
||||||
.on_click(move |_, _, cx| {
|
.on_click(move |_, _, cx| {
|
||||||
alerts_clear.update(cx, |alerts, cx| alerts.clear(cx));
|
alerts_clear.update(cx, |state, cx| state.clear_alerts(cx));
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
@@ -2380,14 +2374,14 @@ impl Render for AlertDemo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ToastDemo {
|
struct ToastDemo {
|
||||||
toasts: Entity<Toasts>,
|
layout_state: Entity<LayoutState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for ToastDemo {
|
impl Render for ToastDemo {
|
||||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
let toasts_undo = self.toasts.clone();
|
let toasts_undo = self.layout_state.clone();
|
||||||
let toasts_saved = self.toasts.clone();
|
let toasts_saved = self.layout_state.clone();
|
||||||
let toasts_connection = self.toasts.clone();
|
let toasts_connection = self.layout_state.clone();
|
||||||
let colors = cx.theme().colors;
|
let colors = cx.theme().colors;
|
||||||
|
|
||||||
ScrollArea::new("toast-demo")
|
ScrollArea::new("toast-demo")
|
||||||
@@ -2404,8 +2398,8 @@ impl Render for ToastDemo {
|
|||||||
.label("Deleted (with undo)")
|
.label("Deleted (with undo)")
|
||||||
.variant(ButtonVariant::Secondary)
|
.variant(ButtonVariant::Secondary)
|
||||||
.on_click(move |_, _, cx| {
|
.on_click(move |_, _, cx| {
|
||||||
toasts_undo.update(cx, |toasts, cx| {
|
toasts_undo.update(cx, |state, cx| {
|
||||||
toasts.push(
|
state.push_toast(
|
||||||
Toast::new("Draft deleted").action(ToastAction::new(
|
Toast::new("Draft deleted").action(ToastAction::new(
|
||||||
"Undo",
|
"Undo",
|
||||||
|cx| {
|
|cx| {
|
||||||
@@ -2423,8 +2417,8 @@ impl Render for ToastDemo {
|
|||||||
.label("Saved (with icon)")
|
.label("Saved (with icon)")
|
||||||
.variant(ButtonVariant::Secondary)
|
.variant(ButtonVariant::Secondary)
|
||||||
.on_click(move |_, _, cx| {
|
.on_click(move |_, _, cx| {
|
||||||
toasts_saved.update(cx, |toasts, cx| {
|
toasts_saved.update(cx, |state, cx| {
|
||||||
toasts.push(
|
state.push_toast(
|
||||||
Toast::new("Workspace saved").icon(IconRole::Check),
|
Toast::new("Workspace saved").icon(IconRole::Check),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
@@ -2436,8 +2430,8 @@ impl Render for ToastDemo {
|
|||||||
.label("Connection lost (sticky)")
|
.label("Connection lost (sticky)")
|
||||||
.variant(ButtonVariant::Secondary)
|
.variant(ButtonVariant::Secondary)
|
||||||
.on_click(move |_, _, cx| {
|
.on_click(move |_, _, cx| {
|
||||||
toasts_connection.update(cx, |toasts, cx| {
|
toasts_connection.update(cx, |state, cx| {
|
||||||
toasts.push(
|
state.push_toast(
|
||||||
Toast::new("Connection lost")
|
Toast::new("Connection lost")
|
||||||
.icon(IconRole::Warning)
|
.icon(IconRole::Warning)
|
||||||
.duration(Duration::ZERO),
|
.duration(Duration::ZERO),
|
||||||
@@ -4025,24 +4019,14 @@ fn main() {
|
|||||||
cx.refresh_windows();
|
cx.refresh_windows();
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
let toasts = cx.new(|_| Toasts::default());
|
let gallery = cx.new(|_| Gallery {
|
||||||
let alerts = cx.new(|_| Alerts::default());
|
layout_state: layout_state.clone(),
|
||||||
let gallery = cx.new(|cx| {
|
dock_state: dock_state.clone(),
|
||||||
// Toast pushes and dismissals repaint the stack.
|
palette: None,
|
||||||
cx.observe(&toasts, |_, _, cx| cx.notify()).detach();
|
palette_runs: Vec::new(),
|
||||||
// Alert pushes and dismissals repaint it.
|
dialog_open: false,
|
||||||
cx.observe(&alerts, |_, _, cx| cx.notify()).detach();
|
alert_open: false,
|
||||||
Gallery {
|
sidebar_transparent: true,
|
||||||
layout_state: layout_state.clone(),
|
|
||||||
dock_state: dock_state.clone(),
|
|
||||||
alerts: alerts.clone(),
|
|
||||||
toasts: toasts.clone(),
|
|
||||||
palette: None,
|
|
||||||
palette_runs: Vec::new(),
|
|
||||||
dialog_open: false,
|
|
||||||
alert_open: false,
|
|
||||||
sidebar_transparent: true,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
let palette = cx.new(|cx| {
|
let palette = cx.new(|cx| {
|
||||||
let matcher = |query: &str, commands: &[Command]| {
|
let matcher = |query: &str, commands: &[Command]| {
|
||||||
@@ -4076,8 +4060,6 @@ fn main() {
|
|||||||
Gallery::register_panels(
|
Gallery::register_panels(
|
||||||
dock,
|
dock,
|
||||||
layout_state.clone(),
|
layout_state.clone(),
|
||||||
alerts.clone(),
|
|
||||||
toasts.clone(),
|
|
||||||
palette.clone(),
|
palette.clone(),
|
||||||
gallery.downgrade(),
|
gallery.downgrade(),
|
||||||
cx,
|
cx,
|
||||||
|
|||||||
Reference in New Issue
Block a user