Make search field in panels be at the top (#43200)
This mostly affects the collab and outline panels for now. It has always been a bit weird that the search field was at the bottom of the panel, even more so because in both cases, you can _arrow down_ to start navigating the list with your keyboard. So, with the search at the bottom, you'd arrow down and get to the top of the list, which was very strange. Now, with it at the top, it not only looks better but it is also more generally consistent with other surfaces in the app, like pickers, the settings UI, rules library, etc. Most search fields are always at the top. <img width="800" height="1830" alt="image" src="https://github.com/user-attachments/assets/3e2c3b8f-5907-4d83-8804-b3fc77342103" /> Release Notes: - N/A
This commit is contained in:
@@ -32,7 +32,7 @@ use std::{mem, sync::Arc};
|
||||
use theme::{ActiveTheme, ThemeSettings};
|
||||
use ui::{
|
||||
Avatar, AvatarAvailabilityIndicator, Button, Color, ContextMenu, Facepile, HighlightedLabel,
|
||||
Icon, IconButton, IconName, IconSize, Indicator, Label, ListHeader, ListItem, Tooltip,
|
||||
Icon, IconButton, IconName, IconSize, Indicator, Label, ListHeader, ListItem, Tab, Tooltip,
|
||||
prelude::*, tooltip_container,
|
||||
};
|
||||
use util::{ResultExt, TryFutureExt, maybe};
|
||||
@@ -287,7 +287,7 @@ impl CollabPanel {
|
||||
cx.new(|cx| {
|
||||
let filter_editor = cx.new(|cx| {
|
||||
let mut editor = Editor::single_line(window, cx);
|
||||
editor.set_placeholder_text("Filter...", window, cx);
|
||||
editor.set_placeholder_text("Search channels…", window, cx);
|
||||
editor
|
||||
});
|
||||
|
||||
@@ -2412,6 +2412,21 @@ impl CollabPanel {
|
||||
});
|
||||
v_flex()
|
||||
.size_full()
|
||||
.gap_1()
|
||||
.child(
|
||||
h_flex()
|
||||
.p_2()
|
||||
.h(Tab::container_height(cx))
|
||||
.gap_1p5()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.child(
|
||||
Icon::new(IconName::MagnifyingGlass)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(self.render_filter_input(&self.filter_editor, cx)),
|
||||
)
|
||||
.child(
|
||||
list(
|
||||
self.list_state.clone(),
|
||||
@@ -2419,15 +2434,6 @@ impl CollabPanel {
|
||||
)
|
||||
.size_full(),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.child(div().mx_2().border_primary(cx).border_t_1())
|
||||
.child(
|
||||
v_flex()
|
||||
.p_2()
|
||||
.child(self.render_filter_input(&self.filter_editor, cx)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_filter_input(
|
||||
|
||||
@@ -46,10 +46,8 @@ use settings::{Settings, SettingsStore};
|
||||
use smol::channel;
|
||||
use theme::{SyntaxTheme, ThemeSettings};
|
||||
use ui::{
|
||||
ActiveTheme, ButtonCommon, Clickable, Color, ContextMenu, DynamicSpacing, FluentBuilder,
|
||||
HighlightedLabel, Icon, IconButton, IconButtonShape, IconName, IconSize, IndentGuideColors,
|
||||
IndentGuideLayout, Label, LabelCommon, ListItem, ScrollAxes, Scrollbars, StyledExt,
|
||||
StyledTypography, Toggleable, Tooltip, WithScrollbar, h_flex, v_flex,
|
||||
ContextMenu, FluentBuilder, HighlightedLabel, IconButton, IconButtonShape, IndentGuideColors,
|
||||
IndentGuideLayout, ListItem, ScrollAxes, Scrollbars, Tab, Tooltip, WithScrollbar, prelude::*,
|
||||
};
|
||||
use util::{RangeExt, ResultExt, TryFutureExt, debug_panic, rel_path::RelPath};
|
||||
use workspace::{
|
||||
@@ -714,7 +712,7 @@ impl OutlinePanel {
|
||||
cx.new(|cx| {
|
||||
let filter_editor = cx.new(|cx| {
|
||||
let mut editor = Editor::single_line(window, cx);
|
||||
editor.set_placeholder_text("Filter...", window, cx);
|
||||
editor.set_placeholder_text("Search buffer symbols…", window, cx);
|
||||
editor
|
||||
});
|
||||
let filter_update_subscription = cx.subscribe_in(
|
||||
@@ -4553,6 +4551,7 @@ impl OutlinePanel {
|
||||
|
||||
v_flex()
|
||||
.id("empty-outline-state")
|
||||
.gap_0p5()
|
||||
.flex_1()
|
||||
.justify_center()
|
||||
.size_full()
|
||||
@@ -4560,25 +4559,28 @@ impl OutlinePanel {
|
||||
panel
|
||||
.child(h_flex().justify_center().child(Label::new(header)))
|
||||
.when_some(query.clone(), |panel, query| {
|
||||
panel.child(h_flex().justify_center().child(Label::new(query)))
|
||||
panel.child(
|
||||
h_flex()
|
||||
.px_0p5()
|
||||
.justify_center()
|
||||
.bg(cx.theme().colors().element_selected.opacity(0.2))
|
||||
.child(Label::new(query)),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
.pt(DynamicSpacing::Base04.rems(cx))
|
||||
.justify_center()
|
||||
.child({
|
||||
let keystroke =
|
||||
match self.position(window, cx) {
|
||||
DockPosition::Left => window
|
||||
.keystroke_text_for(&workspace::ToggleLeftDock),
|
||||
DockPosition::Bottom => window
|
||||
.keystroke_text_for(&workspace::ToggleBottomDock),
|
||||
DockPosition::Right => window
|
||||
.keystroke_text_for(&workspace::ToggleRightDock),
|
||||
};
|
||||
Label::new(format!("Toggle this panel with {keystroke}"))
|
||||
}),
|
||||
)
|
||||
.child(h_flex().justify_center().child({
|
||||
let keystroke = match self.position(window, cx) {
|
||||
DockPosition::Left => {
|
||||
window.keystroke_text_for(&workspace::ToggleLeftDock)
|
||||
}
|
||||
DockPosition::Bottom => {
|
||||
window.keystroke_text_for(&workspace::ToggleBottomDock)
|
||||
}
|
||||
DockPosition::Right => {
|
||||
window.keystroke_text_for(&workspace::ToggleRightDock)
|
||||
}
|
||||
};
|
||||
Label::new(format!("Toggle Panel With {keystroke}")).color(Color::Muted)
|
||||
}))
|
||||
})
|
||||
} else {
|
||||
let list_contents = {
|
||||
@@ -4728,39 +4730,37 @@ impl OutlinePanel {
|
||||
}
|
||||
|
||||
fn render_filter_footer(&mut self, pinned: bool, cx: &mut Context<Self>) -> Div {
|
||||
v_flex().flex_none().child(horizontal_separator(cx)).child(
|
||||
h_flex()
|
||||
.p_2()
|
||||
.w_full()
|
||||
.child(self.filter_editor.clone())
|
||||
.child(
|
||||
div().child(
|
||||
IconButton::new(
|
||||
"outline-panel-menu",
|
||||
if pinned {
|
||||
IconName::Unpin
|
||||
} else {
|
||||
IconName::Pin
|
||||
},
|
||||
)
|
||||
.tooltip(Tooltip::text(if pinned {
|
||||
"Unpin Outline"
|
||||
} else {
|
||||
"Pin Active Outline"
|
||||
}))
|
||||
.shape(IconButtonShape::Square)
|
||||
.on_click(cx.listener(
|
||||
|outline_panel, _, window, cx| {
|
||||
outline_panel.toggle_active_editor_pin(
|
||||
&ToggleActiveEditorPin,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
)
|
||||
let (icon, icon_tooltip) = if pinned {
|
||||
(IconName::Unpin, "Unpin Outline")
|
||||
} else {
|
||||
(IconName::Pin, "Pin Active Outline")
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.p_2()
|
||||
.h(Tab::container_height(cx))
|
||||
.justify_between()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
Icon::new(IconName::MagnifyingGlass)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(self.filter_editor.clone()),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("pin_button", icon)
|
||||
.tooltip(Tooltip::text(icon_tooltip))
|
||||
.shape(IconButtonShape::Square)
|
||||
.on_click(cx.listener(|outline_panel, _, window, cx| {
|
||||
outline_panel.toggle_active_editor_pin(&ToggleActiveEditorPin, window, cx);
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
fn buffers_inside_directory(
|
||||
@@ -4974,6 +4974,8 @@ impl Render for OutlinePanel {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let search_query_text = search_query.map(|sq| sq.query.to_string());
|
||||
|
||||
v_flex()
|
||||
.id("outline-panel")
|
||||
.size_full()
|
||||
@@ -5020,22 +5022,21 @@ impl Render for OutlinePanel {
|
||||
}),
|
||||
)
|
||||
.track_focus(&self.focus_handle)
|
||||
.when_some(search_query, |outline_panel, search_state| {
|
||||
.child(self.render_filter_footer(pinned, cx))
|
||||
.when_some(search_query_text, |outline_panel, query_text| {
|
||||
outline_panel.child(
|
||||
h_flex()
|
||||
.py_1p5()
|
||||
.px_2()
|
||||
.h(DynamicSpacing::Base32.px(cx))
|
||||
.flex_shrink_0()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.h(Tab::container_height(cx))
|
||||
.gap_0p5()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.child(Label::new("Searching:").color(Color::Muted))
|
||||
.child(Label::new(search_state.query.to_string())),
|
||||
.child(Label::new(query_text)),
|
||||
)
|
||||
})
|
||||
.child(self.render_main_contents(query, show_indent_guides, indent_size, window, cx))
|
||||
.child(self.render_filter_footer(pinned, cx))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5214,10 +5215,6 @@ fn empty_icon() -> AnyElement {
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn horizontal_separator(cx: &mut App) -> Div {
|
||||
div().mx_2().border_primary(cx).border_t_1()
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct GenerationState {
|
||||
entries: Vec<CachedEntry>,
|
||||
|
||||
Reference in New Issue
Block a user