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