sidebar: Add another round of refinements (#52101)

Danilo Leal created

- Change the branch button's tooltip to be more accurate given it
displays more stuff than only branches
- Hide the worktree dropdown menu when in a non-Git repo project
- Improve provisioned title truncation
- Remove the plus icon from the "view more" item to improve sidebar's
overall feel
- Remove the always visible "new thread" button but make it visible only
when you're in an empty thread state
- Add worktree icon in the thread item and tooltip with full path
- Space out the worktree name from the branch name in the git picker in
the title bar
- Swap order of views in the git picker to "worktree | branches | stash"
- Improve the "creating worktree" loading indicator

---
<!-- Check before requesting review: -->
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- N/A

Change summary

assets/icons/git_worktree.svg                         |   7 
assets/keymaps/default-linux.json                     |   4 
assets/keymaps/default-macos.json                     |   4 
assets/keymaps/default-windows.json                   |   4 
crates/agent_ui/src/agent_panel.rs                    |  65 +-
crates/agent_ui/src/conversation_view/thread_view.rs  |   2 
crates/agent_ui/src/threads_archive_view.rs           |   3 
crates/git_ui/src/branch_picker.rs                    |  26 
crates/git_ui/src/git_picker.rs                       |  38 
crates/icons/src/icons.rs                             |   1 
crates/recent_projects/src/sidebar_recent_projects.rs |   9 
crates/sidebar/src/sidebar.rs                         | 379 ++++++------
crates/title_bar/src/title_bar.rs                     |  50 +
crates/ui/src/components/ai/thread_item.rs            | 250 +++----
crates/ui/src/components/list/list_item.rs            |  29 
15 files changed, 409 insertions(+), 462 deletions(-)

Detailed changes

assets/icons/git_worktree.svg πŸ”—

@@ -0,0 +1,7 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.99567 13.0812C8.93101 13.0812 9.68925 12.3229 9.68925 11.3876C9.68925 10.4522 8.93101 9.694 7.99567 9.694C7.06033 9.694 6.30209 10.4522 6.30209 11.3876C6.30209 12.3229 7.06033 13.0812 7.99567 13.0812Z" stroke="#A9AFBC" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M4.61023 6.30643C5.54557 6.30643 6.30381 5.54819 6.30381 4.61286C6.30381 3.67752 5.54557 2.91928 4.61023 2.91928C3.6749 2.91928 2.91666 3.67752 2.91666 4.61286C2.91666 5.54819 3.6749 6.30643 4.61023 6.30643Z" stroke="#A9AFBC" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M11.3915 6.30643C12.3268 6.30643 13.0851 5.54819 13.0851 4.61286C13.0851 3.67752 12.3268 2.91928 11.3915 2.91928C10.4561 2.91928 9.69791 3.67752 9.69791 4.61286C9.69791 5.54819 10.4561 6.30643 11.3915 6.30643Z" stroke="#A9AFBC" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M11.3889 6.306V7.43505C11.3889 7.77377 11.1631 7.99958 10.8244 7.99958H5.17912C4.8404 7.99958 4.61459 7.77377 4.61459 7.43505V6.306" stroke="#A9AFBC" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8 8V9.69358" stroke="#A9AFBC" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

assets/keymaps/default-linux.json πŸ”—

@@ -1451,8 +1451,8 @@
   {
     "context": "GitPicker",
     "bindings": {
-      "alt-1": "git_picker::ActivateBranchesTab",
-      "alt-2": "git_picker::ActivateWorktreesTab",
+      "alt-1": "git_picker::ActivateWorktreesTab",
+      "alt-2": "git_picker::ActivateBranchesTab",
       "alt-3": "git_picker::ActivateStashTab",
     },
   },

assets/keymaps/default-macos.json πŸ”—

@@ -1526,8 +1526,8 @@
   {
     "context": "GitPicker",
     "bindings": {
-      "cmd-1": "git_picker::ActivateBranchesTab",
-      "cmd-2": "git_picker::ActivateWorktreesTab",
+      "cmd-1": "git_picker::ActivateWorktreesTab",
+      "cmd-2": "git_picker::ActivateBranchesTab",
       "cmd-3": "git_picker::ActivateStashTab",
     },
   },

assets/keymaps/default-windows.json πŸ”—

@@ -1440,8 +1440,8 @@
   {
     "context": "GitPicker",
     "bindings": {
-      "alt-1": "git_picker::ActivateBranchesTab",
-      "alt-2": "git_picker::ActivateWorktreesTab",
+      "alt-1": "git_picker::ActivateWorktreesTab",
+      "alt-2": "git_picker::ActivateBranchesTab",
       "alt-3": "git_picker::ActivateStashTab",
     },
   },

crates/agent_ui/src/agent_panel.rs πŸ”—

@@ -75,8 +75,8 @@ use search::{BufferSearchBar, buffer_search};
 use settings::{Settings, update_settings_file};
 use theme::ThemeSettings;
 use ui::{
-    Button, Callout, ContextMenu, ContextMenuEntry, DocumentationSide, KeyBinding, PopoverMenu,
-    PopoverMenuHandle, SpinnerLabel, Tab, Tooltip, prelude::*, utils::WithRemSize,
+    Button, Callout, CommonAnimationExt, ContextMenu, ContextMenuEntry, DocumentationSide,
+    KeyBinding, PopoverMenu, PopoverMenuHandle, Tab, Tooltip, prelude::*, utils::WithRemSize,
 };
 use util::{ResultExt as _, debug_panic};
 use workspace::{
@@ -2302,7 +2302,13 @@ impl AgentPanel {
         let default = AgentSettings::get_global(cx).new_thread_location;
         let start_thread_in = match default {
             NewThreadLocation::LocalProject => StartThreadIn::LocalProject,
-            NewThreadLocation::NewWorktree => StartThreadIn::NewWorktree,
+            NewThreadLocation::NewWorktree => {
+                if self.project_has_git_repository(cx) {
+                    StartThreadIn::NewWorktree
+                } else {
+                    StartThreadIn::LocalProject
+                }
+            }
         };
         if self.start_thread_in != start_thread_in {
             self.start_thread_in = start_thread_in;
@@ -4053,9 +4059,10 @@ impl AgentPanel {
                         .gap(DynamicSpacing::Base04.rems(cx))
                         .pl(DynamicSpacing::Base04.rems(cx))
                         .child(agent_selector_menu)
-                        .when(has_visible_worktrees, |this| {
-                            this.child(self.render_start_thread_in_selector(cx))
-                        }),
+                        .when(
+                            has_visible_worktrees && self.project_has_git_repository(cx),
+                            |this| this.child(self.render_start_thread_in_selector(cx)),
+                        ),
                 )
                 .child(
                     h_flex()
@@ -4134,41 +4141,31 @@ impl AgentPanel {
         match status {
             WorktreeCreationStatus::Creating => Some(
                 h_flex()
+                    .absolute()
+                    .bottom_12()
                     .w_full()
-                    .px(DynamicSpacing::Base06.rems(cx))
-                    .py(DynamicSpacing::Base02.rems(cx))
-                    .gap_2()
-                    .bg(cx.theme().colors().surface_background)
-                    .border_b_1()
-                    .border_color(cx.theme().colors().border)
-                    .child(SpinnerLabel::new().size(LabelSize::Small))
+                    .p_2()
+                    .gap_1()
+                    .justify_center()
+                    .bg(cx.theme().colors().editor_background)
+                    .child(
+                        Icon::new(IconName::LoadCircle)
+                            .size(IconSize::Small)
+                            .color(Color::Muted)
+                            .with_rotate_animation(3),
+                    )
                     .child(
-                        Label::new("Creating worktree…")
+                        Label::new("Creating Worktree…")
                             .color(Color::Muted)
                             .size(LabelSize::Small),
                     )
                     .into_any_element(),
             ),
             WorktreeCreationStatus::Error(message) => Some(
-                h_flex()
-                    .w_full()
-                    .px(DynamicSpacing::Base06.rems(cx))
-                    .py(DynamicSpacing::Base02.rems(cx))
-                    .gap_2()
-                    .bg(cx.theme().colors().surface_background)
-                    .border_b_1()
-                    .border_color(cx.theme().colors().border)
-                    .child(
-                        Icon::new(IconName::Warning)
-                            .size(IconSize::Small)
-                            .color(Color::Warning),
-                    )
-                    .child(
-                        Label::new(message.clone())
-                            .color(Color::Warning)
-                            .size(LabelSize::Small)
-                            .truncate(),
-                    )
+                Callout::new()
+                    .icon(IconName::Warning)
+                    .severity(Severity::Warning)
+                    .title(message.clone())
                     .into_any_element(),
             ),
         }
@@ -4611,7 +4608,6 @@ impl Render for AgentPanel {
                 }
             }))
             .child(self.render_toolbar(window, cx))
-            .children(self.render_worktree_creation_status(cx))
             .children(self.render_workspace_trust_message(cx))
             .children(self.render_onboarding(window, cx))
             .map(|parent| {
@@ -4668,6 +4664,7 @@ impl Render for AgentPanel {
                     ActiveView::Configuration => parent.children(self.configuration.clone()),
                 }
             })
+            .children(self.render_worktree_creation_status(cx))
             .children(self.render_trial_end_upsell(window, cx));
 
         match self.active_view.which_font_size_used() {

crates/agent_ui/src/conversation_view/thread_view.rs πŸ”—

@@ -1066,7 +1066,7 @@ impl ThreadView {
                     .join(" ");
                 let text = text.lines().next().unwrap_or("").trim();
                 if !text.is_empty() {
-                    let title: SharedString = util::truncate_and_trailoff(text, 20).into();
+                    let title: SharedString = util::truncate_and_trailoff(text, 200).into();
                     thread.update(cx, |thread, cx| {
                         thread.set_provisional_title(title, cx);
                     })?;

crates/agent_ui/src/threads_archive_view.rs πŸ”—

@@ -575,7 +575,7 @@ impl ThreadsArchiveView {
                                                 .when(can_unarchive, |this| {
                                                     this.child(
                                                         Button::new("unarchive-thread", "Restore")
-                                                            .style(ButtonStyle::OutlinedGhost)
+                                                            .style(ButtonStyle::Filled)
                                                             .label_size(LabelSize::Small)
                                                             .when(is_focused, |this| {
                                                                 this.key_binding(
@@ -606,6 +606,7 @@ impl ThreadsArchiveView {
                                                             "delete-thread",
                                                             IconName::Trash,
                                                         )
+                                                        .style(ButtonStyle::Filled)
                                                         .icon_size(IconSize::Small)
                                                         .icon_color(Color::Muted)
                                                         .tooltip({

crates/git_ui/src/branch_picker.rs πŸ”—

@@ -16,10 +16,7 @@ use project::project_settings::ProjectSettings;
 use settings::Settings;
 use std::sync::Arc;
 use time::OffsetDateTime;
-use ui::{
-    Divider, HighlightedLabel, KeyBinding, ListHeader, ListItem, ListItemSpacing, Tooltip,
-    prelude::*,
-};
+use ui::{Divider, HighlightedLabel, KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*};
 use ui_input::ErasedEditor;
 use util::ResultExt;
 use workspace::notifications::DetachAndPromptErr;
@@ -1084,21 +1081,6 @@ impl PickerDelegate for BranchListDelegate {
         )
     }
 
-    fn render_header(
-        &self,
-        _window: &mut Window,
-        _cx: &mut Context<Picker<Self>>,
-    ) -> Option<AnyElement> {
-        matches!(self.state, PickerState::List).then(|| {
-            let label = match self.branch_filter {
-                BranchFilter::All => "Branches",
-                BranchFilter::Remote => "Remotes",
-            };
-
-            ListHeader::new(label).inset(true).into_any_element()
-        })
-    }
-
     fn render_footer(&self, _: &mut Window, cx: &mut Context<Picker<Self>>) -> Option<AnyElement> {
         if self.editor_position() == PickerEditorPosition::End {
             return None;
@@ -1193,7 +1175,11 @@ impl PickerDelegate for BranchListDelegate {
                                 this.justify_between()
                                     .child({
                                         let focus_handle = focus_handle.clone();
-                                        Button::new("filter-remotes", "Filter Remotes")
+                                        let filter_label = match self.branch_filter {
+                                            BranchFilter::All => "Filter Remote",
+                                            BranchFilter::Remote => "Show All",
+                                        };
+                                        Button::new("filter-remotes", filter_label)
                                             .toggle_state(matches!(
                                                 self.branch_filter,
                                                 BranchFilter::Remote

crates/git_ui/src/git_picker.rs πŸ”—

@@ -25,8 +25,8 @@ actions!(
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum GitPickerTab {
-    Branches,
     Worktrees,
+    Branches,
     Stash,
 }
 
@@ -190,9 +190,9 @@ impl GitPicker {
 
     fn activate_next_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.tab = match self.tab {
-            GitPickerTab::Branches => GitPickerTab::Worktrees,
-            GitPickerTab::Worktrees => GitPickerTab::Stash,
-            GitPickerTab::Stash => GitPickerTab::Branches,
+            GitPickerTab::Worktrees => GitPickerTab::Branches,
+            GitPickerTab::Branches => GitPickerTab::Stash,
+            GitPickerTab::Stash => GitPickerTab::Worktrees,
         };
         self.ensure_active_picker(window, cx);
         self.focus_active_picker(window, cx);
@@ -201,9 +201,9 @@ impl GitPicker {
 
     fn activate_previous_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.tab = match self.tab {
-            GitPickerTab::Branches => GitPickerTab::Stash,
-            GitPickerTab::Worktrees => GitPickerTab::Branches,
-            GitPickerTab::Stash => GitPickerTab::Worktrees,
+            GitPickerTab::Worktrees => GitPickerTab::Stash,
+            GitPickerTab::Branches => GitPickerTab::Worktrees,
+            GitPickerTab::Stash => GitPickerTab::Branches,
         };
         self.ensure_active_picker(window, cx);
         self.focus_active_picker(window, cx);
@@ -241,9 +241,9 @@ impl GitPicker {
                 "git-picker-tabs",
                 [
                     ToggleButtonSimple::new(
-                        GitPickerTab::Branches.to_string(),
+                        GitPickerTab::Worktrees.to_string(),
                         cx.listener(|this, _, window, cx| {
-                            this.tab = GitPickerTab::Branches;
+                            this.tab = GitPickerTab::Worktrees;
                             this.ensure_active_picker(window, cx);
                             this.focus_active_picker(window, cx);
                             cx.notify();
@@ -251,16 +251,16 @@ impl GitPicker {
                     )
                     .tooltip(move |_, cx| {
                         Tooltip::for_action_in(
-                            "Toggle Branch Picker",
-                            &ActivateBranchesTab,
-                            &branches_focus_handle,
+                            "Toggle Worktree Picker",
+                            &ActivateWorktreesTab,
+                            &worktrees_focus_handle,
                             cx,
                         )
                     }),
                     ToggleButtonSimple::new(
-                        GitPickerTab::Worktrees.to_string(),
+                        GitPickerTab::Branches.to_string(),
                         cx.listener(|this, _, window, cx| {
-                            this.tab = GitPickerTab::Worktrees;
+                            this.tab = GitPickerTab::Branches;
                             this.ensure_active_picker(window, cx);
                             this.focus_active_picker(window, cx);
                             cx.notify();
@@ -268,9 +268,9 @@ impl GitPicker {
                     )
                     .tooltip(move |_, cx| {
                         Tooltip::for_action_in(
-                            "Toggle Worktree Picker",
-                            &ActivateWorktreesTab,
-                            &worktrees_focus_handle,
+                            "Toggle Branch Picker",
+                            &ActivateBranchesTab,
+                            &branches_focus_handle,
                             cx,
                         )
                     }),
@@ -297,8 +297,8 @@ impl GitPicker {
             .style(ToggleButtonGroupStyle::Outlined)
             .auto_width()
             .selected_index(match self.tab {
-                GitPickerTab::Branches => 0,
-                GitPickerTab::Worktrees => 1,
+                GitPickerTab::Worktrees => 0,
+                GitPickerTab::Branches => 1,
                 GitPickerTab::Stash => 2,
             }),
         )

crates/recent_projects/src/sidebar_recent_projects.rs πŸ”—

@@ -47,6 +47,7 @@ impl SidebarRecentProjects {
                 workspaces: Vec::new(),
                 filtered_workspaces: Vec::new(),
                 selected_index: 0,
+                has_any_non_local_projects: false,
                 focus_handle: cx.focus_handle(),
             };
 
@@ -122,6 +123,7 @@ pub struct SidebarRecentProjectsDelegate {
     )>,
     filtered_workspaces: Vec<StringMatch>,
     selected_index: usize,
+    has_any_non_local_projects: bool,
     focus_handle: FocusHandle,
 }
 
@@ -135,6 +137,9 @@ impl SidebarRecentProjectsDelegate {
             DateTime<Utc>,
         )>,
     ) {
+        self.has_any_non_local_projects = workspaces
+            .iter()
+            .any(|(_, location, _, _)| !matches!(location, SerializedWorkspaceLocation::Local));
         self.workspaces = workspaces;
     }
 }
@@ -383,7 +388,9 @@ impl PickerDelegate for SidebarRecentProjectsDelegate {
                     h_flex()
                         .gap_3()
                         .flex_grow()
-                        .child(Icon::new(icon).color(Color::Muted))
+                        .when(self.has_any_non_local_projects, |this| {
+                            this.child(Icon::new(icon).color(Color::Muted))
+                        })
                         .child(highlighted_match.render(window, cx)),
                 )
                 .tooltip(Tooltip::text(tooltip_path))

crates/sidebar/src/sidebar.rs πŸ”—

@@ -29,8 +29,7 @@ use std::sync::Arc;
 use theme::ActiveTheme;
 use ui::{
     AgentThreadStatus, CommonAnimationExt, ContextMenu, Divider, HighlightedLabel, KeyBinding,
-    ListItem, PopoverMenu, PopoverMenuHandle, Tab, ThreadItem, TintColor, Tooltip, WithScrollbar,
-    prelude::*,
+    PopoverMenu, PopoverMenuHandle, Tab, ThreadItem, TintColor, Tooltip, WithScrollbar, prelude::*,
 };
 use util::ResultExt as _;
 use util::path_list::PathList;
@@ -110,6 +109,7 @@ struct ThreadEntry {
     is_title_generating: bool,
     highlight_positions: Vec<usize>,
     worktree_name: Option<SharedString>,
+    worktree_full_path: Option<SharedString>,
     worktree_highlight_positions: Vec<usize>,
     diff_stats: DiffStats,
 }
@@ -127,7 +127,6 @@ enum ListEntry {
     Thread(ThreadEntry),
     ViewMore {
         path_list: PathList,
-        remaining_count: usize,
         is_fully_expanded: bool,
     },
     NewThread {
@@ -599,6 +598,19 @@ impl Sidebar {
 
         let query = self.filter_editor.read(cx).text(cx);
 
+        // Re-derive agent_panel_visible from the active workspace so it stays
+        // correct after workspace switches.
+        self.agent_panel_visible = active_workspace
+            .as_ref()
+            .map_or(false, |ws| AgentPanel::is_visible(ws, cx));
+
+        // Derive active_thread_is_draft BEFORE focused_thread so we can
+        // use it as a guard below.
+        self.active_thread_is_draft = active_workspace
+            .as_ref()
+            .and_then(|ws| ws.read(cx).panel::<AgentPanel>(cx))
+            .map_or(false, |panel| panel.read(cx).active_thread_is_draft(cx));
+
         // Derive focused_thread from the active workspace's agent panel.
         // Only update when the panel gives us a positive signal β€” if the
         // panel returns None (e.g. still loading after a thread activation),
@@ -612,21 +624,10 @@ impl Sidebar {
                     .active_conversation()
                     .and_then(|cv| cv.read(cx).parent_id(cx))
             });
-        if panel_focused.is_some() {
+        if panel_focused.is_some() && !self.active_thread_is_draft {
             self.focused_thread = panel_focused;
         }
 
-        // Re-derive agent_panel_visible from the active workspace so it stays
-        // correct after workspace switches.
-        self.agent_panel_visible = active_workspace
-            .as_ref()
-            .map_or(false, |ws| AgentPanel::is_visible(ws, cx));
-
-        self.active_thread_is_draft = active_workspace
-            .as_ref()
-            .and_then(|ws| ws.read(cx).panel::<AgentPanel>(cx))
-            .map_or(false, |panel| panel.read(cx).active_thread_is_draft(cx));
-
         let previous = mem::take(&mut self.contents);
 
         let old_statuses: HashMap<acp::SessionId, AgentThreadStatus> = previous
@@ -756,6 +757,7 @@ impl Sidebar {
                         is_title_generating: false,
                         highlight_positions: Vec::new(),
                         worktree_name: None,
+                        worktree_full_path: None,
                         worktree_highlight_positions: Vec::new(),
                         diff_stats: DiffStats::default(),
                     });
@@ -842,6 +844,9 @@ impl Sidebar {
                                 is_title_generating: false,
                                 highlight_positions: Vec::new(),
                                 worktree_name: Some(worktree_name.clone()),
+                                worktree_full_path: Some(
+                                    worktree_path.display().to_string().into(),
+                                ),
                                 worktree_highlight_positions: Vec::new(),
                                 diff_stats: DiffStats::default(),
                             });
@@ -886,9 +891,7 @@ impl Sidebar {
                         ThreadEntryWorkspace::Closed(_) => false,
                     };
 
-                    if thread.is_background && thread.status == AgentThreadStatus::Completed {
-                        notified_threads.insert(session_id.clone());
-                    } else if thread.status == AgentThreadStatus::Completed
+                    if thread.status == AgentThreadStatus::Completed
                         && !is_thread_workspace_active
                         && old_statuses.get(session_id) == Some(&AgentThreadStatus::Running)
                     {
@@ -965,6 +968,16 @@ impl Sidebar {
                     entries.push(thread.into());
                 }
             } else {
+                let thread_count = threads.len();
+                let is_draft_for_workspace = self.agent_panel_visible
+                    && self.active_thread_is_draft
+                    && self.focused_thread.is_none()
+                    && active_workspace
+                        .as_ref()
+                        .is_some_and(|active| active == workspace);
+
+                let show_new_thread_entry = thread_count == 0 || is_draft_for_workspace;
+
                 project_header_indices.push(entries.len());
                 entries.push(ListEntry::ProjectHeader {
                     path_list: path_list.clone(),
@@ -979,10 +992,12 @@ impl Sidebar {
                     continue;
                 }
 
-                entries.push(ListEntry::NewThread {
-                    path_list: path_list.clone(),
-                    workspace: workspace.clone(),
-                });
+                if show_new_thread_entry {
+                    entries.push(ListEntry::NewThread {
+                        path_list: path_list.clone(),
+                        workspace: workspace.clone(),
+                    });
+                }
 
                 let total = threads.len();
 
@@ -1027,7 +1042,6 @@ impl Sidebar {
                 if total > DEFAULT_THREADS_SHOWN {
                     entries.push(ListEntry::ViewMore {
                         path_list: path_list.clone(),
-                        remaining_count: total.saturating_sub(visible),
                         is_fully_expanded,
                     });
                 }
@@ -1126,16 +1140,8 @@ impl Sidebar {
             ListEntry::Thread(thread) => self.render_thread(ix, thread, is_selected, cx),
             ListEntry::ViewMore {
                 path_list,
-                remaining_count,
                 is_fully_expanded,
-            } => self.render_view_more(
-                ix,
-                path_list,
-                *remaining_count,
-                *is_fully_expanded,
-                is_selected,
-                cx,
-            ),
+            } => self.render_view_more(ix, path_list, *is_fully_expanded, is_selected, cx),
             ListEntry::NewThread {
                 path_list,
                 workspace,
@@ -1178,6 +1184,13 @@ impl Sidebar {
             IconName::ChevronDown
         };
 
+        let has_new_thread_entry = self
+            .contents
+            .entries
+            .get(ix + 1)
+            .is_some_and(|entry| matches!(entry, ListEntry::NewThread { .. }));
+        let show_new_thread_button = !has_new_thread_entry && !self.has_filter_query(cx);
+
         let workspace_for_remove = workspace.clone();
         let workspace_for_menu = workspace.clone();
 
@@ -1200,10 +1213,27 @@ impl Sidebar {
                 .into_any_element()
         };
 
-        ListItem::new(id)
-            .height(Tab::content_height(cx))
-            .group_name(group_name)
-            .focused(is_selected)
+        let color = cx.theme().colors();
+        let hover_color = color
+            .element_active
+            .blend(color.element_background.opacity(0.2));
+
+        h_flex()
+            .id(id)
+            .group(&group_name)
+            .h(Tab::content_height(cx))
+            .w_full()
+            .px_1p5()
+            .border_1()
+            .map(|this| {
+                if is_selected {
+                    this.border_color(color.border_focused)
+                } else {
+                    this.border_color(gpui::transparent_black())
+                }
+            })
+            .justify_between()
+            .hover(|s| s.bg(hover_color))
             .child(
                 h_flex()
                     .relative()
@@ -1214,7 +1244,7 @@ impl Sidebar {
                         h_flex().size_4().flex_none().justify_center().child(
                             Icon::new(disclosure_icon)
                                 .size(IconSize::Small)
-                                .color(Color::Custom(cx.theme().colors().icon_muted.opacity(0.6))),
+                                .color(Color::Custom(cx.theme().colors().icon_muted.opacity(0.5))),
                         ),
                     )
                     .child(label)
@@ -1244,11 +1274,13 @@ impl Sidebar {
                         )
                     }),
             )
-            .end_hover_gradient_overlay(true)
-            .end_slot({
+            .child({
+                let workspace_for_new_thread = workspace.clone();
+                let path_list_for_new_thread = path_list.clone();
+
                 h_flex()
                     .when(self.project_header_menu_ix != Some(ix), |this| {
-                        this.visible_on_hover("list_item")
+                        this.visible_on_hover(group_name)
                     })
                     .on_mouse_down(gpui::MouseButton::Left, |_, _, cx| {
                         cx.stop_propagation();
@@ -1300,6 +1332,30 @@ impl Sidebar {
                             )),
                         )
                     })
+                    .when(show_new_thread_button, |this| {
+                        this.child(
+                            IconButton::new(
+                                SharedString::from(format!(
+                                    "{id_prefix}project-header-new-thread-{ix}",
+                                )),
+                                IconName::Plus,
+                            )
+                            .icon_size(IconSize::Small)
+                            .icon_color(Color::Muted)
+                            .tooltip(Tooltip::text("New Thread"))
+                            .on_click(cx.listener({
+                                let workspace_for_new_thread = workspace_for_new_thread.clone();
+                                let path_list_for_new_thread = path_list_for_new_thread.clone();
+                                move |this, _, window, cx| {
+                                    // Uncollapse the group if collapsed so
+                                    // the new-thread entry becomes visible.
+                                    this.collapsed_groups.remove(&path_list_for_new_thread);
+                                    this.selection = None;
+                                    this.create_new_thread(&workspace_for_new_thread, window, cx);
+                                }
+                            })),
+                        )
+                    })
             })
             .on_click(cx.listener(move |this, _, window, cx| {
                 this.selection = None;
@@ -1513,7 +1569,7 @@ impl Sidebar {
         let color = cx.theme().colors();
         let background = color
             .title_bar_background
-            .blend(color.panel_background.opacity(0.8));
+            .blend(color.panel_background.opacity(0.2));
 
         let element = v_flex()
             .absolute()
@@ -2348,17 +2404,21 @@ impl Sidebar {
 
         ThreadItem::new(id, title)
             .icon(thread.icon)
+            .status(thread.status)
             .when_some(thread.icon_from_external_svg.clone(), |this, svg| {
                 this.custom_icon_from_external_svg(svg)
             })
             .when_some(thread.worktree_name.clone(), |this, name| {
-                this.worktree(name)
+                let this = this.worktree(name);
+                match thread.worktree_full_path.clone() {
+                    Some(path) => this.worktree_full_path(path),
+                    None => this,
+                }
             })
             .worktree_highlight_positions(thread.worktree_highlight_positions.clone())
             .when_some(timestamp, |this, ts| this.timestamp(ts))
             .highlight_positions(thread.highlight_positions.to_vec())
-            .status(thread.status)
-            .generating_title(thread.is_title_generating)
+            .title_generating(thread.is_title_generating)
             .notified(has_notification)
             .when(thread.diff_stats.lines_added > 0, |this| {
                 this.added(thread.diff_stats.lines_added as usize)
@@ -2521,7 +2581,6 @@ impl Sidebar {
         &self,
         ix: usize,
         path_list: &PathList,
-        remaining_count: usize,
         is_fully_expanded: bool,
         is_selected: bool,
         cx: &mut Context<Self>,
@@ -2529,23 +2588,15 @@ impl Sidebar {
         let path_list = path_list.clone();
         let id = SharedString::from(format!("view-more-{}", ix));
 
-        let icon = if is_fully_expanded {
-            IconName::ListCollapse
-        } else {
-            IconName::Plus
-        };
-
         let label: SharedString = if is_fully_expanded {
             "Collapse".into()
-        } else if remaining_count > 0 {
-            format!("View More ({})", remaining_count).into()
         } else {
             "View More".into()
         };
 
         ThreadItem::new(id, label)
-            .icon(icon)
             .focused(is_selected)
+            .icon_visible(false)
             .title_label_color(Color::Muted)
             .on_click(cx.listener(move |this, _, _window, cx| {
                 this.selection = None;
@@ -2650,9 +2701,9 @@ impl Sidebar {
 
         let thread_item = ThreadItem::new(id, label)
             .icon(IconName::Plus)
+            .icon_color(Color::Custom(cx.theme().colors().icon_muted.opacity(0.8)))
             .selected(is_active)
             .focused(is_selected)
-            .title_label_color(Color::Custom(cx.theme().colors().text.opacity(0.85)))
             .when(!is_active, |this| {
                 this.on_click(cx.listener(move |this, _, window, cx| {
                     this.selection = None;
@@ -2927,11 +2978,11 @@ impl Render for Sidebar {
         let _titlebar_height = ui::utils::platform_title_bar_height(window);
         let ui_font = theme::setup_ui_font(window, cx);
         let sticky_header = self.render_sticky_header(window, cx);
-        let bg = cx
-            .theme()
-            .colors()
+
+        let color = cx.theme().colors();
+        let bg = color
             .title_bar_background
-            .blend(cx.theme().colors().panel_background.opacity(0.8));
+            .blend(color.panel_background.opacity(0.32));
 
         let no_open_projects = !self.contents.has_open_projects;
         let no_search_results = self.contents.entries.is_empty();
@@ -2965,7 +3016,7 @@ impl Render for Sidebar {
             .w(self.width)
             .bg(bg)
             .border_r_1()
-            .border_color(cx.theme().colors().border)
+            .border_color(color.border)
             .map(|this| match &self.view {
                 SidebarView::ThreadList => this
                     .child(self.render_sidebar_header(no_open_projects, window, cx))
@@ -3240,14 +3291,12 @@ mod tests {
                             )
                         }
                         ListEntry::ViewMore {
-                            remaining_count,
-                            is_fully_expanded,
-                            ..
+                            is_fully_expanded, ..
                         } => {
                             if *is_fully_expanded {
                                 format!("  - Collapse{}", selected)
                             } else {
-                                format!("  + View More ({}){}", remaining_count, selected)
+                                format!("  + View More{}", selected)
                             }
                         }
                         ListEntry::NewThread { .. } => {
@@ -3345,7 +3394,6 @@ mod tests {
             visible_entries_as_strings(&sidebar, cx),
             vec![
                 "v [my-project]",
-                "  [+ New Thread]",
                 "  Fix crash in project panel",
                 "  Add inline diff view",
             ]
@@ -3377,7 +3425,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [project-a]", "  [+ New Thread]", "  Thread A1"]
+            vec!["v [project-a]", "  Thread A1"]
         );
 
         // Add a second workspace
@@ -3388,7 +3436,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [project-a]", "  [+ New Thread]", "  Thread A1",]
+            vec!["v [project-a]", "  Thread A1",]
         );
 
         // Remove the second workspace
@@ -3399,7 +3447,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [project-a]", "  [+ New Thread]", "  Thread A1"]
+            vec!["v [project-a]", "  Thread A1"]
         );
     }
 
@@ -3420,13 +3468,12 @@ mod tests {
             visible_entries_as_strings(&sidebar, cx),
             vec![
                 "v [my-project]",
-                "  [+ New Thread]",
                 "  Thread 12",
                 "  Thread 11",
                 "  Thread 10",
                 "  Thread 9",
                 "  Thread 8",
-                "  + View More (7)",
+                "  + View More",
             ]
         );
     }
@@ -3445,23 +3492,23 @@ mod tests {
         multi_workspace.update_in(cx, |_, _window, cx| cx.notify());
         cx.run_until_parked();
 
-        // Initially shows NewThread + 5 threads + View More (12 remaining)
+        // Initially shows 5 threads + View More
         let entries = visible_entries_as_strings(&sidebar, cx);
-        assert_eq!(entries.len(), 8); // header + NewThread + 5 threads + View More
-        assert!(entries.iter().any(|e| e.contains("View More (12)")));
+        assert_eq!(entries.len(), 7); // header + 5 threads + View More
+        assert!(entries.iter().any(|e| e.contains("View More")));
 
         // Focus and navigate to View More, then confirm to expand by one batch
         open_and_focus_sidebar(&sidebar, cx);
-        for _ in 0..8 {
+        for _ in 0..7 {
             cx.dispatch_action(SelectNext);
         }
         cx.dispatch_action(Confirm);
         cx.run_until_parked();
 
-        // Now shows NewThread + 10 threads + View More (7 remaining)
+        // Now shows 10 threads + View More
         let entries = visible_entries_as_strings(&sidebar, cx);
-        assert_eq!(entries.len(), 13); // header + NewThread + 10 threads + View More
-        assert!(entries.iter().any(|e| e.contains("View More (7)")));
+        assert_eq!(entries.len(), 12); // header + 10 threads + View More
+        assert!(entries.iter().any(|e| e.contains("View More")));
 
         // Expand again by one batch
         sidebar.update_in(cx, |s, _window, cx| {
@@ -3471,10 +3518,10 @@ mod tests {
         });
         cx.run_until_parked();
 
-        // Now shows NewThread + 15 threads + View More (2 remaining)
+        // Now shows 15 threads + View More
         let entries = visible_entries_as_strings(&sidebar, cx);
-        assert_eq!(entries.len(), 18); // header + NewThread + 15 threads + View More
-        assert!(entries.iter().any(|e| e.contains("View More (2)")));
+        assert_eq!(entries.len(), 17); // header + 15 threads + View More
+        assert!(entries.iter().any(|e| e.contains("View More")));
 
         // Expand one more time - should show all 17 threads with Collapse button
         sidebar.update_in(cx, |s, _window, cx| {
@@ -3486,7 +3533,7 @@ mod tests {
 
         // All 17 threads shown with Collapse button
         let entries = visible_entries_as_strings(&sidebar, cx);
-        assert_eq!(entries.len(), 20); // header + NewThread + 17 threads + Collapse
+        assert_eq!(entries.len(), 19); // header + 17 threads + Collapse
         assert!(!entries.iter().any(|e| e.contains("View More")));
         assert!(entries.iter().any(|e| e.contains("Collapse")));
 
@@ -3497,10 +3544,10 @@ mod tests {
         });
         cx.run_until_parked();
 
-        // Back to initial state: NewThread + 5 threads + View More (12 remaining)
+        // Back to initial state: 5 threads + View More
         let entries = visible_entries_as_strings(&sidebar, cx);
-        assert_eq!(entries.len(), 8); // header + NewThread + 5 threads + View More
-        assert!(entries.iter().any(|e| e.contains("View More (12)")));
+        assert_eq!(entries.len(), 7); // header + 5 threads + View More
+        assert!(entries.iter().any(|e| e.contains("View More")));
     }
 
     #[gpui::test]
@@ -3518,7 +3565,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [my-project]", "  [+ New Thread]", "  Thread 1"]
+            vec!["v [my-project]", "  Thread 1"]
         );
 
         // Collapse
@@ -3540,7 +3587,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [my-project]", "  [+ New Thread]", "  Thread 1"]
+            vec!["v [my-project]", "  Thread 1"]
         );
     }
 
@@ -3570,7 +3617,6 @@ mod tests {
                     has_running_threads: false,
                     waiting_thread_count: 0,
                 },
-                // Thread with default (Completed) status, not active
                 ListEntry::Thread(ThreadEntry {
                     agent: Agent::NativeAgent,
                     session_info: acp_thread::AgentSessionInfo {
@@ -3590,6 +3636,7 @@ mod tests {
                     is_title_generating: false,
                     highlight_positions: Vec::new(),
                     worktree_name: None,
+                    worktree_full_path: None,
                     worktree_highlight_positions: Vec::new(),
                     diff_stats: DiffStats::default(),
                 }),
@@ -3613,6 +3660,7 @@ mod tests {
                     is_title_generating: false,
                     highlight_positions: Vec::new(),
                     worktree_name: None,
+                    worktree_full_path: None,
                     worktree_highlight_positions: Vec::new(),
                     diff_stats: DiffStats::default(),
                 }),
@@ -3636,6 +3684,7 @@ mod tests {
                     is_title_generating: false,
                     highlight_positions: Vec::new(),
                     worktree_name: None,
+                    worktree_full_path: None,
                     worktree_highlight_positions: Vec::new(),
                     diff_stats: DiffStats::default(),
                 }),
@@ -3659,6 +3708,7 @@ mod tests {
                     is_title_generating: false,
                     highlight_positions: Vec::new(),
                     worktree_name: None,
+                    worktree_full_path: None,
                     worktree_highlight_positions: Vec::new(),
                     diff_stats: DiffStats::default(),
                 }),
@@ -3682,13 +3732,13 @@ mod tests {
                     is_title_generating: false,
                     highlight_positions: Vec::new(),
                     worktree_name: None,
+                    worktree_full_path: None,
                     worktree_highlight_positions: Vec::new(),
                     diff_stats: DiffStats::default(),
                 }),
                 // View More entry
                 ListEntry::ViewMore {
                     path_list: expanded_path.clone(),
-                    remaining_count: 42,
                     is_fully_expanded: false,
                 },
                 // Collapsed project header
@@ -3701,6 +3751,7 @@ mod tests {
                     waiting_thread_count: 0,
                 },
             ];
+
             // Select the Running thread (index 2)
             s.selection = Some(2);
         });
@@ -3714,7 +3765,7 @@ mod tests {
                 "  Error thread * (error)",
                 "  Waiting thread (waiting)",
                 "  Notified thread * (!)",
-                "  + View More (42)",
+                "  + View More",
                 "> [collapsed-project]",
             ]
         );
@@ -3758,7 +3809,7 @@ mod tests {
         multi_workspace.update_in(cx, |_, _window, cx| cx.notify());
         cx.run_until_parked();
 
-        // Entries: [header, new_thread, thread3, thread2, thread1]
+        // Entries: [header, thread3, thread2, thread1]
         // Focusing the sidebar does not set a selection; select_next/select_previous
         // handle None gracefully by starting from the first or last entry.
         open_and_focus_sidebar(&sidebar, cx);
@@ -3778,9 +3829,6 @@ mod tests {
         cx.dispatch_action(SelectNext);
         assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(3));
 
-        cx.dispatch_action(SelectNext);
-        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(4));
-
         // At the end, wraps back to first entry
         cx.dispatch_action(SelectNext);
         assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(0));
@@ -3792,13 +3840,8 @@ mod tests {
         assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(2));
         cx.dispatch_action(SelectNext);
         assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(3));
-        cx.dispatch_action(SelectNext);
-        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(4));
 
         // Move back up
-        cx.dispatch_action(SelectPrevious);
-        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(3));
-
         cx.dispatch_action(SelectPrevious);
         assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(2));
 
@@ -3829,7 +3872,7 @@ mod tests {
 
         // SelectLast jumps to the end
         cx.dispatch_action(SelectLast);
-        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(4));
+        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(3));
 
         // SelectFirst jumps to the beginning
         cx.dispatch_action(SelectFirst);
@@ -3882,7 +3925,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [my-project]", "  [+ New Thread]", "  Thread 1"]
+            vec!["v [my-project]", "  Thread 1"]
         );
 
         // Focus the sidebar and select the header (index 0)
@@ -3906,11 +3949,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [my-project]  <== selected",
-                "  [+ New Thread]",
-                "  Thread 1",
-            ]
+            vec!["v [my-project]  <== selected", "  Thread 1",]
         );
     }
 
@@ -3926,17 +3965,17 @@ mod tests {
         multi_workspace.update_in(cx, |_, _window, cx| cx.notify());
         cx.run_until_parked();
 
-        // Should show header + NewThread + 5 threads + "View More (3)"
+        // Should show header + 5 threads + "View More"
         let entries = visible_entries_as_strings(&sidebar, cx);
-        assert_eq!(entries.len(), 8);
-        assert!(entries.iter().any(|e| e.contains("View More (3)")));
+        assert_eq!(entries.len(), 7);
+        assert!(entries.iter().any(|e| e.contains("View More")));
 
-        // Focus sidebar (selection starts at None), then navigate down to the "View More" entry (index 7)
+        // Focus sidebar (selection starts at None), then navigate down to the "View More" entry (index 6)
         open_and_focus_sidebar(&sidebar, cx);
-        for _ in 0..8 {
+        for _ in 0..7 {
             cx.dispatch_action(SelectNext);
         }
-        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(7));
+        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(6));
 
         // Confirm on "View More" to expand
         cx.dispatch_action(Confirm);
@@ -3944,7 +3983,7 @@ mod tests {
 
         // All 8 threads should now be visible with a "Collapse" button
         let entries = visible_entries_as_strings(&sidebar, cx);
-        assert_eq!(entries.len(), 11); // header + NewThread + 8 threads + Collapse button
+        assert_eq!(entries.len(), 10); // header + 8 threads + Collapse button
         assert!(!entries.iter().any(|e| e.contains("View More")));
         assert!(entries.iter().any(|e| e.contains("Collapse")));
     }
@@ -3963,7 +4002,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [my-project]", "  [+ New Thread]", "  Thread 1"]
+            vec!["v [my-project]", "  Thread 1"]
         );
 
         // Focus sidebar and manually select the header (index 0). Press left to collapse.
@@ -3986,11 +4025,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [my-project]  <== selected",
-                "  [+ New Thread]",
-                "  Thread 1",
-            ]
+            vec!["v [my-project]  <== selected", "  Thread 1",]
         );
 
         // Press right again on already-expanded header moves selection down
@@ -4014,16 +4049,11 @@ mod tests {
         open_and_focus_sidebar(&sidebar, cx);
         cx.dispatch_action(SelectNext);
         cx.dispatch_action(SelectNext);
-        cx.dispatch_action(SelectNext);
-        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(2));
+        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(1));
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [my-project]",
-                "  [+ New Thread]",
-                "  Thread 1  <== selected",
-            ]
+            vec!["v [my-project]", "  Thread 1  <== selected",]
         );
 
         // Pressing left on a child collapses the parent group and selects it
@@ -4044,7 +4074,7 @@ mod tests {
             cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx));
         let sidebar = setup_sidebar(&multi_workspace, cx);
 
-        // Even an empty project has the header and a new thread button
+        // An empty project has the header and a new thread button.
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
             vec!["v [empty-project]", "  [+ New Thread]"]
@@ -4083,12 +4113,11 @@ mod tests {
         multi_workspace.update_in(cx, |_, _window, cx| cx.notify());
         cx.run_until_parked();
 
-        // Focus sidebar (selection starts at None), navigate down to the thread (index 2)
+        // Focus sidebar (selection starts at None), navigate down to the thread (index 1)
         open_and_focus_sidebar(&sidebar, cx);
         cx.dispatch_action(SelectNext);
         cx.dispatch_action(SelectNext);
-        cx.dispatch_action(SelectNext);
-        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(2));
+        assert_eq!(sidebar.read_with(cx, |s, _| s.selection), Some(1));
 
         // Collapse the group, which removes the thread from the list
         cx.dispatch_action(SelectParent);
@@ -4188,15 +4217,10 @@ mod tests {
         cx.run_until_parked();
 
         let mut entries = visible_entries_as_strings(&sidebar, cx);
-        entries[2..].sort();
+        entries[1..].sort();
         assert_eq!(
             entries,
-            vec![
-                "v [my-project]",
-                "  [+ New Thread]",
-                "  Hello *",
-                "  Hello * (running)",
-            ]
+            vec!["v [my-project]", "  Hello *", "  Hello * (running)",]
         );
     }
 
@@ -4237,7 +4261,7 @@ mod tests {
         // Thread A is still running; no notification yet.
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [project-a]", "  [+ New Thread]", "  Hello * (running)",]
+            vec!["v [project-a]", "  Hello * (running)",]
         );
 
         // Complete thread A's turn (transition Running β†’ Completed).
@@ -4247,7 +4271,7 @@ mod tests {
         // The completed background thread shows a notification indicator.
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [project-a]", "  [+ New Thread]", "  Hello * (!)",]
+            vec!["v [project-a]", "  Hello * (!)",]
         );
     }
 
@@ -4290,7 +4314,6 @@ mod tests {
             visible_entries_as_strings(&sidebar, cx),
             vec![
                 "v [my-project]",
-                "  [+ New Thread]",
                 "  Fix crash in project panel",
                 "  Add inline diff view",
                 "  Refactor settings module",
@@ -4381,12 +4404,7 @@ mod tests {
         // Confirm the full list is showing.
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [my-project]",
-                "  [+ New Thread]",
-                "  Alpha thread",
-                "  Beta thread",
-            ]
+            vec!["v [my-project]", "  Alpha thread", "  Beta thread",]
         );
 
         // User types a search query to filter down.
@@ -4398,16 +4416,14 @@ mod tests {
         );
 
         // User presses Escape β€” filter clears, full list is restored.
-        // The selection index (1) now points at the NewThread entry that was
-        // re-inserted when the filter was removed.
+        // The selection index (1) now points at the first thread entry.
         cx.dispatch_action(Cancel);
         cx.run_until_parked();
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
             vec![
                 "v [my-project]",
-                "  [+ New Thread]  <== selected",
-                "  Alpha thread",
+                "  Alpha thread  <== selected",
                 "  Beta thread",
             ]
         );
@@ -4463,7 +4479,6 @@ mod tests {
             visible_entries_as_strings(&sidebar, cx),
             vec![
                 "v [project-a]",
-                "  [+ New Thread]",
                 "  Fix bug in sidebar",
                 "  Add tests for editor",
             ]
@@ -4781,7 +4796,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [my-project]", "  [+ New Thread]", "  Historical Thread",]
+            vec!["v [my-project]", "  Historical Thread",]
         );
 
         // Switch to workspace 1 so we can verify the confirm switches back.
@@ -4843,22 +4858,17 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [my-project]",
-                "  [+ New Thread]",
-                "  Thread A",
-                "  Thread B",
-            ]
+            vec!["v [my-project]", "  Thread A", "  Thread B",]
         );
 
         // Keyboard confirm preserves selection.
         sidebar.update_in(cx, |sidebar, window, cx| {
-            sidebar.selection = Some(2);
+            sidebar.selection = Some(1);
             sidebar.confirm(&Confirm, window, cx);
         });
         assert_eq!(
             sidebar.read_with(cx, |sidebar, _| sidebar.selection),
-            Some(2)
+            Some(1)
         );
 
         // Click handlers clear selection to None so no highlight lingers
@@ -4901,7 +4911,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [my-project]", "  [+ New Thread]", "  Hello *"]
+            vec!["v [my-project]", "  Hello *"]
         );
 
         // Simulate the agent generating a title. The notification chain is:
@@ -4923,11 +4933,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [my-project]",
-                "  [+ New Thread]",
-                "  Friendly Greeting with AI *"
-            ]
+            vec!["v [my-project]", "  Friendly Greeting with AI *"]
         );
     }
 
@@ -5179,7 +5185,7 @@ mod tests {
         // Verify the thread appears in the sidebar.
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec!["v [project-a]", "  [+ New Thread]", "  Hello *",]
+            vec!["v [project-a]", "  Hello *",]
         );
 
         // The "New Thread" button should NOT be in "active/draft" state
@@ -5340,11 +5346,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [project]",
-                "  [+ New Thread]",
-                "  Worktree Thread {rosewood}",
-            ]
+            vec!["v [project]", "  Worktree Thread {rosewood}",]
         );
     }
 
@@ -5421,10 +5423,8 @@ mod tests {
             visible_entries_as_strings(&sidebar, cx),
             vec![
                 "v [wt-feature-a]",
-                "  [+ New Thread]",
                 "  Thread A",
                 "v [wt-feature-b]",
-                "  [+ New Thread]",
                 "  Thread B",
             ]
         );
@@ -5461,7 +5461,6 @@ mod tests {
             visible_entries_as_strings(&sidebar, cx),
             vec![
                 "v [project]",
-                "  [+ New Thread]",
                 "  Thread A {wt-feature-a}",
                 "  Thread B {wt-feature-b}",
             ]
@@ -5482,11 +5481,7 @@ mod tests {
         // under the main repo.
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [project]",
-                "  [+ New Thread]",
-                "  Thread A {wt-feature-a}",
-            ]
+            vec!["v [project]", "  Thread A {wt-feature-a}",]
         );
     }
 
@@ -5603,11 +5598,7 @@ mod tests {
         let entries = visible_entries_as_strings(&sidebar, cx);
         assert_eq!(
             entries,
-            vec![
-                "v [project]",
-                "  [+ New Thread]",
-                "  Hello {wt-feature-a} * (running)",
-            ]
+            vec!["v [project]", "  Hello {wt-feature-a} * (running)",]
         );
     }
 
@@ -5706,11 +5697,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [project]",
-                "  [+ New Thread]",
-                "  Hello {wt-feature-a} * (running)",
-            ]
+            vec!["v [project]", "  Hello {wt-feature-a} * (running)",]
         );
 
         connection.end_turn(session_id, acp::StopReason::EndTurn);
@@ -5718,11 +5705,7 @@ mod tests {
 
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [project]",
-                "  [+ New Thread]",
-                "  Hello {wt-feature-a} * (!)",
-            ]
+            vec!["v [project]", "  Hello {wt-feature-a} * (!)",]
         );
     }
 
@@ -5790,11 +5773,7 @@ mod tests {
         // Thread should appear under the main repo with a worktree chip.
         assert_eq!(
             visible_entries_as_strings(&sidebar, cx),
-            vec![
-                "v [project]",
-                "  [+ New Thread]",
-                "  WT Thread {wt-feature-a}"
-            ],
+            vec!["v [project]", "  WT Thread {wt-feature-a}"],
         );
 
         // Only 1 workspace should exist.
@@ -5806,7 +5785,7 @@ mod tests {
         // Focus the sidebar and select the worktree thread.
         open_and_focus_sidebar(&sidebar, cx);
         sidebar.update_in(cx, |sidebar, _window, _cx| {
-            sidebar.selection = Some(2); // index 0 is header, 1 is NewThread, 2 is the thread
+            sidebar.selection = Some(1); // index 0 is header, 1 is the thread
         });
 
         // Confirm to open the worktree thread.

crates/title_bar/src/title_bar.rs πŸ”—

@@ -908,14 +908,7 @@ impl TitleBar {
         };
 
         let branch_name = branch_name?;
-        let button_text = if let Some(worktree_name) = linked_worktree_name {
-            format!("{}/{}", worktree_name, branch_name)
-        } else {
-            branch_name
-        };
-
         let settings = TitleBarSettings::get_global(cx);
-
         let effective_repository = Some(repository);
 
         Some(
@@ -931,21 +924,42 @@ impl TitleBar {
                     ))
                 })
                 .trigger_with_tooltip(
-                    Button::new("project_branch_trigger", button_text)
+                    ButtonLike::new("project_branch_trigger")
                         .selected_style(ButtonStyle::Tinted(TintColor::Accent))
-                        .label_size(LabelSize::Small)
-                        .color(Color::Muted)
-                        .when(settings.show_branch_icon, |branch_button| {
-                            let (icon, icon_color) = icon_info;
-                            branch_button.start_icon(
-                                Icon::new(icon).size(IconSize::Indicator).color(icon_color),
-                            )
-                        }),
+                        .child(
+                            h_flex()
+                                .gap_0p5()
+                                .when(settings.show_branch_icon, |this| {
+                                    let (icon, icon_color) = icon_info;
+                                    this.child(
+                                        Icon::new(icon).size(IconSize::XSmall).color(icon_color),
+                                    )
+                                })
+                                .when_some(linked_worktree_name.as_ref(), |this, worktree_name| {
+                                    this.child(
+                                        Label::new(worktree_name)
+                                            .size(LabelSize::Small)
+                                            .color(Color::Muted),
+                                    )
+                                    .child(
+                                        Label::new("/").size(LabelSize::Small).color(
+                                            Color::Custom(
+                                                cx.theme().colors().text_muted.opacity(0.4),
+                                            ),
+                                        ),
+                                    )
+                                })
+                                .child(
+                                    Label::new(branch_name)
+                                        .size(LabelSize::Small)
+                                        .color(Color::Muted),
+                                ),
+                        ),
                     move |_window, cx| {
                         Tooltip::with_meta(
-                            "Recent Branches",
+                            "Git Switcher",
                             Some(&zed_actions::git::Branch),
-                            "Local branches only",
+                            "Worktrees, Branches, and Stashes",
                             cx,
                         )
                     },

crates/ui/src/components/ai/thread_item.rs πŸ”—

@@ -22,25 +22,26 @@ pub enum AgentThreadStatus {
 pub struct ThreadItem {
     id: ElementId,
     icon: IconName,
+    icon_color: Option<Color>,
+    icon_visible: bool,
     custom_icon_from_external_svg: Option<SharedString>,
     title: SharedString,
+    title_label_color: Option<Color>,
+    title_generating: bool,
+    highlight_positions: Vec<usize>,
     timestamp: SharedString,
     notified: bool,
     status: AgentThreadStatus,
-    generating_title: bool,
     selected: bool,
     focused: bool,
     hovered: bool,
-    docked_right: bool,
     added: Option<usize>,
     removed: Option<usize>,
     worktree: Option<SharedString>,
-    highlight_positions: Vec<usize>,
+    worktree_full_path: Option<SharedString>,
     worktree_highlight_positions: Vec<usize>,
     on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
     on_hover: Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>,
-    title_label_color: Option<Color>,
-    title_label_size: Option<LabelSize>,
     action_slot: Option<AnyElement>,
     tooltip: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
 }
@@ -50,25 +51,26 @@ impl ThreadItem {
         Self {
             id: id.into(),
             icon: IconName::ZedAgent,
+            icon_color: None,
+            icon_visible: true,
             custom_icon_from_external_svg: None,
             title: title.into(),
+            title_label_color: None,
+            title_generating: false,
+            highlight_positions: Vec::new(),
             timestamp: "".into(),
             notified: false,
             status: AgentThreadStatus::default(),
-            generating_title: false,
             selected: false,
             focused: false,
             hovered: false,
-            docked_right: false,
             added: None,
             removed: None,
             worktree: None,
-            highlight_positions: Vec::new(),
+            worktree_full_path: None,
             worktree_highlight_positions: Vec::new(),
             on_click: None,
             on_hover: Box::new(|_, _, _| {}),
-            title_label_color: None,
-            title_label_size: None,
             action_slot: None,
             tooltip: None,
         }
@@ -84,6 +86,16 @@ impl ThreadItem {
         self
     }
 
+    pub fn icon_color(mut self, color: Color) -> Self {
+        self.icon_color = Some(color);
+        self
+    }
+
+    pub fn icon_visible(mut self, visible: bool) -> Self {
+        self.icon_visible = visible;
+        self
+    }
+
     pub fn custom_icon_from_external_svg(mut self, svg: impl Into<SharedString>) -> Self {
         self.custom_icon_from_external_svg = Some(svg.into());
         self
@@ -99,8 +111,18 @@ impl ThreadItem {
         self
     }
 
-    pub fn generating_title(mut self, generating: bool) -> Self {
-        self.generating_title = generating;
+    pub fn title_generating(mut self, generating: bool) -> Self {
+        self.title_generating = generating;
+        self
+    }
+
+    pub fn title_label_color(mut self, color: Color) -> Self {
+        self.title_label_color = Some(color);
+        self
+    }
+
+    pub fn highlight_positions(mut self, positions: Vec<usize>) -> Self {
+        self.highlight_positions = positions;
         self
     }
 
@@ -124,18 +146,13 @@ impl ThreadItem {
         self
     }
 
-    pub fn docked_right(mut self, docked_right: bool) -> Self {
-        self.docked_right = docked_right;
-        self
-    }
-
     pub fn worktree(mut self, worktree: impl Into<SharedString>) -> Self {
         self.worktree = Some(worktree.into());
         self
     }
 
-    pub fn highlight_positions(mut self, positions: Vec<usize>) -> Self {
-        self.highlight_positions = positions;
+    pub fn worktree_full_path(mut self, worktree_full_path: impl Into<SharedString>) -> Self {
+        self.worktree_full_path = Some(worktree_full_path.into());
         self
     }
 
@@ -162,16 +179,6 @@ impl ThreadItem {
         self
     }
 
-    pub fn title_label_color(mut self, color: Color) -> Self {
-        self.title_label_color = Some(color);
-        self
-    }
-
-    pub fn title_label_size(mut self, size: LabelSize) -> Self {
-        self.title_label_size = Some(size);
-        self
-    }
-
     pub fn action_slot(mut self, element: impl IntoElement) -> Self {
         self.action_slot = Some(element.into_any_element());
         self
@@ -186,6 +193,26 @@ impl ThreadItem {
 impl RenderOnce for ThreadItem {
     fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
         let color = cx.theme().colors();
+        let base_bg = color
+            .title_bar_background
+            .blend(color.panel_background.opacity(0.2));
+
+        let base_bg = if self.selected {
+            color.element_active
+        } else {
+            base_bg
+        };
+
+        let hover_color = color
+            .element_active
+            .blend(color.element_background.opacity(0.2));
+
+        let gradient_overlay = GradientFade::new(base_bg, hover_color, hover_color)
+            .width(px(64.0))
+            .right(px(-10.0))
+            .gradient_stop(0.75)
+            .group_name("thread-item");
+
         let dot_separator = || {
             Label::new("β€’")
                 .size(LabelSize::Small)
@@ -194,25 +221,26 @@ impl RenderOnce for ThreadItem {
         };
 
         let icon_id = format!("icon-{}", self.id);
+        let icon_visible = self.icon_visible;
         let icon_container = || {
             h_flex()
                 .id(icon_id.clone())
                 .size_4()
                 .flex_none()
                 .justify_center()
+                .when(!icon_visible, |this| this.invisible())
         };
+        let icon_color = self.icon_color.unwrap_or(Color::Muted);
         let agent_icon = if let Some(custom_svg) = self.custom_icon_from_external_svg {
             Icon::from_external_svg(custom_svg)
-                .color(Color::Muted)
+                .color(icon_color)
                 .size(IconSize::Small)
         } else {
-            Icon::new(self.icon)
-                .color(Color::Muted)
-                .size(IconSize::Small)
+            Icon::new(self.icon).color(icon_color).size(IconSize::Small)
         };
 
         let decoration = |icon: IconDecorationKind, color: Hsla| {
-            IconDecoration::new(icon, cx.theme().colors().surface_background, cx)
+            IconDecoration::new(icon, base_bg, cx)
                 .color(color)
                 .position(gpui::Point {
                     x: px(-2.),
@@ -264,10 +292,9 @@ impl RenderOnce for ThreadItem {
 
         let title = self.title;
         let highlight_positions = self.highlight_positions;
-        let title_label_size = self.title_label_size.unwrap_or(LabelSize::Default);
-        let title_label = if self.generating_title {
+
+        let title_label = if self.title_generating {
             Label::new(title)
-                .size(title_label_size)
                 .color(Color::Muted)
                 .with_animation(
                     "generating-title",
@@ -278,66 +305,38 @@ impl RenderOnce for ThreadItem {
                 )
                 .into_any_element()
         } else if highlight_positions.is_empty() {
-            let label = Label::new(title).size(title_label_size);
-            let label = if let Some(color) = self.title_label_color {
-                label.color(color)
-            } else {
-                label
-            };
-            label.into_any_element()
-        } else {
-            let label = HighlightedLabel::new(title, highlight_positions).size(title_label_size);
-            let label = if let Some(color) = self.title_label_color {
-                label.color(color)
-            } else {
-                label
-            };
-            label.into_any_element()
-        };
-
-        let b_bg = color
-            .title_bar_background
-            .blend(color.panel_background.opacity(0.8));
-
-        let base_bg = if self.selected {
-            color.element_active
+            Label::new(title)
+                .when_some(self.title_label_color, |label, color| label.color(color))
+                .into_any_element()
         } else {
-            b_bg
+            HighlightedLabel::new(title, highlight_positions)
+                .when_some(self.title_label_color, |label, color| label.color(color))
+                .into_any_element()
         };
 
-        let gradient_overlay =
-            GradientFade::new(base_bg, color.element_hover, color.element_active)
-                .width(px(64.0))
-                .right(px(-10.0))
-                .gradient_stop(0.75)
-                .group_name("thread-item");
-
         let has_diff_stats = self.added.is_some() || self.removed.is_some();
+        let diff_stat_id = self.id.clone();
         let added_count = self.added.unwrap_or(0);
         let removed_count = self.removed.unwrap_or(0);
-        let diff_stat_id = self.id.clone();
+
         let has_worktree = self.worktree.is_some();
         let has_timestamp = !self.timestamp.is_empty();
         let timestamp = self.timestamp;
 
         v_flex()
             .id(self.id.clone())
+            .cursor_pointer()
             .group("thread-item")
             .relative()
             .overflow_hidden()
-            .cursor_pointer()
             .w_full()
             .py_1()
             .px_1p5()
             .when(self.selected, |s| s.bg(color.element_active))
             .border_1()
             .border_color(gpui::transparent_black())
-            .when(self.focused, |s| {
-                s.when(self.docked_right, |s| s.border_r_2())
-                    .border_color(color.border_focused)
-            })
-            .hover(|s| s.bg(color.element_hover))
-            .active(|s| s.bg(color.element_active))
+            .when(self.focused, |s| s.border_color(color.border_focused))
+            .hover(|s| s.bg(hover_color))
             .on_hover(self.on_hover)
             .child(
                 h_flex()
@@ -358,15 +357,11 @@ impl RenderOnce for ThreadItem {
                     .child(gradient_overlay)
                     .when(self.hovered, |this| {
                         this.when_some(self.action_slot, |this, slot| {
-                            let overlay = GradientFade::new(
-                                base_bg,
-                                color.element_hover,
-                                color.element_active,
-                            )
-                            .width(px(64.0))
-                            .right(px(6.))
-                            .gradient_stop(0.75)
-                            .group_name("thread-item");
+                            let overlay = GradientFade::new(base_bg, hover_color, hover_color)
+                                .width(px(64.0))
+                                .right(px(6.))
+                                .gradient_stop(0.75)
+                                .group_name("thread-item");
 
                             this.child(
                                 h_flex()
@@ -380,57 +375,56 @@ impl RenderOnce for ThreadItem {
                         })
                     }),
             )
-            .when_some(self.worktree, |this, worktree| {
-                let worktree_highlight_positions = self.worktree_highlight_positions;
-                let worktree_label = if worktree_highlight_positions.is_empty() {
-                    Label::new(worktree)
-                        .size(LabelSize::Small)
-                        .color(Color::Muted)
-                        .into_any_element()
-                } else {
-                    HighlightedLabel::new(worktree, worktree_highlight_positions)
-                        .size(LabelSize::Small)
-                        .color(Color::Muted)
-                        .into_any_element()
-                };
+            .when(has_worktree || has_diff_stats || has_timestamp, |this| {
+                let worktree_full_path = self.worktree_full_path.clone().unwrap_or_default();
+                let worktree_label = self.worktree.map(|worktree| {
+                    let positions = self.worktree_highlight_positions;
+                    if positions.is_empty() {
+                        Label::new(worktree)
+                            .size(LabelSize::Small)
+                            .color(Color::Muted)
+                            .into_any_element()
+                    } else {
+                        HighlightedLabel::new(worktree, positions)
+                            .size(LabelSize::Small)
+                            .color(Color::Muted)
+                            .into_any_element()
+                    }
+                });
 
                 this.child(
                     h_flex()
                         .min_w_0()
                         .gap_1p5()
                         .child(icon_container()) // Icon Spacing
-                        .child(worktree_label)
-                        .when(has_diff_stats || has_timestamp, |this| {
-                            this.child(dot_separator())
-                        })
-                        .when(has_diff_stats, |this| {
+                        .when_some(worktree_label, |this, label| {
                             this.child(
-                                DiffStat::new(diff_stat_id.clone(), added_count, removed_count)
-                                    .tooltip("Unreviewed changes"),
+                                h_flex()
+                                    .id(format!("{}-worktree", self.id.clone()))
+                                    .gap_1()
+                                    .child(
+                                        Icon::new(IconName::GitWorktree)
+                                            .size(IconSize::XSmall)
+                                            .color(Color::Muted),
+                                    )
+                                    .child(label)
+                                    .tooltip(move |_, cx| {
+                                        Tooltip::with_meta(
+                                            "Thread Running in a Local Git Worktree",
+                                            None,
+                                            worktree_full_path.clone(),
+                                            cx,
+                                        )
+                                    }),
                             )
                         })
-                        .when(has_diff_stats && has_timestamp, |this| {
+                        .when(has_worktree && (has_diff_stats || has_timestamp), |this| {
                             this.child(dot_separator())
                         })
-                        .when(has_timestamp, |this| {
-                            this.child(
-                                Label::new(timestamp.clone())
-                                    .size(LabelSize::Small)
-                                    .color(Color::Muted),
-                            )
-                        }),
-                )
-            })
-            .when(!has_worktree && (has_diff_stats || has_timestamp), |this| {
-                this.child(
-                    h_flex()
-                        .min_w_0()
-                        .gap_1p5()
-                        .child(icon_container()) // Icon Spacing
                         .when(has_diff_stats, |this| {
                             this.child(
                                 DiffStat::new(diff_stat_id, added_count, removed_count)
-                                    .tooltip("Unreviewed Changes"),
+                                    .tooltip("Unreviewed changes"),
                             )
                         })
                         .when(has_diff_stats && has_timestamp, |this| {
@@ -583,18 +577,6 @@ impl Component for ThreadItem {
                     )
                     .into_any_element(),
             ),
-            single_example(
-                "Focused + Docked Right",
-                container()
-                    .child(
-                        ThreadItem::new("ti-7b", "Focused with right dock border")
-                            .icon(IconName::AiClaude)
-                            .timestamp("1w")
-                            .focused(true)
-                            .docked_right(true),
-                    )
-                    .into_any_element(),
-            ),
             single_example(
                 "Selected + Focused",
                 container()

crates/ui/src/components/list/list_item.rs πŸ”—

@@ -4,7 +4,7 @@ use component::{Component, ComponentScope, example_group_with_title, single_exam
 use gpui::{AnyElement, AnyView, ClickEvent, MouseButton, MouseDownEvent, Pixels, px};
 use smallvec::SmallVec;
 
-use crate::{Disclosure, GradientFade, prelude::*};
+use crate::{Disclosure, prelude::*};
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
 pub enum ListItemSpacing {
@@ -31,9 +31,6 @@ pub struct ListItem {
     /// A slot for content that appears on hover after the children
     /// It will obscure the `end_slot` when visible.
     end_hover_slot: Option<AnyElement>,
-    /// When true, renders a gradient fade overlay before the `end_hover_slot`
-    /// to smoothly truncate overflowing content.
-    end_hover_gradient_overlay: bool,
     toggle: Option<bool>,
     inset: bool,
     on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
@@ -65,7 +62,6 @@ impl ListItem {
             start_slot: None,
             end_slot: None,
             end_hover_slot: None,
-            end_hover_gradient_overlay: false,
             toggle: None,
             inset: false,
             on_click: None,
@@ -174,11 +170,6 @@ impl ListItem {
         self
     }
 
-    pub fn end_hover_gradient_overlay(mut self, show: bool) -> Self {
-        self.end_hover_gradient_overlay = show;
-        self
-    }
-
     pub fn outlined(mut self) -> Self {
         self.outlined = true;
         self
@@ -232,21 +223,6 @@ impl ParentElement for ListItem {
 
 impl RenderOnce for ListItem {
     fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
-        let color = cx.theme().colors();
-
-        let base_bg = if self.selected {
-            color.element_active
-        } else {
-            color.panel_background
-        };
-
-        let end_hover_gradient_overlay =
-            GradientFade::new(base_bg, color.element_hover, color.element_active)
-                .width(px(96.0))
-                .when_some(self.group_name.clone(), |fade, group| {
-                    fade.group_name(group)
-                });
-
         h_flex()
             .id(self.id)
             .when_some(self.group_name, |this, group| this.group(group))
@@ -382,9 +358,6 @@ impl RenderOnce for ListItem {
                                 .right(DynamicSpacing::Base06.rems(cx))
                                 .top_0()
                                 .visible_on_hover("list_item")
-                                .when(self.end_hover_gradient_overlay, |this| {
-                                    this.child(end_hover_gradient_overlay)
-                                })
                                 .child(end_hover_slot),
                         )
                     }),