guise/feedback/
notification.rs1use gpui::prelude::*;
4use gpui::{div, px, App, ClickEvent, FontWeight, IntoElement, SharedString, Window};
5
6use crate::input::ClickHandler;
7use crate::theme::{theme, ColorName, Size};
8
9#[derive(IntoElement)]
12pub struct Notification {
13 title: Option<SharedString>,
14 message: SharedString,
15 color: ColorName,
16 icon: Option<SharedString>,
17 on_close: Option<ClickHandler>,
18}
19
20impl Notification {
21 pub fn new(message: impl Into<SharedString>) -> Self {
22 Notification {
23 title: None,
24 message: message.into(),
25 color: ColorName::Blue,
26 icon: None,
27 on_close: None,
28 }
29 }
30
31 pub fn title(mut self, title: impl Into<SharedString>) -> Self {
32 self.title = Some(title.into());
33 self
34 }
35
36 pub fn color(mut self, color: ColorName) -> Self {
37 self.color = color;
38 self
39 }
40
41 pub fn icon(mut self, icon: impl Into<SharedString>) -> Self {
42 self.icon = Some(icon.into());
43 self
44 }
45
46 pub fn on_close(
47 mut self,
48 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
49 ) -> Self {
50 self.on_close = Some(Box::new(handler));
51 self
52 }
53}
54
55impl RenderOnce for Notification {
56 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
57 let t = theme(cx);
58 let accent = t.color(self.color, t.primary_shade()).hsla();
59 let surface = t.surface().hsla();
60 let text = t.text().hsla();
61 let dimmed = t.dimmed().hsla();
62 let radius = t.radius(Size::Md);
63
64 let mut content = div().flex().flex_col().gap(px(2.0)).flex_1();
65 if let Some(title) = self.title {
66 content = content.child(
67 div()
68 .font_weight(FontWeight::BOLD)
69 .text_size(px(t.font_size(Size::Sm)))
70 .text_color(text)
71 .child(title),
72 );
73 }
74 content = content.child(
75 div()
76 .text_size(px(t.font_size(Size::Sm)))
77 .text_color(dimmed)
78 .child(self.message),
79 );
80
81 let mut row = div()
82 .flex()
83 .items_start()
84 .gap(px(12.0))
85 .w(px(360.0))
86 .p(px(t.spacing(Size::Md)))
87 .rounded(px(radius))
88 .bg(surface)
89 .border_1()
90 .border_color(t.border().hsla())
91 .shadow_md()
92 .child(div().w(px(4.0)).h(px(38.0)).rounded(px(4.0)).bg(accent));
94
95 if let Some(icon) = self.icon {
96 row = row.child(
97 div()
98 .text_size(px(t.font_size(Size::Md)))
99 .text_color(accent)
100 .child(icon),
101 );
102 }
103 row = row.child(content);
104 if let Some(handler) = self.on_close {
105 row = row.child(
106 div()
107 .id("guise-notification-close")
108 .text_color(dimmed)
109 .child(SharedString::new_static("\u{00d7}"))
110 .on_click(handler),
111 );
112 }
113 row
114 }
115}