palette.rs

  1use std::marker::PhantomData;
  2
  3use crate::prelude::OrderMethod;
  4use crate::theme::theme;
  5use crate::{label, palette_item, LabelColor, PaletteItem};
  6use gpui2::elements::div::ScrollState;
  7use gpui2::style::{StyleHelpers, Styleable};
  8use gpui2::{elements::div, IntoElement};
  9use gpui2::{Element, ParentElement, ViewContext};
 10
 11#[derive(Element)]
 12pub struct Palette<V: 'static> {
 13    view_type: PhantomData<V>,
 14    scroll_state: ScrollState,
 15    input_placeholder: &'static str,
 16    empty_string: &'static str,
 17    items: Vec<PaletteItem>,
 18    default_order: OrderMethod,
 19}
 20
 21pub fn palette<V: 'static>(scroll_state: ScrollState) -> Palette<V> {
 22    Palette {
 23        view_type: PhantomData,
 24        scroll_state,
 25        input_placeholder: "Find something...",
 26        empty_string: "No items found.",
 27        items: vec![],
 28        default_order: OrderMethod::default(),
 29    }
 30}
 31
 32impl<V: 'static> Palette<V> {
 33    pub fn items(mut self, mut items: Vec<PaletteItem>) -> Self {
 34        items.sort_by_key(|item| item.label);
 35        self.items = items;
 36        self
 37    }
 38
 39    pub fn placeholder(mut self, input_placeholder: &'static str) -> Self {
 40        self.input_placeholder = input_placeholder;
 41        self
 42    }
 43
 44    pub fn empty_string(mut self, empty_string: &'static str) -> Self {
 45        self.empty_string = empty_string;
 46        self
 47    }
 48
 49    // TODO: Hook up sort order
 50    pub fn default_order(mut self, default_order: OrderMethod) -> Self {
 51        self.default_order = default_order;
 52        self
 53    }
 54
 55    fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
 56        let theme = theme(cx);
 57
 58        div()
 59            .w_96()
 60            .rounded_lg()
 61            .fill(theme.lowest.base.default.background)
 62            .border()
 63            .border_color(theme.lowest.base.default.border)
 64            .flex()
 65            .flex_col()
 66            .child(
 67                div()
 68                    .flex()
 69                    .flex_col()
 70                    .gap_px()
 71                    .child(
 72                        div().py_0p5().px_1().flex().flex_col().child(
 73                            div().px_2().py_0p5().child(
 74                                label(self.input_placeholder).color(LabelColor::Placeholder),
 75                            ),
 76                        ),
 77                    )
 78                    .child(div().h_px().w_full().fill(theme.lowest.base.default.border))
 79                    .child(
 80                        div()
 81                            .py_0p5()
 82                            .px_1()
 83                            .flex()
 84                            .flex_col()
 85                            .grow()
 86                            .max_h_96()
 87                            .overflow_y_scroll(self.scroll_state.clone())
 88                            .children(
 89                                vec![if self.items.is_empty() {
 90                                    Some(
 91                                        div()
 92                                            .flex()
 93                                            .flex_row()
 94                                            .justify_between()
 95                                            .px_2()
 96                                            .py_1()
 97                                            .child(
 98                                                label(self.empty_string).color(LabelColor::Muted),
 99                                            ),
100                                    )
101                                } else {
102                                    None
103                                }]
104                                .into_iter()
105                                .flatten(),
106                            )
107                            .children(self.items.iter().map(|item| {
108                                div()
109                                    .flex()
110                                    .flex_row()
111                                    .justify_between()
112                                    .px_2()
113                                    .py_0p5()
114                                    .rounded_lg()
115                                    .hover()
116                                    .fill(theme.lowest.base.hovered.background)
117                                    .active()
118                                    .fill(theme.lowest.base.pressed.background)
119                                    .child(palette_item(item.label, item.keybinding))
120                            })),
121                    ),
122            )
123    }
124}