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