1use gpui::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 v_stack()
43 .id(self.id.clone())
44 .w_96()
45 // .rounded_xl()
46 .bg(cx.theme().colors().background)
47 .border()
48 .border_color(cx.theme().colors().border)
49 .shadow_2xl()
50 .child(
51 h_stack()
52 .justify_between()
53 .p_1()
54 .border_b()
55 .border_color(cx.theme().colors().border)
56 .child(div().children(self.title.clone().map(|t| Label::new(t))))
57 .child(IconButton::new("close", Icon::Close)),
58 )
59 .child(v_stack().p_1().children(self.children))
60 .when(
61 self.primary_action.is_some() || self.secondary_action.is_some(),
62 |this| {
63 this.child(
64 h_stack()
65 .border_t()
66 .border_color(cx.theme().colors().border)
67 .p_1()
68 .justify_end()
69 .children(self.secondary_action)
70 .children(self.primary_action),
71 )
72 },
73 )
74 }
75}
76
77impl<V: 'static> ParentComponent<V> for Modal<V> {
78 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
79 &mut self.children
80 }
81}