Add notification toast component and remove ToastVariant from toast.rs

Nate Butler created

Change summary

crates/ui2/src/components.rs              |  2 
crates/ui2/src/components/notification.rs | 63 +++++++++++++++++++++++++
crates/ui2/src/components/toast.rs        |  7 --
crates/ui2/src/elements/icon.rs           |  6 +
4 files changed, 70 insertions(+), 8 deletions(-)

Detailed changes

crates/ui2/src/components.rs 🔗

@@ -12,6 +12,7 @@ mod keybinding;
 mod language_selector;
 mod list;
 mod multi_buffer;
+mod notification;
 mod palette;
 mod panel;
 mod panes;
@@ -43,6 +44,7 @@ pub use keybinding::*;
 pub use language_selector::*;
 pub use list::*;
 pub use multi_buffer::*;
+pub use notification::*;
 pub use palette::*;
 pub use panel::*;
 pub use panes::*;

crates/ui2/src/components/notification.rs 🔗

@@ -0,0 +1,63 @@
+use gpui3::{Element, ParentElement, StyleHelpers, ViewContext};
+
+use crate::{
+    h_stack, v_stack, Button, Icon, IconButton, IconElement, Label, ThemeColor, Toast, ToastOrigin,
+};
+
+/// Notification toasts are used to display a message
+/// that requires them to take action.
+///
+/// To simply convey information, use a Status.
+pub struct NotificationToast<S: 'static + Send + Sync + Clone> {
+    left_icon: Option<Icon>,
+    title: String,
+    message: String,
+    actions: Vec<Button<S>>,
+}
+
+impl<S: 'static + Send + Sync + Clone> NotificationToast<S> {
+    pub fn new(
+        title: impl Into<String>,
+        message: impl Into<String>,
+        actions: Vec<Button<S>>,
+    ) -> Self {
+        Self {
+            left_icon: None,
+            title: title.into(),
+            message: message.into(),
+            actions,
+        }
+    }
+
+    pub fn set_left_icon(mut self, icon: Icon) -> Self {
+        self.left_icon = Some(icon);
+        self
+    }
+
+    fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
+        let color = ThemeColor::new(cx);
+
+        let notification = h_stack()
+            .gap_1()
+            .items_start()
+            .children(self.left_icon.map(|i| IconElement::new(i)))
+            .child(
+                v_stack()
+                    .child(
+                        h_stack()
+                            .justify_between()
+                            .p_1()
+                            .child(Label::new(self.title))
+                            .child(IconButton::new(Icon::Close)),
+                    )
+                    .child(
+                        h_stack()
+                            .p_1()
+                            .child(Label::new(self.message))
+                            .children(self.actions.iter().map(|action| action)),
+                    ),
+            );
+
+        Toast::new(ToastOrigin::BottomRight)
+    }
+}

crates/ui2/src/components/toast.rs 🔗

@@ -10,13 +10,6 @@ pub enum ToastOrigin {
     BottomRight,
 }
 
-#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
-pub enum ToastVariant {
-    #[default]
-    Toast,
-    Status,
-}
-
 /// A toast is a small, temporary window that appears to show a message to the user
 /// or indicate a required action.
 ///

crates/ui2/src/elements/icon.rs 🔗

@@ -206,7 +206,11 @@ mod stories {
             }
         }
 
-        fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
+        fn render(
+            &mut self,
+            _view: &mut S,
+            cx: &mut ViewContext<S>,
+        ) -> impl Element<ViewState = S> {
             let icons = Icon::iter();
 
             Story::container(cx)