diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index b8603b86499424d2ca3ee4dab6d27f983b369ad3..5b1a482f5e1f7d723d088a51b579da727ff9ef62 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -27,7 +27,10 @@ use settings::Settings; use std::sync::Arc; use theme::ThemeSettings; -use ui::{h_flex, prelude::*, IconButton, IconButtonShape, IconName, Tooltip, BASE_REM_SIZE_IN_PX}; +use ui::{ + h_flex, prelude::*, utils::SearchInputWidth, IconButton, IconButtonShape, IconName, Tooltip, + BASE_REM_SIZE_IN_PX, +}; use util::ResultExt; use workspace::{ item::ItemHandle, @@ -38,8 +41,6 @@ use workspace::{ pub use registrar::DivRegistrar; use registrar::{ForDeployed, ForDismissed, SearchActionsRegistrar, WithResults}; -const MIN_INPUT_WIDTH_REMS: f32 = 10.; -const MAX_INPUT_WIDTH_REMS: f32 = 30.; const MAX_BUFFER_SEARCH_HISTORY_SIZE: usize = 50; #[derive(PartialEq, Clone, Deserialize)] @@ -160,12 +161,12 @@ impl Render for BufferSearchBar { query_editor.placeholder_text(cx).is_none() }) { self.query_editor.update(cx, |editor, cx| { - editor.set_placeholder_text("Search", cx); + editor.set_placeholder_text("Search…", cx); }); } self.replacement_editor.update(cx, |editor, cx| { - editor.set_placeholder_text("Replace with...", cx); + editor.set_placeholder_text("Replace with…", cx); }); let mut text_color = Color::Default; @@ -203,21 +204,26 @@ impl Render for BufferSearchBar { cx.theme().colors().border }; + let container_width = cx.viewport_size().width; + let input_width = SearchInputWidth::calc_width(container_width); + + let input_base_styles = || { + h_flex() + .w(input_width) + .h_8() + .px_2() + .py_1() + .border_1() + .border_color(editor_border) + .rounded_lg() + }; + let search_line = h_flex() .gap_2() .child( - h_flex() + input_base_styles() .id("editor-scroll") .track_scroll(&self.editor_scroll_handle) - .flex_1() - .h_8() - .px_2() - .py_1() - .border_1() - .border_color(editor_border) - .min_w(rems(MIN_INPUT_WIDTH_REMS)) - .max_w(rems(MAX_INPUT_WIDTH_REMS)) - .rounded_lg() .child(self.render_text_input(&self.query_editor, text_color.color(cx), cx)) .when(!hide_inline_icons, |div| { div.children(supported_options.case.then(|| { @@ -249,8 +255,8 @@ impl Render for BufferSearchBar { ) .child( h_flex() - .flex_none() - .gap_0p5() + .gap_1() + .min_w_64() .when(supported_options.replacement, |this| { this.child( IconButton::new( @@ -323,20 +329,27 @@ impl Render for BufferSearchBar { } }), ) - .child(render_nav_button( - ui::IconName::ChevronLeft, - self.active_match_index.is_some(), - "Select Previous Match", - &SelectPrevMatch, - focus_handle.clone(), - )) - .child(render_nav_button( - ui::IconName::ChevronRight, - self.active_match_index.is_some(), - "Select Next Match", - &SelectNextMatch, - focus_handle.clone(), - )) + .child( + h_flex() + .pl_2() + .ml_2() + .border_l_1() + .border_color(cx.theme().colors().border_variant) + .child(render_nav_button( + ui::IconName::ChevronLeft, + self.active_match_index.is_some(), + "Select Previous Match", + &SelectPrevMatch, + focus_handle.clone(), + )) + .child(render_nav_button( + ui::IconName::ChevronRight, + self.active_match_index.is_some(), + "Select Next Match", + &SelectNextMatch, + focus_handle.clone(), + )), + ) .when(!narrow_mode, |this| { this.child(h_flex().ml_2().min_w(rems_from_px(40.)).child( Label::new(match_text).size(LabelSize::Small).color( @@ -353,30 +366,15 @@ impl Render for BufferSearchBar { let replace_line = should_show_replace_input.then(|| { h_flex() .gap_2() - .flex_1() - .child( - h_flex() - .flex_1() - // We're giving this a fixed height to match the height of the search input, - // which has an icon inside that is increasing its height. - .h_8() - .px_2() - .py_1() - .border_1() - .border_color(cx.theme().colors().border) - .rounded_lg() - .min_w(rems(MIN_INPUT_WIDTH_REMS)) - .max_w(rems(MAX_INPUT_WIDTH_REMS)) - .child(self.render_text_input( - &self.replacement_editor, - cx.theme().colors().text, - cx, - )), - ) + .child(input_base_styles().child(self.render_text_input( + &self.replacement_editor, + cx.theme().colors().text, + cx, + ))) .child( h_flex() - .flex_none() - .gap_0p5() + .min_w_64() + .gap_1() .child( IconButton::new("search-replace-next", ui::IconName::ReplaceNext) .shape(IconButtonShape::Square) @@ -418,6 +416,7 @@ impl Render for BufferSearchBar { v_flex() .id("buffer_search") + .gap_2() .track_scroll(&self.scroll_handle) .key_context(key_context) .capture_action(cx.listener(Self::tab)) @@ -446,20 +445,22 @@ impl Render for BufferSearchBar { .when(self.supported_options().selection, |this| { this.on_action(cx.listener(Self::toggle_selection)) }) - .gap_2() .child( h_flex() + .relative() .child(search_line.w_full()) .when(!narrow_mode, |div| { div.child( - IconButton::new(SharedString::from("Close"), IconName::Close) - .shape(IconButtonShape::Square) - .tooltip(move |cx| { - Tooltip::for_action("Close Search Bar", &Dismiss, cx) - }) - .on_click(cx.listener(|this, _: &ClickEvent, cx| { - this.dismiss(&Dismiss, cx) - })), + h_flex().absolute().right_0().child( + IconButton::new(SharedString::from("Close"), IconName::Close) + .shape(IconButtonShape::Square) + .tooltip(move |cx| { + Tooltip::for_action("Close Search Bar", &Dismiss, cx) + }) + .on_click(cx.listener(|this, _: &ClickEvent, cx| { + this.dismiss(&Dismiss, cx) + })), + ), ) }), ) diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 8430fd1f370a5dff4004523bc1d97aa8bd9d88fd..3ec2ac2ababfb525e0c99f0a812e311d52863428 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -34,8 +34,8 @@ use std::{ }; use theme::ThemeSettings; use ui::{ - h_flex, prelude::*, v_flex, Icon, IconButton, IconButtonShape, IconName, KeyBinding, Label, - LabelCommon, LabelSize, Selectable, Tooltip, + h_flex, prelude::*, utils::SearchInputWidth, v_flex, Icon, IconButton, IconButtonShape, + IconName, KeyBinding, Label, LabelCommon, LabelSize, Selectable, Tooltip, }; use util::paths::PathMatcher; use workspace::{ @@ -669,7 +669,7 @@ impl ProjectSearchView { let query_editor = cx.new_view(|cx| { let mut editor = Editor::single_line(cx); - editor.set_placeholder_text("Search all files...", cx); + editor.set_placeholder_text("Search all files…", cx); editor.set_text(query_text, cx); editor }); @@ -692,7 +692,7 @@ impl ProjectSearchView { ); let replacement_editor = cx.new_view(|cx| { let mut editor = Editor::single_line(cx); - editor.set_placeholder_text("Replace in project...", cx); + editor.set_placeholder_text("Replace in project…", cx); if let Some(text) = replacement_text { editor.set_text(text, cx); } @@ -1586,9 +1586,12 @@ impl Render for ProjectSearchBar { let search = search.read(cx); let focus_handle = search.focus_handle(cx); + let container_width = cx.viewport_size().width; + let input_width = SearchInputWidth::calc_width(container_width); + let input_base_styles = || { h_flex() - .w_full() + .w(input_width) .h_8() .px_2() .py_1() @@ -1701,6 +1704,10 @@ impl Render for ProjectSearchBar { .unwrap_or_else(|| "0/0".to_string()); let matches_column = h_flex() + .pl_2() + .ml_2() + .border_l_1() + .border_color(cx.theme().colors().border_variant) .child( IconButton::new("project-search-prev-match", IconName::ChevronLeft) .shape(IconButtonShape::Square) @@ -1751,13 +1758,13 @@ impl Render for ProjectSearchBar { div() .id("matches") .ml_1() - .child( - Label::new(match_text).color(if search.active_match_index.is_some() { + .child(Label::new(match_text).size(LabelSize::Small).color( + if search.active_match_index.is_some() { Color::Default } else { Color::Disabled - }), - ) + }, + )) .when(limit_reached, |el| { el.tooltip(|cx| { Tooltip::text("Search limits reached.\nTry narrowing your search.", cx) @@ -1767,9 +1774,9 @@ impl Render for ProjectSearchBar { let search_line = h_flex() .w_full() - .gap_1p5() + .gap_2() .child(query_column) - .child(h_flex().min_w_40().child(mode_column).child(matches_column)); + .child(h_flex().min_w_64().child(mode_column).child(matches_column)); let replace_line = search.replace_enabled.then(|| { let replace_column = @@ -1779,7 +1786,7 @@ impl Render for ProjectSearchBar { let replace_actions = h_flex() - .min_w_40() + .min_w_64() .gap_1() .when(search.replace_enabled, |this| { this.child( @@ -1830,7 +1837,7 @@ impl Render for ProjectSearchBar { h_flex() .w_full() - .gap_1p5() + .gap_2() .child(replace_column) .child(replace_actions) }); @@ -1838,7 +1845,7 @@ impl Render for ProjectSearchBar { let filter_line = search.filters_enabled.then(|| { h_flex() .w_full() - .gap_1p5() + .gap_2() .child( input_base_styles() .on_action( @@ -1861,12 +1868,11 @@ impl Render for ProjectSearchBar { ) .child( h_flex() - .min_w_40() + .min_w_64() .gap_1() .child( 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| { diff --git a/crates/ui/src/utils.rs b/crates/ui/src/utils.rs index 25477194dc363ee00aeeb9c18c4c0eefdccb73d1..e5c591a97041edfb24747aef44535d02128d324e 100644 --- a/crates/ui/src/utils.rs +++ b/crates/ui/src/utils.rs @@ -2,8 +2,10 @@ mod color_contrast; mod format_distance; +mod search_input; mod with_rem_size; pub use color_contrast::*; pub use format_distance::*; +pub use search_input::*; pub use with_rem_size::*; diff --git a/crates/ui/src/utils/search_input.rs b/crates/ui/src/utils/search_input.rs new file mode 100644 index 0000000000000000000000000000000000000000..3a507f9a5ae14536b685f8cab1b60f6e38e2c2a0 --- /dev/null +++ b/crates/ui/src/utils/search_input.rs @@ -0,0 +1,22 @@ +#![allow(missing_docs)] + +use gpui::Pixels; + +pub struct SearchInputWidth; + +impl SearchInputWidth { + /// The containzer size in which the input stops filling the whole width. + pub const THRESHOLD_WIDTH: f32 = 1200.0; + + /// The maximum width for the search input when the container is larger than the threshold. + pub const MAX_WIDTH: f32 = 1200.0; + + /// Calculates the actual width in pixels based on the container width. + pub fn calc_width(container_width: Pixels) -> Pixels { + if container_width.0 < Self::THRESHOLD_WIDTH { + container_width + } else { + Pixels(container_width.0.min(Self::MAX_WIDTH)) + } + } +}