diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index 3bb3ea9ea44efe2cf57a4d021b0a1755ac3b3681..eec55f16af8cf7deefdb8adeddeac5b6b4fb4ea9 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -677,9 +677,15 @@ impl Sidebar { label, workspace, highlight_positions, - } => { - self.render_project_header(ix, path_list, label, workspace, highlight_positions, cx) - } + } => self.render_project_header( + ix, + path_list, + label, + workspace, + highlight_positions, + is_selected, + cx, + ), ListEntry::Thread { session_info, icon, @@ -730,6 +736,7 @@ impl Sidebar { label: &SharedString, workspace: &Entity, highlight_positions: &[usize], + is_selected: bool, cx: &mut Context, ) -> AnyElement { let id = SharedString::from(format!("project-header-{}", ix)); @@ -770,6 +777,7 @@ impl Sidebar { // TODO: if is_selected, draw a blue border around the item. ListItem::new(id) + .selection_outlined(is_selected) .group_name(&group) .toggle_state(is_active_workspace) .child( @@ -1092,7 +1100,7 @@ impl Sidebar { status: AgentThreadStatus, workspace: &Entity, highlight_positions: &[usize], - _is_selected: bool, + is_selected: bool, cx: &mut Context, ) -> AnyElement { let has_notification = self.contents.is_thread_notified(&session_info.session_id); @@ -1114,6 +1122,7 @@ impl Sidebar { .status(status) .notified(has_notification) .selected(self.focused_thread.as_ref() == Some(&session_info.session_id)) + .outlined(is_selected) .on_click(cx.listener(move |this, _, window, cx| { this.selection = None; this.activate_thread(session_info.clone(), &workspace, window, cx); @@ -1159,7 +1168,7 @@ impl Sidebar { let count = format!("({})", remaining_count); ListItem::new(id) - .toggle_state(is_selected) + .selection_outlined(is_selected) .child( h_flex() .px_1() diff --git a/crates/ui/src/components/ai/thread_item.rs b/crates/ui/src/components/ai/thread_item.rs index 52d91e09824077738bde6be75122b0bf7b9e3d52..c8f5c8a41cdf74dae16a411b4fe3170b2be04bf3 100644 --- a/crates/ui/src/components/ai/thread_item.rs +++ b/crates/ui/src/components/ai/thread_item.rs @@ -24,6 +24,7 @@ pub struct ThreadItem { notified: bool, status: AgentThreadStatus, selected: bool, + outlined: bool, hovered: bool, added: Option, removed: Option, @@ -47,6 +48,7 @@ impl ThreadItem { notified: false, status: AgentThreadStatus::default(), selected: false, + outlined: false, hovered: false, added: None, removed: None, @@ -90,6 +92,11 @@ impl ThreadItem { self } + pub fn outlined(mut self, outlined: bool) -> Self { + self.outlined = outlined; + self + } + pub fn added(mut self, added: usize) -> Self { self.added = Some(added); self @@ -221,6 +228,9 @@ impl RenderOnce for ThreadItem { } }) .when(self.selected, |s| s.bg(clr.element_active)) + .border_1() + .border_color(gpui::transparent_black()) + .when(self.outlined, |s| s.border_color(clr.panel_focused_border)) .hover(|s| s.bg(clr.element_hover)) .on_hover(self.on_hover) .child( @@ -409,6 +419,29 @@ impl Component for ThreadItem { ) .into_any_element(), ), + single_example( + "Outlined Item (Keyboard Selection)", + container() + .child( + ThreadItem::new("ti-7", "Implement keyboard navigation") + .icon(IconName::AiClaude) + .timestamp("4:00 PM") + .outlined(true), + ) + .into_any_element(), + ), + single_example( + "Selected + Outlined", + container() + .child( + ThreadItem::new("ti-8", "Active and keyboard-focused thread") + .icon(IconName::AiGemini) + .timestamp("5:00 PM") + .selected(true) + .outlined(true), + ) + .into_any_element(), + ), ]; Some( diff --git a/crates/ui/src/components/list/list_item.rs b/crates/ui/src/components/list/list_item.rs index d581fad9453d9812f17b7bc9e0297fb9927c8188..cc9c955fd35aa33355be84f9ee3f17f27995ffaf 100644 --- a/crates/ui/src/components/list/list_item.rs +++ b/crates/ui/src/components/list/list_item.rs @@ -42,6 +42,7 @@ pub struct ListItem { selectable: bool, always_show_disclosure_icon: bool, outlined: bool, + selection_outlined: Option, rounded: bool, overflow_x: bool, focused: Option, @@ -71,6 +72,7 @@ impl ListItem { selectable: true, always_show_disclosure_icon: false, outlined: false, + selection_outlined: None, rounded: false, overflow_x: false, focused: None, @@ -171,6 +173,11 @@ impl ListItem { self } + pub fn selection_outlined(mut self, outlined: bool) -> Self { + self.selection_outlined = Some(outlined); + self + } + pub fn rounded(mut self) -> Self { self.rounded = true; self @@ -241,6 +248,13 @@ impl RenderOnce for ListItem { }) }) .when(self.rounded, |this| this.rounded_sm()) + .when_some(self.selection_outlined, |this, outlined| { + this.border_1() + .border_color(gpui::transparent_black()) + .when(outlined, |this| { + this.border_color(cx.theme().colors().panel_focused_border) + }) + }) .when_some(self.on_hover, |this, on_hover| this.on_hover(on_hover)) .child( h_flex()