notification.rs

 1use std::marker::PhantomData;
 2
 3use gpui3::{Element, ParentElement, Styled, ViewContext};
 4
 5use crate::{
 6    h_stack, v_stack, Button, Icon, IconButton, IconElement, Label, ThemeColor, Toast, ToastOrigin,
 7};
 8
 9/// Notification toasts are used to display a message
10/// that requires them to take action.
11///
12/// You must provide a primary action for the user to take.
13///
14/// To simply convey information, use a `StatusToast`.
15#[derive(Element)]
16pub struct NotificationToast<S: 'static + Send + Sync + Clone> {
17    state_type: PhantomData<S>,
18    left_icon: Option<Icon>,
19    title: String,
20    message: String,
21    primary_action: Option<Button<S>>,
22    secondary_action: Option<Button<S>>,
23}
24
25impl<S: 'static + Send + Sync + Clone> NotificationToast<S> {
26    pub fn new(
27        // TODO: use a `SharedString` here
28        title: impl Into<String>,
29        message: impl Into<String>,
30        primary_action: Button<S>,
31    ) -> Self {
32        Self {
33            state_type: PhantomData,
34            left_icon: None,
35            title: title.into(),
36            message: message.into(),
37            primary_action: Some(primary_action),
38            secondary_action: None,
39        }
40    }
41
42    pub fn left_icon(mut self, icon: Icon) -> Self {
43        self.left_icon = Some(icon);
44        self
45    }
46
47    pub fn secondary_action(mut self, action: Button<S>) -> Self {
48        self.secondary_action = Some(action);
49        self
50    }
51
52    fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
53        let color = ThemeColor::new(cx);
54
55        let notification = h_stack()
56            .min_w_64()
57            .max_w_96()
58            .gap_1()
59            .items_start()
60            .p_1()
61            .children(self.left_icon.map(|i| IconElement::new(i)))
62            .child(
63                v_stack()
64                    .flex_1()
65                    .w_full()
66                    .gap_1()
67                    .child(
68                        h_stack()
69                            .justify_between()
70                            .child(Label::new(self.title.clone()))
71                            .child(IconButton::new(Icon::Close).color(crate::IconColor::Muted)),
72                    )
73                    .child(
74                        v_stack()
75                            .overflow_hidden_x()
76                            .gap_1()
77                            .child(Label::new(self.message.clone()))
78                            .child(
79                                h_stack()
80                                    .gap_1()
81                                    .justify_end()
82                                    .children(self.secondary_action.take())
83                                    .children(self.primary_action.take()),
84                            ),
85                    ),
86            );
87
88        Toast::new(ToastOrigin::BottomRight).child(notification)
89    }
90}