1use gpui::{AnyElement, Div, RenderOnce};
2use smallvec::SmallVec;
3
4use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label};
5
6#[derive(RenderOnce)]
7pub struct Modal {
8 id: ElementId,
9 title: Option<SharedString>,
10 primary_action: Option<Button>,
11 secondary_action: Option<Button>,
12 children: SmallVec<[AnyElement; 2]>,
13}
14
15impl Component for Modal {
16 type Rendered = gpui::Stateful<Div>;
17
18 fn render(self, cx: &mut WindowContext) -> Self::Rendered {
19 v_stack()
20 .id(self.id.clone())
21 .w_96()
22 // .rounded_xl()
23 .bg(cx.theme().colors().background)
24 .border()
25 .border_color(cx.theme().colors().border)
26 .shadow_2xl()
27 .child(
28 h_stack()
29 .justify_between()
30 .p_1()
31 .border_b()
32 .border_color(cx.theme().colors().border)
33 .child(div().children(self.title.clone().map(|t| Label::new(t))))
34 .child(IconButton::new("close", Icon::Close)),
35 )
36 .child(v_stack().p_1().children(self.children))
37 .when(
38 self.primary_action.is_some() || self.secondary_action.is_some(),
39 |this| {
40 this.child(
41 h_stack()
42 .border_t()
43 .border_color(cx.theme().colors().border)
44 .p_1()
45 .justify_end()
46 .children(self.secondary_action)
47 .children(self.primary_action),
48 )
49 },
50 )
51 }
52}
53
54impl Modal {
55 pub fn new(id: impl Into<ElementId>) -> Self {
56 Self {
57 id: id.into(),
58 title: None,
59 primary_action: None,
60 secondary_action: None,
61 children: SmallVec::new(),
62 }
63 }
64
65 pub fn title(mut self, title: impl Into<SharedString>) -> Self {
66 self.title = Some(title.into());
67 self
68 }
69
70 pub fn primary_action(mut self, action: Button) -> Self {
71 self.primary_action = Some(action);
72 self
73 }
74
75 pub fn secondary_action(mut self, action: Button) -> Self {
76 self.secondary_action = Some(action);
77 self
78 }
79}
80
81impl ParentElement for Modal {
82 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
83 &mut self.children
84 }
85}