feat: host toasts and alerts in the shell

This commit is contained in:
2026-11-10 18:33:56 +07:00
parent a6b6cfd5a4
commit 67f34ead74
7 changed files with 182 additions and 60 deletions
+33 -56
View File
@@ -7,7 +7,7 @@ use gpui::{
SharedString, Styled as _, UniformListScrollHandle, WeakEntity, Window, WindowBounds,
WindowOptions, actions, div, list, px, rems, 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::badge::{Badge, BadgeVariant};
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::status_dot::{StatusDot, StatusDotVariant};
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::tooltip::Tooltip;
use gpui_native_data::list::{List, ListItem};
@@ -219,15 +219,12 @@ fn gallery_commands() -> Vec<Command> {
struct Gallery {
layout_state: Entity<LayoutState>,
dock_state: Entity<DockState>,
alerts: Entity<Alerts>,
toasts: Entity<Toasts>,
palette: Option<Entity<CommandPaletteState>>,
palette_runs: Vec<SharedString>,
dialog_open: bool,
alert_open: bool,
/// Whether the app sidebar paints the window's native material.
sidebar_transparent: bool,
_subscriptions: Vec<gpui::Subscription>,
}
impl Gallery {
@@ -402,8 +399,6 @@ impl Gallery {
fn register_panels(
dock: &mut DockState,
layout_state: Entity<LayoutState>,
alerts: Entity<Alerts>,
toasts: Entity<Toasts>,
palette: Entity<CommandPaletteState>,
gallery: WeakEntity<Self>,
cx: &mut Context<DockState>,
@@ -521,20 +516,20 @@ impl Gallery {
.into()
}));
dock.register_panel(PanelDescriptor::new("alert", "Alert", {
let alerts = alerts.clone();
let layout_state = layout_state.clone();
move |_, cx| {
cx.new(|_| AlertDemo {
alerts: alerts.clone(),
layout_state: layout_state.clone(),
dismissed: false,
})
.into()
}
}));
dock.register_panel(PanelDescriptor::new("toast", "Toast", {
let toasts = toasts.clone();
let layout_state = layout_state.clone();
move |_, cx| {
cx.new(|_| ToastDemo {
toasts: toasts.clone(),
layout_state: layout_state.clone(),
})
.into()
}
@@ -665,8 +660,6 @@ impl Render for Gallery {
.child(dialog)
.child(alert_dialog)
.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()))
}
}
@@ -2344,16 +2337,16 @@ impl Render for TabsDemo {
}
struct AlertDemo {
alerts: Entity<Alerts>,
layout_state: Entity<LayoutState>,
dismissed: bool,
}
impl Render for AlertDemo {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let view = cx.entity();
let alerts_info = self.alerts.clone();
let alerts_warning = self.alerts.clone();
let alerts_clear = self.alerts.clone();
let alerts_info = self.layout_state.clone();
let alerts_warning = self.layout_state.clone();
let alerts_clear = self.layout_state.clone();
let colors = cx.theme().colors;
ScrollArea::new("alert-demo").size_full().child(
@@ -2396,8 +2389,8 @@ impl Render for AlertDemo {
.label("Push info")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
alerts_info.update(cx, |alerts, cx| {
alerts.push(
alerts_info.update(cx, |state, cx| {
state.push_alert(
Alert::new("alert-demo-pushed-info")
.title("Backed up")
.message("Everything is in sync.")
@@ -2412,8 +2405,8 @@ impl Render for AlertDemo {
.label("Push warning")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
alerts_warning.update(cx, |alerts, cx| {
alerts.push(
alerts_warning.update(cx, |state, cx| {
state.push_alert(
Alert::new("alert-demo-pushed-warning")
.title("Storage almost full")
.message("1.2 GB remaining on this device.")
@@ -2428,7 +2421,7 @@ impl Render for AlertDemo {
.label("Clear all")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
alerts_clear.update(cx, |alerts, cx| alerts.clear(cx));
alerts_clear.update(cx, |state, cx| state.clear_alerts(cx));
}),
),
)),
@@ -2437,14 +2430,14 @@ impl Render for AlertDemo {
}
struct ToastDemo {
toasts: Entity<Toasts>,
layout_state: Entity<LayoutState>,
}
impl Render for ToastDemo {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let toasts_undo = self.toasts.clone();
let toasts_saved = self.toasts.clone();
let toasts_connection = self.toasts.clone();
let toasts_undo = self.layout_state.clone();
let toasts_saved = self.layout_state.clone();
let toasts_connection = self.layout_state.clone();
let colors = cx.theme().colors;
ScrollArea::new("toast-demo")
@@ -2460,8 +2453,8 @@ impl Render for ToastDemo {
.label("Deleted (with undo)")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
toasts_undo.update(cx, |toasts, cx| {
toasts.push(
toasts_undo.update(cx, |state, cx| {
state.push_toast(
Toast::new("Draft deleted").action(ToastAction::new(
"Undo",
|cx| {
@@ -2479,8 +2472,8 @@ impl Render for ToastDemo {
.label("Saved (with icon)")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
toasts_saved.update(cx, |toasts, cx| {
toasts.push(
toasts_saved.update(cx, |state, cx| {
state.push_toast(
Toast::new("Workspace saved").icon(IconRole::Check),
cx,
);
@@ -2492,8 +2485,8 @@ impl Render for ToastDemo {
.label("Connection lost (sticky)")
.variant(ButtonVariant::Secondary)
.on_click(move |_, _, cx| {
toasts_connection.update(cx, |toasts, cx| {
toasts.push(
toasts_connection.update(cx, |state, cx| {
state.push_toast(
Toast::new("Connection lost")
.icon(IconRole::Warning)
.duration(Duration::ZERO),
@@ -4157,28 +4150,14 @@ fn main() {
cx.refresh_windows();
})
.detach();
let toasts = cx.new(|_| Toasts::default());
let alerts = cx.new(|_| Alerts::default());
let gallery = cx.new(|cx| {
Gallery {
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,
_subscriptions: vec![
// Toast pushes and dismissals repaint the stack.
cx.observe(&toasts, |_, _, cx| cx.notify()),
// Alert pushes and dismissals repaint it.
cx.observe(&alerts, |_, _, cx| cx.notify()),
],
}
let gallery = cx.new(|_| Gallery {
layout_state: layout_state.clone(),
dock_state: dock_state.clone(),
palette: None,
palette_runs: Vec::new(),
dialog_open: false,
alert_open: false,
sidebar_transparent: true,
});
let palette = cx.new(|cx| {
@@ -4216,8 +4195,6 @@ fn main() {
Gallery::register_panels(
dock,
layout_state.clone(),
alerts.clone(),
toasts.clone(),
palette.clone(),
gallery.downgrade(),
cx,