Ensure project search actions are always aligned (#20353)

Danilo Leal created

Follow up to https://github.com/zed-industries/zed/pull/20242

This PR ensures all the actions to the right of the project search
inputs have the same minimum width, ensuring that the inputs themselves
are always aligned. In the previous PR, I didn't considered the scenario
where the project search numbers where beyond 4 or 5 digits, which then
increased their width. This should be treated now!

<img width="700" alt="Screenshot 2024-11-07 at 09 55 11"
src="https://github.com/user-attachments/assets/7a9d8ebd-b575-4141-9242-3044f00150c5">

Release Notes:

- N/A

Change summary

assets/icons/file_search.svg        |   1 
crates/search/src/project_search.rs | 108 +++++++++++++++---------------
crates/ui/src/components/icon.rs    |   1 
3 files changed, 57 insertions(+), 53 deletions(-)

Detailed changes

assets/icons/file_search.svg 🔗

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-file-search"><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M4.268 21a2 2 0 0 0 1.727 1H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3"/><path d="m9 18-1.5-1.5"/><circle cx="5" cy="14" r="3"/></svg>

crates/search/src/project_search.rs 🔗

@@ -1747,7 +1747,7 @@ impl Render for ProjectSearchBar {
             .child(
                 div()
                     .id("matches")
-                    .ml_0p5()
+                    .ml_1()
                     .child(
                         Label::new(match_text).color(if search.active_match_index.is_some() {
                             Color::Default
@@ -1765,10 +1765,8 @@ impl Render for ProjectSearchBar {
         let search_line = h_flex()
             .w_full()
             .gap_1p5()
-            .pr_6()
             .child(query_column)
-            .child(mode_column)
-            .child(matches_column);
+            .child(h_flex().min_w_40().child(mode_column).child(matches_column));
 
         let replace_line = search.replace_enabled.then(|| {
             let replace_column =
@@ -1776,57 +1774,60 @@ impl Render for ProjectSearchBar {
 
             let focus_handle = search.replacement_editor.read(cx).focus_handle(cx);
 
-            let replace_actions = h_flex().gap_1().when(search.replace_enabled, |this| {
-                this.child(
-                    IconButton::new("project-search-replace-next", IconName::ReplaceNext)
-                        .shape(IconButtonShape::Square)
-                        .on_click(cx.listener(|this, _, cx| {
-                            if let Some(search) = this.active_project_search.as_ref() {
-                                search.update(cx, |this, cx| {
-                                    this.replace_next(&ReplaceNext, cx);
-                                })
-                            }
-                        }))
-                        .tooltip({
-                            let focus_handle = focus_handle.clone();
-                            move |cx| {
-                                Tooltip::for_action_in(
-                                    "Replace Next Match",
-                                    &ReplaceNext,
-                                    &focus_handle,
-                                    cx,
-                                )
-                            }
-                        }),
-                )
-                .child(
-                    IconButton::new("project-search-replace-all", IconName::ReplaceAll)
-                        .shape(IconButtonShape::Square)
-                        .on_click(cx.listener(|this, _, cx| {
-                            if let Some(search) = this.active_project_search.as_ref() {
-                                search.update(cx, |this, cx| {
-                                    this.replace_all(&ReplaceAll, cx);
-                                })
-                            }
-                        }))
-                        .tooltip({
-                            let focus_handle = focus_handle.clone();
-                            move |cx| {
-                                Tooltip::for_action_in(
-                                    "Replace All Matches",
-                                    &ReplaceAll,
-                                    &focus_handle,
-                                    cx,
-                                )
-                            }
-                        }),
-                )
-            });
+            let replace_actions =
+                h_flex()
+                    .min_w_40()
+                    .gap_1()
+                    .when(search.replace_enabled, |this| {
+                        this.child(
+                            IconButton::new("project-search-replace-next", IconName::ReplaceNext)
+                                .shape(IconButtonShape::Square)
+                                .on_click(cx.listener(|this, _, cx| {
+                                    if let Some(search) = this.active_project_search.as_ref() {
+                                        search.update(cx, |this, cx| {
+                                            this.replace_next(&ReplaceNext, cx);
+                                        })
+                                    }
+                                }))
+                                .tooltip({
+                                    let focus_handle = focus_handle.clone();
+                                    move |cx| {
+                                        Tooltip::for_action_in(
+                                            "Replace Next Match",
+                                            &ReplaceNext,
+                                            &focus_handle,
+                                            cx,
+                                        )
+                                    }
+                                }),
+                        )
+                        .child(
+                            IconButton::new("project-search-replace-all", IconName::ReplaceAll)
+                                .shape(IconButtonShape::Square)
+                                .on_click(cx.listener(|this, _, cx| {
+                                    if let Some(search) = this.active_project_search.as_ref() {
+                                        search.update(cx, |this, cx| {
+                                            this.replace_all(&ReplaceAll, cx);
+                                        })
+                                    }
+                                }))
+                                .tooltip({
+                                    let focus_handle = focus_handle.clone();
+                                    move |cx| {
+                                        Tooltip::for_action_in(
+                                            "Replace All Matches",
+                                            &ReplaceAll,
+                                            &focus_handle,
+                                            cx,
+                                        )
+                                    }
+                                }),
+                        )
+                    });
 
             h_flex()
                 .w_full()
                 .gap_1p5()
-                .pr_24()
                 .child(replace_column)
                 .child(replace_actions)
         });
@@ -1835,7 +1836,6 @@ impl Render for ProjectSearchBar {
             h_flex()
                 .w_full()
                 .gap_1p5()
-                .pr_24()
                 .child(
                     input_base_styles()
                         .on_action(
@@ -1858,10 +1858,12 @@ impl Render for ProjectSearchBar {
                 )
                 .child(
                     h_flex()
+                        .min_w_40()
                         .gap_1()
                         .child(
-                            IconButton::new("project-search-opened-only", IconName::FileDoc)
+                            IconButton::new("project-search-opened-only", IconName::FileSearch)
                                 .shape(IconButtonShape::Square)
+                                .icon_size(IconSize::XSmall)
                                 .selected(self.is_opened_only_enabled(cx))
                                 .tooltip(|cx| Tooltip::text("Only Search Open Files", cx))
                                 .on_click(cx.listener(|this, _, cx| {