1use gpui::*;
2use smallvec::SmallVec;
3
4use crate::{h_flex, IconButton, IconButtonShape, IconName, Label, LabelCommon, LabelSize};
5
6#[derive(IntoElement)]
7pub struct ModalHeader {
8 id: ElementId,
9 children: SmallVec<[AnyElement; 2]>,
10}
11
12impl ModalHeader {
13 pub fn new(id: impl Into<ElementId>) -> Self {
14 Self {
15 id: id.into(),
16 children: SmallVec::new(),
17 }
18 }
19}
20
21impl ParentElement for ModalHeader {
22 fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
23 self.children.extend(elements)
24 }
25}
26
27impl RenderOnce for ModalHeader {
28 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
29 h_flex()
30 .id(self.id)
31 .w_full()
32 .px_2()
33 .py_1p5()
34 .child(div().flex_1().children(self.children))
35 .justify_between()
36 .child(IconButton::new("dismiss", IconName::Close).shape(IconButtonShape::Square))
37 }
38}
39
40#[derive(IntoElement)]
41pub struct ModalContent {
42 children: SmallVec<[AnyElement; 2]>,
43}
44
45impl ModalContent {
46 pub fn new() -> Self {
47 Self {
48 children: SmallVec::new(),
49 }
50 }
51}
52
53impl ParentElement for ModalContent {
54 fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
55 self.children.extend(elements)
56 }
57}
58
59impl RenderOnce for ModalContent {
60 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
61 h_flex().w_full().px_2().py_1p5().children(self.children)
62 }
63}
64
65#[derive(IntoElement)]
66pub struct ModalRow {
67 children: SmallVec<[AnyElement; 2]>,
68}
69
70impl ModalRow {
71 pub fn new() -> Self {
72 Self {
73 children: SmallVec::new(),
74 }
75 }
76}
77
78impl ParentElement for ModalRow {
79 fn extend(&mut self, elements: impl Iterator<Item = AnyElement>) {
80 self.children.extend(elements)
81 }
82}
83
84impl RenderOnce for ModalRow {
85 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
86 h_flex().w_full().px_2().py_1().children(self.children)
87 }
88}
89
90#[derive(IntoElement)]
91pub struct SectionHeader {
92 /// The label of the header.
93 label: SharedString,
94 /// A slot for content that appears after the label, usually on the other side of the header.
95 /// This might be a button, a disclosure arrow, a face pile, etc.
96 end_slot: Option<AnyElement>,
97}
98
99impl SectionHeader {
100 pub fn new(label: impl Into<SharedString>) -> Self {
101 Self {
102 label: label.into(),
103 end_slot: None,
104 }
105 }
106
107 pub fn end_slot<E: IntoElement>(mut self, end_slot: impl Into<Option<E>>) -> Self {
108 self.end_slot = end_slot.into().map(IntoElement::into_any_element);
109 self
110 }
111}
112
113impl RenderOnce for SectionHeader {
114 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
115 h_flex().id(self.label.clone()).w_full().child(
116 div()
117 .h_7()
118 .flex()
119 .items_center()
120 .justify_between()
121 .w_full()
122 .gap_1()
123 .child(
124 div().flex_1().child(
125 Label::new(self.label.clone())
126 .size(LabelSize::Large)
127 .into_element(),
128 ),
129 )
130 .child(h_flex().children(self.end_slot)),
131 )
132 }
133}