split toast into alert and toast

This commit is contained in:
2026-11-01 09:20:10 +07:00
parent 9ddf8fe90f
commit 5a32401e25
10 changed files with 954 additions and 235 deletions
+114 -32
View File
@@ -6,6 +6,7 @@ use gpui::{
IntoElement, ParentElement as _, Render, SharedString, StatefulInteractiveElement as _,
Styled as _, Window, WindowBounds, WindowOptions, div, px, size,
};
use gpui_native_core::alert::{Alert, AlertSeverity, Alerts, AlertsView};
use gpui_native_core::avatar::Avatar;
use gpui_native_core::button::{Button, ButtonVariant};
use gpui_native_core::checkbox::Checkbox;
@@ -20,7 +21,7 @@ use gpui_native_core::radio::{Radio, RadioGroup};
use gpui_native_core::scroll_area::ScrollArea;
use gpui_native_core::slider::Slider;
use gpui_native_core::switch::Switch;
use gpui_native_core::toast::{Toast, ToastSeverity, Toasts, ToastsView};
use gpui_native_core::toast::{Toast, ToastAction, Toasts, ToastsView};
use gpui_native_core::toggle::Toggle;
use gpui_native_core::tooltip::Tooltip;
use gpui_native_data::list::{List, ListItem};
@@ -43,6 +44,8 @@ struct Gallery {
menu_open: bool,
dialog_open: bool,
alert_open: bool,
update_alert_dismissed: bool,
alerts: Entity<Alerts>,
toasts: Entity<Toasts>,
scroll: gpui::ScrollHandle,
list_selected: Option<usize>,
@@ -550,21 +553,113 @@ impl Render for Gallery {
v_flex()
.gap_2()
.child(section_label(
"toast · native ref — NSUserNotification stack, WinUI InfoBar, Adwaita in-app notifications",
"alert · static callout — Adwaita InfoBar, WinUI InfoBar",
colors,
))
.child(
v_flex()
.gap_2()
.child(
Alert::new("gallery-alert-update").title("Update available")
.message("Version 2.4.0 is ready to install.")
.severity(AlertSeverity::Info),
)
.when(!self.update_alert_dismissed, |section| {
section.child(
Alert::new("gallery-alert-sync")
.title("Sync failed")
.message("Will retry when you're back online.")
.severity(AlertSeverity::Danger)
.on_dismiss({
let gallery = gallery.clone();
move |cx| {
gallery.update(cx, |gallery, cx| {
gallery.update_alert_dismissed = true;
cx.notify();
});
}
}),
)
}),
),
)
.child(
v_flex()
.gap_2()
.child(section_label(
"alert stack · pushed, persistent — macOS notification stack",
colors,
))
.child(
div().flex().gap_2().children([
{
let alerts = self.alerts.clone();
Button::new("gallery-alert-push-info")
.label("Push info")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
alerts.update(cx, |alerts, cx| {
alerts.push(
Alert::new("pushed-info")
.title("Backed up")
.message("Everything is in sync.")
.severity(AlertSeverity::Info),
cx,
);
});
})
},
{
let alerts = self.alerts.clone();
Button::new("gallery-alert-push-warning")
.label("Push warning")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
alerts.update(cx, |alerts, cx| {
alerts.push(
Alert::new("pushed-warning")
.title("Storage almost full")
.message("1.2 GB remaining on this device.")
.severity(AlertSeverity::Warning),
cx,
);
});
})
},
{
let alerts = self.alerts.clone();
Button::new("gallery-alert-clear")
.label("Clear all")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
alerts.update(cx, |alerts, cx| alerts.clear(cx));
})
},
]),
),
)
.child(
v_flex()
.gap_2()
.child(section_label(
"toast · temporary message, one at a time — Adwaita Toast, macOS banner",
colors,
))
.child(
div().flex().gap_2().children([
{
let toasts = self.toasts.clone();
Button::new("gallery-toast-info")
.label("Info")
Button::new("gallery-toast-undo")
.label("Deleted (with undo)")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
toasts.update(cx, |toasts, cx| {
toasts.push(
Toast::new("New version available")
.message("Reload to update to 2.4.0."),
Toast::new("Draft deleted")
.action(ToastAction::new("Undo", |cx| {
// A real app restores the draft here.
let _ = cx;
})),
cx,
);
});
@@ -572,16 +667,14 @@ impl Render for Gallery {
},
{
let toasts = self.toasts.clone();
Button::new("gallery-toast-success")
.label("Success")
Button::new("gallery-toast-saved")
.label("Saved (with icon)")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
toasts.update(cx, |toasts, cx| {
toasts.push(
Toast::new("Workspace saved")
.message("All changes written to disk.")
.severity(ToastSeverity::Success)
.no_icon(),
.icon(IconRole::Check),
cx,
);
});
@@ -589,31 +682,14 @@ impl Render for Gallery {
},
{
let toasts = self.toasts.clone();
Button::new("gallery-toast-warning")
.label("Warning")
Button::new("gallery-toast-connection")
.label("Connection lost (sticky)")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
toasts.update(cx, |toasts, cx| {
toasts.push(
Toast::new("Disk almost full")
.message("1.2 GB remaining.")
.severity(ToastSeverity::Warning),
cx,
);
});
})
},
{
let toasts = self.toasts.clone();
Button::new("gallery-toast-danger")
.label("Danger (sticky)")
.variant(ButtonVariant::Destructive)
.on_click(move |_, _, cx| {
toasts.update(cx, |toasts, cx| {
toasts.push(
Toast::new("Sync failed")
.message("Will retry when online.")
.severity(ToastSeverity::Danger)
Toast::new("Connection lost")
.icon(IconRole::Warning)
.duration(Duration::ZERO),
cx,
);
@@ -1081,6 +1157,7 @@ impl Render for Gallery {
)
.child(dialog)
.child(alert)
.child(AlertsView::new("gallery-alerts", self.alerts.clone()))
.child(ToastsView::new("gallery-toasts", self.toasts.clone()))
}
}
@@ -1162,9 +1239,12 @@ fn main() {
})
.detach();
let toasts = cx.new(|_| Toasts::default());
let alerts = cx.new(|_| Alerts::default());
cx.new(|cx| {
// Toast pushes and dismissals repaint the stack.
cx.observe(&toasts, |_, _, cx| cx.notify()).detach();
// Alert pushes and dismissals repaint it.
cx.observe(&alerts, |_, _, cx| cx.notify()).detach();
Gallery {
button_clicks: 0,
checkbox_checked: false,
@@ -1177,6 +1257,8 @@ fn main() {
menu_open: false,
dialog_open: false,
alert_open: false,
update_alert_dismissed: false,
alerts,
toasts,
scroll: gpui::ScrollHandle::new(),
list_selected: None,