Add consistency between buffer and project search design (#20754)

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

This PR adds the `SearchInputWidth` util, which sets a threshold
container size in which an input's width stops filling the available
space. In practice, this is in place to make the buffer and project
search input fill the whole container width up to a certain point (where
this point is really an arbitrary number that can be fine-tuned per
taste). For folks using huge monitors, the UX isn't excellent if you
have a gigantic input.

In the future, upon further review, maybe it makes more sense to
reorganize this code better, baking it in as a default behavior of the
input component. Or even exposing this is a function many other
components could use, given we may want to have dynamic width in
different scenarios.

For now, I just wanted to make the design of these search UIs better and
more consistent.

| Buffer Search | Project Search |
|--------|--------|
| <img width="1042" alt="Screenshot 2024-11-15 at 20 39 21"
src="https://github.com/user-attachments/assets/f9cbf0b3-8c58-46d1-8380-e89cd9c89699">
| <img width="1042" alt="Screenshot 2024-11-15 at 20 39 24"
src="https://github.com/user-attachments/assets/ed244a51-ea55-4fe3-a719-a3d9cd119aa9">
|

Release Notes:

- N/A
This commit is contained in:
Danilo Leal
2024-11-28 13:39:49 -03:00
committed by GitHub
parent f30944543e
commit 301a8900a5
4 changed files with 109 additions and 78 deletions
+63 -62
View File
@@ -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(input_base_styles().child(self.render_text_input(
&self.replacement_editor,
cx.theme().colors().text,
cx,
)))
.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(
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)
})),
),
)
}),
)