Improve extensions UI detail (#8578)

Jason Lee and Marshall Bowers created

Release Notes:

- Improved "Extensions" UI details to tidy layout, add border, add
placeholder to search input.


## Before


![SCR-20240229-fbk](https://github.com/zed-industries/zed/assets/5518/a62608e2-8f79-48fe-9e1c-87d6eb59ddc9)

## After


![SCR-20240229-fhz](https://github.com/zed-industries/zed/assets/5518/d5c97711-ff93-4944-8e23-39b60dda88fc)

![SCR-20240229-fg9](https://github.com/zed-industries/zed/assets/5518/a24ad839-3b69-4ca7-813f-00375a81a008)

![SCR-20240229-fbb](https://github.com/zed-industries/zed/assets/5518/ff45d6c3-93a3-431c-81f5-edc9e7aa68d6)

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>

Change summary

crates/extensions_ui/src/extensions_ui.rs | 112 ++++++++++++++----------
1 file changed, 63 insertions(+), 49 deletions(-)

Detailed changes

crates/extensions_ui/src/extensions_ui.rs 🔗

@@ -55,7 +55,11 @@ impl ExtensionsPage {
             let store = ExtensionStore::global(cx);
             let subscription = cx.observe(&store, |_, _, cx| cx.notify());
 
-            let query_editor = cx.new_view(|cx| Editor::single_line(cx));
+            let query_editor = cx.new_view(|cx| {
+                let mut input = Editor::single_line(cx);
+                input.set_placeholder_text("Search extensions...", cx);
+                input
+            });
             cx.subscribe(&query_editor, Self::on_query_change).detach();
 
             let mut this = Self {
@@ -464,64 +468,73 @@ impl Render for ExtensionsPage {
     fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
         v_flex()
             .size_full()
-            .p_4()
-            .gap_4()
             .bg(cx.theme().colors().editor_background)
             .child(
-                h_flex()
-                    .w_full()
-                    .child(Headline::new("Extensions").size(HeadlineSize::XLarge)),
-            )
-            .child(
-                h_flex()
-                    .w_full()
-                    .gap_2()
-                    .child(h_flex().child(self.render_search(cx)))
+                v_flex()
+                    .gap_4()
+                    .p_4()
+                    .border_b()
+                    .border_color(cx.theme().colors().border)
+                    .bg(cx.theme().colors().editor_background)
                     .child(
                         h_flex()
+                            .w_full()
+                            .child(Headline::new("Extensions").size(HeadlineSize::XLarge)),
+                    )
+                    .child(
+                        h_flex()
+                            .w_full()
+                            .gap_2()
+                            .justify_between()
+                            .child(h_flex().child(self.render_search(cx)))
                             .child(
-                                ToggleButton::new("filter-all", "All")
-                                    .style(ButtonStyle::Filled)
-                                    .size(ButtonSize::Large)
-                                    .selected(self.filter == ExtensionFilter::All)
-                                    .on_click(cx.listener(|this, _event, _cx| {
-                                        this.filter = ExtensionFilter::All;
-                                    }))
-                                    .tooltip(move |cx| Tooltip::text("Show all extensions", cx))
-                                    .first(),
-                            )
-                            .child(
-                                ToggleButton::new("filter-installed", "Installed")
-                                    .style(ButtonStyle::Filled)
-                                    .size(ButtonSize::Large)
-                                    .selected(self.filter == ExtensionFilter::Installed)
-                                    .on_click(cx.listener(|this, _event, _cx| {
-                                        this.filter = ExtensionFilter::Installed;
-                                    }))
-                                    .tooltip(move |cx| {
-                                        Tooltip::text("Show installed extensions", cx)
-                                    })
-                                    .middle(),
-                            )
-                            .child(
-                                ToggleButton::new("filter-not-installed", "Not Installed")
-                                    .style(ButtonStyle::Filled)
-                                    .size(ButtonSize::Large)
-                                    .selected(self.filter == ExtensionFilter::NotInstalled)
-                                    .on_click(cx.listener(|this, _event, _cx| {
-                                        this.filter = ExtensionFilter::NotInstalled;
-                                    }))
-                                    .tooltip(move |cx| {
-                                        Tooltip::text("Show not installed extensions", cx)
-                                    })
-                                    .last(),
+                                h_flex()
+                                    .child(
+                                        ToggleButton::new("filter-all", "All")
+                                            .style(ButtonStyle::Filled)
+                                            .size(ButtonSize::Large)
+                                            .selected(self.filter == ExtensionFilter::All)
+                                            .on_click(cx.listener(|this, _event, _cx| {
+                                                this.filter = ExtensionFilter::All;
+                                            }))
+                                            .tooltip(move |cx| {
+                                                Tooltip::text("Show all extensions", cx)
+                                            })
+                                            .first(),
+                                    )
+                                    .child(
+                                        ToggleButton::new("filter-installed", "Installed")
+                                            .style(ButtonStyle::Filled)
+                                            .size(ButtonSize::Large)
+                                            .selected(self.filter == ExtensionFilter::Installed)
+                                            .on_click(cx.listener(|this, _event, _cx| {
+                                                this.filter = ExtensionFilter::Installed;
+                                            }))
+                                            .tooltip(move |cx| {
+                                                Tooltip::text("Show installed extensions", cx)
+                                            })
+                                            .middle(),
+                                    )
+                                    .child(
+                                        ToggleButton::new("filter-not-installed", "Not Installed")
+                                            .style(ButtonStyle::Filled)
+                                            .size(ButtonSize::Large)
+                                            .selected(self.filter == ExtensionFilter::NotInstalled)
+                                            .on_click(cx.listener(|this, _event, _cx| {
+                                                this.filter = ExtensionFilter::NotInstalled;
+                                            }))
+                                            .tooltip(move |cx| {
+                                                Tooltip::text("Show not installed extensions", cx)
+                                            })
+                                            .last(),
+                                    ),
                             ),
                     ),
             )
-            .child(v_flex().size_full().overflow_y_hidden().map(|this| {
+            .child(v_flex().px_4().size_full().overflow_y_hidden().map(|this| {
                 let entries = self.filtered_extension_entries(cx);
                 if entries.is_empty() {
-                    return this.child(self.render_empty_state(cx));
+                    return this.py_4().child(self.render_empty_state(cx));
                 }
 
                 this.child(
@@ -537,6 +550,7 @@ impl Render for ExtensionsPage {
                                 Self::render_extensions,
                             )
                             .size_full()
+                            .pb_4()
                             .track_scroll(scroll_handle)
                             .into_any_element()
                             .draw(