components.rs

 1use editor::Editor;
 2use gpui::div;
 3use ui::{
 4    ActiveTheme as _, App, FluentBuilder as _, InteractiveElement as _, IntoElement,
 5    ParentElement as _, RenderOnce, Styled as _, Window,
 6};
 7
 8#[derive(IntoElement)]
 9pub struct SettingsEditor {
10    initial_text: Option<String>,
11    placeholder: Option<&'static str>,
12    confirm: Option<Box<dyn Fn(Option<String>, &mut App)>>,
13}
14
15impl SettingsEditor {
16    pub fn new() -> Self {
17        Self {
18            initial_text: None,
19            placeholder: None,
20            confirm: None,
21        }
22    }
23
24    pub fn with_initial_text(mut self, initial_text: String) -> Self {
25        self.initial_text = Some(initial_text);
26        self
27    }
28
29    pub fn with_placeholder(mut self, placeholder: &'static str) -> Self {
30        self.placeholder = Some(placeholder);
31        self
32    }
33
34    pub fn on_confirm(mut self, confirm: impl Fn(Option<String>, &mut App) + 'static) -> Self {
35        self.confirm = Some(Box::new(confirm));
36        self
37    }
38}
39
40impl RenderOnce for SettingsEditor {
41    fn render(self, window: &mut Window, cx: &mut App) -> impl ui::IntoElement {
42        let editor = window.use_state(cx, {
43            move |window, cx| {
44                let mut editor = Editor::single_line(window, cx);
45                if let Some(text) = self.initial_text {
46                    editor.set_text(text, window, cx);
47                }
48
49                if let Some(placeholder) = self.placeholder {
50                    editor.set_placeholder_text(placeholder, window, cx);
51                }
52                // todo(settings_ui): We should have an observe global use for settings store
53                // so whenever a settings file is updated, the settings ui updates too
54                editor
55            }
56        });
57
58        let weak_editor = editor.downgrade();
59        let theme_colors = cx.theme().colors();
60
61        div()
62            .py_1()
63            .px_2()
64            .min_w_64()
65            .rounded_md()
66            .border_1()
67            .border_color(theme_colors.border)
68            .bg(theme_colors.editor_background)
69            .child(editor)
70            .when_some(self.confirm, |this, confirm| {
71                this.on_action::<menu::Confirm>({
72                    move |_, _, cx| {
73                        let Some(editor) = weak_editor.upgrade() else {
74                            return;
75                        };
76                        let new_value = editor.read_with(cx, |editor, cx| editor.text(cx));
77                        let new_value = (!new_value.is_empty()).then_some(new_value);
78                        confirm(new_value, cx);
79                    }
80                })
81            })
82    }
83}