diff --git a/Cargo.lock b/Cargo.lock index ebddead4b980ce1f5c5f7f3c744a9549d0565ac9..d7d354fa9a366159e68ad0eaa0134fffbf3cbac2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16879,11 +16879,13 @@ dependencies = [ "cloud_llm_client", "collections", "db", + "git_ui", "gpui", "http_client", "notifications", "pretty_assertions", "project", + "recent_projects", "remote", "rpc", "schemars", diff --git a/crates/git_ui/src/branch_picker.rs b/crates/git_ui/src/branch_picker.rs index 4db37e91b8720e51ff0416cc471842483ab1d0ca..a23d116f4371362ac1e809be844f207d2b496edc 100644 --- a/crates/git_ui/src/branch_picker.rs +++ b/crates/git_ui/src/branch_picker.rs @@ -70,27 +70,34 @@ pub fn open( ) { let workspace_handle = workspace.weak_handle(); let repository = workspace.project().read(cx).active_repository(cx); - let style = BranchListStyle::Modal; + workspace.toggle_modal(window, cx, |window, cx| { - BranchList::new(workspace_handle, repository, style, rems(34.), window, cx) + BranchList::new( + workspace_handle, + repository, + BranchListStyle::Modal, + rems(34.), + window, + cx, + ) }) } pub fn popover( workspace: WeakEntity, + modal_style: bool, repository: Option>, window: &mut Window, cx: &mut App, ) -> Entity { + let (style, width) = if modal_style { + (BranchListStyle::Modal, rems(34.)) + } else { + (BranchListStyle::Popover, rems(20.)) + }; + cx.new(|cx| { - let list = BranchList::new( - workspace, - repository, - BranchListStyle::Popover, - rems(20.), - window, - cx, - ); + let list = BranchList::new(workspace, repository, style, width, window, cx); list.focus_handle(cx).focus(window, cx); list }) diff --git a/crates/git_ui/src/commit_modal.rs b/crates/git_ui/src/commit_modal.rs index e154933adc794221159c7f1b28b3d1e33cf1854d..c7f659147645be8e9145bcf15d5f9273d496a6ad 100644 --- a/crates/git_ui/src/commit_modal.rs +++ b/crates/git_ui/src/commit_modal.rs @@ -380,6 +380,7 @@ impl CommitModal { .menu(move |window, cx| { Some(branch_picker::popover( workspace.clone(), + false, active_repo.clone(), window, cx, diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 0540bb55971879c7feb7ebe36276da03684a2b4d..c2ab62810b47fbe1338e54f1d0220e644bbc967b 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -5738,7 +5738,7 @@ impl RenderOnce for PanelRepoFooter { .menu(move |window, cx| { let workspace = workspace.clone()?; let repo = repo.clone().flatten(); - Some(branch_picker::popover(workspace, repo, window, cx)) + Some(branch_picker::popover(workspace, false, repo, window, cx)) }) .trigger_with_tooltip( branch_selector_button, diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index 435933a880123c00d3f3fbaaea2c54f6554f0d3b..2c278e17adc09eb26d8aeaeb2e68f94a1d34c436 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -350,6 +350,22 @@ impl RecentProjects { Self::new(delegate, 34., window, cx) }) } + + pub fn popover( + workspace: WeakEntity, + create_new_window: bool, + focus_handle: FocusHandle, + window: &mut Window, + cx: &mut App, + ) -> Entity { + cx.new(|cx| { + let delegate = + RecentProjectsDelegate::new(workspace, create_new_window, true, focus_handle); + let list = Self::new(delegate, 34., window, cx); + list.picker.focus_handle(cx).focus(window, cx); + list + }) + } } impl EventEmitter for RecentProjects {} diff --git a/crates/recent_projects/src/remote_servers.rs b/crates/recent_projects/src/remote_servers.rs index 15735b6664e4b72749b0149013d02428eb2735de..bd7a3d29301b727f14311e5aad0b37a8d15ab109 100644 --- a/crates/recent_projects/src/remote_servers.rs +++ b/crates/recent_projects/src/remote_servers.rs @@ -664,6 +664,20 @@ impl RemoteServerProjects { ) } + pub fn popover( + fs: Arc, + workspace: WeakEntity, + create_new_window: bool, + window: &mut Window, + cx: &mut App, + ) -> Entity { + cx.new(|cx| { + let server = Self::new(create_new_window, fs, window, workspace, cx); + server.focus_handle(cx).focus(window, cx); + server + }) + } + fn new_inner( mode: Mode, create_new_window: bool, diff --git a/crates/title_bar/Cargo.toml b/crates/title_bar/Cargo.toml index 6d5d0ce170e261deefca679953199597b2753981..b73a586c4436f93c472960c0805fc39a2266abe7 100644 --- a/crates/title_bar/Cargo.toml +++ b/crates/title_bar/Cargo.toml @@ -35,9 +35,11 @@ chrono.workspace = true client.workspace = true cloud_llm_client.workspace = true db.workspace = true +git_ui.workspace = true gpui = { workspace = true, features = ["screen-capture"] } notifications.workspace = true project.workspace = true +recent_projects.workspace = true remote.workspace = true rpc.workspace = true schemars.workspace = true diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index 9b75d35eccafa3c30f23329d9c0ee890ed2b2405..6693b6acb0b37416a8261e2d004a35366469524b 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -44,7 +44,7 @@ use ui::{ }; use util::{ResultExt, rel_path::RelPath}; use workspace::{ToggleWorktreeSecurity, Workspace, notifications::NotifyResultExt}; -use zed_actions::{OpenRecent, OpenRemote}; +use zed_actions::OpenRemote; pub use onboarding_banner::restore_banner; @@ -166,11 +166,11 @@ impl Render for TitleBar { .when(title_bar_settings.show_project_items, |title_bar| { title_bar .children(self.render_restricted_mode(cx)) - .children(self.render_project_host(window, cx)) - .child(self.render_project_name(window, cx)) + .children(self.render_project_host(cx)) + .child(self.render_project_name(cx)) }) .when(title_bar_settings.show_branch_name, |title_bar| { - title_bar.children(self.render_project_repo(window, cx)) + title_bar.children(self.render_project_repo(cx)) }) }) }) @@ -350,13 +350,8 @@ impl TitleBar { .next() } - fn render_remote_project_connection( - &self, - window: &mut Window, - cx: &mut Context, - ) -> Option { + fn render_remote_project_connection(&self, cx: &mut Context) -> Option { let workspace = self.workspace.clone(); - let is_picker_open = self.is_picker_open(window, cx); let options = self.project.read(cx).remote_connection_options(cx)?; let host: SharedString = options.display_name().into(); @@ -402,23 +397,38 @@ impl TitleBar { let meta = SharedString::from(meta); Some( - ButtonLike::new("remote_project") - .child( - h_flex() - .gap_2() - .max_w_32() + PopoverMenu::new("remote-project-menu") + .menu(move |window, cx| { + let workspace_entity = workspace.upgrade()?; + let fs = workspace_entity.read(cx).project().read(cx).fs().clone(); + Some(recent_projects::RemoteServerProjects::popover( + fs, + workspace.clone(), + false, + window, + cx, + )) + }) + .trigger_with_tooltip( + ButtonLike::new("remote_project") + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .child( - IconWithIndicator::new( - Icon::new(icon).size(IconSize::Small).color(icon_color), - Some(Indicator::dot().color(indicator_color)), - ) - .indicator_border_color(Some(cx.theme().colors().title_bar_background)) - .into_any_element(), - ) - .child(Label::new(nickname).size(LabelSize::Small).truncate()), - ) - .when(!is_picker_open, |this| { - this.tooltip(move |_window, cx| { + h_flex() + .gap_2() + .max_w_32() + .child( + IconWithIndicator::new( + Icon::new(icon).size(IconSize::Small).color(icon_color), + Some(Indicator::dot().color(indicator_color)), + ) + .indicator_border_color(Some( + cx.theme().colors().title_bar_background, + )) + .into_any_element(), + ) + .child(Label::new(nickname).size(LabelSize::Small).truncate()), + ), + move |_window, cx| { Tooltip::with_meta( tooltip_title, Some(&OpenRemote { @@ -428,25 +438,9 @@ impl TitleBar { meta.clone(), cx, ) - }) - }) - .on_click(move |event, window, cx| { - let position = event.position(); - let _ = workspace.update(cx, |this, cx| { - this.set_next_modal_placement(workspace::ModalPlacement::Anchored { - position, - }); - - window.dispatch_action( - OpenRemote { - from_existing_connection: false, - create_new_window: false, - } - .boxed_clone(), - cx, - ); - }); - }) + }, + ) + .anchor(gpui::Corner::TopLeft) .into_any_element(), ) } @@ -497,13 +491,9 @@ impl TitleBar { } } - pub fn render_project_host( - &self, - window: &mut Window, - cx: &mut Context, - ) -> Option { + pub fn render_project_host(&self, cx: &mut Context) -> Option { if self.project.read(cx).is_via_remote_server() { - return self.render_remote_project_connection(window, cx); + return self.render_remote_project_connection(cx); } if self.project.read(cx).is_disconnected(cx) { @@ -550,13 +540,8 @@ impl TitleBar { ) } - pub fn render_project_name( - &self, - window: &mut Window, - cx: &mut Context, - ) -> impl IntoElement { + pub fn render_project_name(&self, cx: &mut Context) -> impl IntoElement { let workspace = self.workspace.clone(); - let is_picker_open = self.is_picker_open(window, cx); let name = self.project_name(cx); let is_project_selected = name.is_some(); @@ -566,11 +551,27 @@ impl TitleBar { "Open Recent Project".to_string() }; - Button::new("project_name_trigger", name) - .label_size(LabelSize::Small) - .when(!is_project_selected, |s| s.color(Color::Muted)) - .when(!is_picker_open, |this| { - this.tooltip(move |_window, cx| { + let focus_handle = workspace + .upgrade() + .map(|w| w.read(cx).focus_handle(cx)) + .unwrap_or_else(|| cx.focus_handle()); + + PopoverMenu::new("recent-projects-menu") + .menu(move |window, cx| { + Some(recent_projects::RecentProjects::popover( + workspace.clone(), + false, + focus_handle.clone(), + window, + cx, + )) + }) + .trigger_with_tooltip( + Button::new("project_name_trigger", name) + .label_size(LabelSize::Small) + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) + .when(!is_project_selected, |s| s.color(Color::Muted)), + move |_window, cx| { Tooltip::for_action( "Recent Projects", &zed_actions::OpenRecent { @@ -578,29 +579,12 @@ impl TitleBar { }, cx, ) - }) - }) - .on_click(move |event, window, cx| { - let position = event.position(); - let _ = workspace.update(cx, |this, _cx| { - this.set_next_modal_placement(workspace::ModalPlacement::Anchored { position }) - }); - - window.dispatch_action( - OpenRecent { - create_new_window: false, - } - .boxed_clone(), - cx, - ); - }) + }, + ) + .anchor(gpui::Corner::TopLeft) } - pub fn render_project_repo( - &self, - window: &mut Window, - cx: &mut Context, - ) -> Option { + pub fn render_project_repo(&self, cx: &mut Context) -> Option { let repository = self.project.read(cx).active_repository(cx)?; let repository_count = self.project.read(cx).repositories(cx).len(); let workspace = self.workspace.upgrade()?; @@ -655,41 +639,44 @@ impl TitleBar { (branch_name, icon_info) }; - let is_picker_open = self.is_picker_open(window, cx); let settings = TitleBarSettings::get_global(cx); + let project = self.project.clone(); Some( - Button::new("project_branch_trigger", branch_name) - .label_size(LabelSize::Small) - .color(Color::Muted) - .when(!is_picker_open, |this| { - this.tooltip(move |_window, cx| { + PopoverMenu::new("branch-menu") + .menu(move |window, cx| { + let repository = project.read(cx).active_repository(cx); + Some(git_ui::branch_picker::popover( + workspace.downgrade(), + true, + repository, + window, + cx, + )) + }) + .trigger_with_tooltip( + Button::new("project_branch_trigger", branch_name) + .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 + .icon(icon) + .icon_position(IconPosition::Start) + .icon_color(icon_color) + .icon_size(IconSize::Indicator) + }), + move |_window, cx| { Tooltip::with_meta( "Recent Branches", Some(&zed_actions::git::Branch), "Local branches only", cx, ) - }) - }) - .when(settings.show_branch_icon, |branch_button| { - let (icon, icon_color) = icon_info; - branch_button - .icon(icon) - .icon_position(IconPosition::Start) - .icon_color(icon_color) - .icon_size(IconSize::Indicator) - }) - .on_click(move |event, window, cx| { - let position = event.position(); - let _ = workspace.update(cx, |this, cx| { - this.set_next_modal_placement(workspace::ModalPlacement::Anchored { - position, - }); - window.focus(&this.active_pane().focus_handle(cx), cx); - window.dispatch_action(zed_actions::git::Branch.boxed_clone(), cx); - }); - }), + }, + ) + .anchor(gpui::Corner::TopLeft), ) } @@ -902,10 +889,4 @@ impl TitleBar { }) .anchor(gpui::Corner::TopRight) } - - fn is_picker_open(&self, window: &mut Window, cx: &mut Context) -> bool { - self.workspace - .update(cx, |workspace, cx| workspace.has_active_modal(window, cx)) - .unwrap_or(false) - } }