1use gpui::{prelude::FluentBuilder, *};
2use smallvec::SmallVec;
3
4use crate::{
5 h_flex, Clickable, IconButton, IconButtonShape, IconName, Label, LabelCommon, LabelSize,
6 Spacing,
7};
8
9#[derive(IntoElement)]
10pub struct ModalHeader {
11 id: ElementId,
12 children: SmallVec<[AnyElement; 2]>,
13 show_dismiss_button: bool,
14 show_back_button: bool,
15}
16
17impl ModalHeader {
18 pub fn new(id: impl Into<ElementId>) -> Self {
19 Self {
20 id: id.into(),
21 children: SmallVec::new(),
22 show_dismiss_button: false,
23 show_back_button: false,
24 }
25 }
26
27 pub fn show_dismiss_button(mut self, show: bool) -> Self {
28 self.show_dismiss_button = show;
29 self
30 }
31
32 pub fn show_back_button(mut self, show: bool) -> Self {
33 self.show_back_button = show;
34 self
35 }
36}
37
38impl ParentElement for ModalHeader {
39 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
40 self.children.extend(elements)
41 }
42}
43
44impl RenderOnce for ModalHeader {
45 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
46 h_flex()
47 .id(self.id)
48 .w_full()
49 .px(Spacing::Large.rems(cx))
50 .py_1p5()
51 .when(self.show_back_button, |this| {
52 this.child(
53 div().pr_1().child(
54 IconButton::new("back", IconName::ArrowLeft)
55 .shape(IconButtonShape::Square)
56 .on_click(|_, cx| {
57 cx.dispatch_action(menu::Cancel.boxed_clone());
58 }),
59 ),
60 )
61 })
62 .child(div().flex_1().children(self.children))
63 .justify_between()
64 .when(self.show_dismiss_button, |this| {
65 this.child(
66 IconButton::new("dismiss", IconName::Close)
67 .shape(IconButtonShape::Square)
68 .on_click(|_, cx| {
69 cx.dispatch_action(menu::Cancel.boxed_clone());
70 }),
71 )
72 })
73 }
74}
75
76#[derive(IntoElement)]
77pub struct ModalContent {
78 children: SmallVec<[AnyElement; 2]>,
79}
80
81impl ModalContent {
82 pub fn new() -> Self {
83 Self {
84 children: SmallVec::new(),
85 }
86 }
87}
88
89impl ParentElement for ModalContent {
90 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
91 self.children.extend(elements)
92 }
93}
94
95impl RenderOnce for ModalContent {
96 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
97 h_flex().w_full().px_2().py_1p5().children(self.children)
98 }
99}
100
101#[derive(IntoElement)]
102pub struct ModalRow {
103 children: SmallVec<[AnyElement; 2]>,
104}
105
106impl ModalRow {
107 pub fn new() -> Self {
108 Self {
109 children: SmallVec::new(),
110 }
111 }
112}
113
114impl ParentElement for ModalRow {
115 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
116 self.children.extend(elements)
117 }
118}
119
120impl RenderOnce for ModalRow {
121 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
122 h_flex().w_full().px_2().py_1().children(self.children)
123 }
124}
125
126#[derive(IntoElement)]
127pub struct SectionHeader {
128 /// The label of the header.
129 label: SharedString,
130 /// A slot for content that appears after the label, usually on the other side of the header.
131 /// This might be a button, a disclosure arrow, a face pile, etc.
132 end_slot: Option<AnyElement>,
133}
134
135impl SectionHeader {
136 pub fn new(label: impl Into<SharedString>) -> Self {
137 Self {
138 label: label.into(),
139 end_slot: None,
140 }
141 }
142
143 pub fn end_slot<E: IntoElement>(mut self, end_slot: impl Into<Option<E>>) -> Self {
144 self.end_slot = end_slot.into().map(IntoElement::into_any_element);
145 self
146 }
147}
148
149impl RenderOnce for SectionHeader {
150 fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
151 h_flex().id(self.label.clone()).w_full().child(
152 div()
153 .h_7()
154 .flex()
155 .items_center()
156 .justify_between()
157 .w_full()
158 .gap_1()
159 .child(
160 div().flex_1().child(
161 Label::new(self.label.clone())
162 .size(LabelSize::Large)
163 .into_element(),
164 ),
165 )
166 .child(h_flex().children(self.end_slot)),
167 )
168 }
169}