modal.rs

  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}