Merge pull request #2001 from zed-industries/dissmis-search-button

Julia created

Add dismiss buffer search button & fix some faulty icon button styling

Change summary

crates/gpui/src/app.rs                      |   2 
crates/search/src/buffer_search.rs          | 166 ++++++++++++++--------
crates/theme/src/theme.rs                   |   1 
styles/src/styleTree/contactNotification.ts |   4 
styles/src/styleTree/editor.ts              |   1 
styles/src/styleTree/search.ts              |  12 +
styles/src/styleTree/tabBar.ts              |   2 
7 files changed, 119 insertions(+), 69 deletions(-)

Detailed changes

crates/gpui/src/app.rs 🔗

@@ -4038,7 +4038,7 @@ pub struct RenderContext<'a, T: View> {
     pub refreshing: bool,
 }
 
-#[derive(Clone, Default)]
+#[derive(Debug, Clone, Default)]
 pub struct MouseState {
     hovered: bool,
     clicked: Option<MouseButton>,

crates/search/src/buffer_search.rs 🔗

@@ -106,73 +106,79 @@ impl View for BufferSearchBar {
             .with_child(
                 Flex::row()
                     .with_child(
-                        ChildView::new(&self.query_editor, cx)
-                            .aligned()
-                            .left()
-                            .flex(1., true)
-                            .boxed(),
-                    )
-                    .with_children(self.active_searchable_item.as_ref().and_then(
-                        |searchable_item| {
-                            let matches = self
-                                .seachable_items_with_matches
-                                .get(&searchable_item.downgrade())?;
-                            let message = if let Some(match_ix) = self.active_match_index {
-                                format!("{}/{}", match_ix + 1, matches.len())
-                            } else {
-                                "No matches".to_string()
-                            };
-
-                            Some(
-                                Label::new(message, theme.search.match_index.text.clone())
-                                    .contained()
-                                    .with_style(theme.search.match_index.container)
+                        Flex::row()
+                            .with_child(
+                                ChildView::new(&self.query_editor, cx)
                                     .aligned()
+                                    .left()
+                                    .flex(1., true)
                                     .boxed(),
                             )
-                        },
-                    ))
-                    .contained()
-                    .with_style(editor_container)
-                    .aligned()
-                    .constrained()
-                    .with_min_width(theme.search.editor.min_width)
-                    .with_max_width(theme.search.editor.max_width)
-                    .flex(1., false)
-                    .boxed(),
-            )
-            .with_child(
-                Flex::row()
-                    .with_child(self.render_nav_button("<", Direction::Prev, cx))
-                    .with_child(self.render_nav_button(">", Direction::Next, cx))
-                    .aligned()
-                    .boxed(),
-            )
-            .with_child(
-                Flex::row()
-                    .with_children(self.render_search_option(
-                        supported_options.case,
-                        "Case",
-                        SearchOption::CaseSensitive,
-                        cx,
-                    ))
-                    .with_children(self.render_search_option(
-                        supported_options.word,
-                        "Word",
-                        SearchOption::WholeWord,
-                        cx,
-                    ))
-                    .with_children(self.render_search_option(
-                        supported_options.regex,
-                        "Regex",
-                        SearchOption::Regex,
-                        cx,
-                    ))
-                    .contained()
-                    .with_style(theme.search.option_button_group)
-                    .aligned()
+                            .with_children(self.active_searchable_item.as_ref().and_then(
+                                |searchable_item| {
+                                    let matches = self
+                                        .seachable_items_with_matches
+                                        .get(&searchable_item.downgrade())?;
+                                    let message = if let Some(match_ix) = self.active_match_index {
+                                        format!("{}/{}", match_ix + 1, matches.len())
+                                    } else {
+                                        "No matches".to_string()
+                                    };
+
+                                    Some(
+                                        Label::new(message, theme.search.match_index.text.clone())
+                                            .contained()
+                                            .with_style(theme.search.match_index.container)
+                                            .aligned()
+                                            .boxed(),
+                                    )
+                                },
+                            ))
+                            .contained()
+                            .with_style(editor_container)
+                            .aligned()
+                            .constrained()
+                            .with_min_width(theme.search.editor.min_width)
+                            .with_max_width(theme.search.editor.max_width)
+                            .flex(1., false)
+                            .boxed(),
+                    )
+                    .with_child(
+                        Flex::row()
+                            .with_child(self.render_nav_button("<", Direction::Prev, cx))
+                            .with_child(self.render_nav_button(">", Direction::Next, cx))
+                            .aligned()
+                            .boxed(),
+                    )
+                    .with_child(
+                        Flex::row()
+                            .with_children(self.render_search_option(
+                                supported_options.case,
+                                "Case",
+                                SearchOption::CaseSensitive,
+                                cx,
+                            ))
+                            .with_children(self.render_search_option(
+                                supported_options.word,
+                                "Word",
+                                SearchOption::WholeWord,
+                                cx,
+                            ))
+                            .with_children(self.render_search_option(
+                                supported_options.regex,
+                                "Regex",
+                                SearchOption::Regex,
+                                cx,
+                            ))
+                            .contained()
+                            .with_style(theme.search.option_button_group)
+                            .aligned()
+                            .boxed(),
+                    )
+                    .flex(1., true)
                     .boxed(),
             )
+            .with_child(self.render_close_button(&theme.search, cx))
             .contained()
             .with_style(theme.search.container)
             .named("search bar")
@@ -325,7 +331,7 @@ impl BufferSearchBar {
         let is_active = self.is_search_option_enabled(option);
         Some(
             MouseEventHandler::<Self>::new(option as usize, cx, |state, cx| {
-                let style = &cx
+                let style = cx
                     .global::<Settings>()
                     .theme
                     .search
@@ -373,7 +379,7 @@ impl BufferSearchBar {
 
         enum NavButton {}
         MouseEventHandler::<NavButton>::new(direction as usize, cx, |state, cx| {
-            let style = &cx
+            let style = cx
                 .global::<Settings>()
                 .theme
                 .search
@@ -399,6 +405,38 @@ impl BufferSearchBar {
         .boxed()
     }
 
+    fn render_close_button(
+        &self,
+        theme: &theme::Search,
+        cx: &mut RenderContext<Self>,
+    ) -> ElementBox {
+        let action = Box::new(Dismiss);
+        let tooltip = "Dismiss Buffer Search";
+        let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
+
+        enum CloseButton {}
+        MouseEventHandler::<CloseButton>::new(0, cx, |state, _| {
+            let style = theme.dismiss_button.style_for(state, false);
+            Svg::new("icons/x_mark_8.svg")
+                .with_color(style.color)
+                .constrained()
+                .with_width(style.icon_width)
+                .aligned()
+                .constrained()
+                .with_width(style.button_width)
+                .contained()
+                .with_style(style.container)
+                .boxed()
+        })
+        .on_click(MouseButton::Left, {
+            let action = action.boxed_clone();
+            move |_, cx| cx.dispatch_any_action(action.boxed_clone())
+        })
+        .with_cursor_style(CursorStyle::PointingHand)
+        .with_tooltip::<CloseButton, _>(0, tooltip.to_string(), Some(action), tooltip_style, cx)
+        .boxed()
+    }
+
     fn deploy(pane: &mut Pane, action: &Deploy, cx: &mut ViewContext<Pane>) {
         if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
             if search_bar.update(cx, |search_bar, cx| search_bar.show(action.focus, true, cx)) {

crates/theme/src/theme.rs 🔗

@@ -247,6 +247,7 @@ pub struct Search {
     pub results_status: TextStyle,
     pub tab_icon_width: f32,
     pub tab_icon_spacing: f32,
+    pub dismiss_button: Interactive<IconButton>,
 }
 
 #[derive(Clone, Deserialize, Default)]

styles/src/styleTree/contactNotification.ts 🔗

@@ -32,13 +32,13 @@ export default function contactNotification(colorScheme: ColorScheme): Object {
       },
     },
     dismissButton: {
-      color: foreground(layer, "on"),
+      color: foreground(layer, "variant"),
       iconWidth: 8,
       iconHeight: 8,
       buttonWidth: 8,
       buttonHeight: 8,
       hover: {
-        color: foreground(layer, "on", "hovered"),
+        color: foreground(layer, "hovered"),
       },
     },
   };

styles/src/styleTree/editor.ts 🔗

@@ -257,7 +257,6 @@ export default function editor(colorScheme: ColorScheme) {
         right: 6,
       },
       hover: {
-        color: foreground(layer, "on", "hovered"),
         background: background(layer, "on", "hovered"),
       },
     },

styles/src/styleTree/search.ts 🔗

@@ -80,5 +80,17 @@ export default function search(colorScheme: ColorScheme) {
       ...text(layer, "mono", "on"),
       size: 18,
     },
+    dismissButton: {
+      color: foreground(layer, "variant"),
+      iconWidth: 12,
+      buttonWidth: 14,
+      padding: {
+        left: 10,
+        right: 10,
+      },
+      hover: {
+        color: foreground(layer, "hovered"),
+      },
+    },
   };
 }

styles/src/styleTree/tabBar.ts 🔗

@@ -26,7 +26,7 @@ export default function tabBar(colorScheme: ColorScheme) {
     // Close icons
     iconWidth: 8,
     iconClose: foreground(layer, "variant"),
-    iconCloseActive: foreground(layer),
+    iconCloseActive: foreground(layer, "hovered"),
 
     // Indicators
     iconConflict: foreground(layer, "warning"),