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}