palette.rs

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