mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
title_bar: Use popovers for modal anchoring (#45924)
Anchoring fix part of #45853 Before: https://github.com/user-attachments/assets/abe66049-04e5-4f33-9efb-2e99e63e4cc8 After: https://github.com/user-attachments/assets/14533bbe-8f46-43b1-9465-11e8d313561f Release Notes: - N/A --------- Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
This commit is contained in:
parent
d492b48f32
commit
0a1b79880e
8 changed files with 149 additions and 126 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -16879,11 +16879,13 @@ dependencies = [
|
|||
"cloud_llm_client",
|
||||
"collections",
|
||||
"db",
|
||||
"git_ui",
|
||||
"gpui",
|
||||
"http_client",
|
||||
"notifications",
|
||||
"pretty_assertions",
|
||||
"project",
|
||||
"recent_projects",
|
||||
"remote",
|
||||
"rpc",
|
||||
"schemars",
|
||||
|
|
|
|||
|
|
@ -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<Workspace>,
|
||||
modal_style: bool,
|
||||
repository: Option<Entity<Repository>>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Entity<BranchList> {
|
||||
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
|
||||
})
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ impl CommitModal {
|
|||
.menu(move |window, cx| {
|
||||
Some(branch_picker::popover(
|
||||
workspace.clone(),
|
||||
false,
|
||||
active_repo.clone(),
|
||||
window,
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -350,6 +350,22 @@ impl RecentProjects {
|
|||
Self::new(delegate, 34., window, cx)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn popover(
|
||||
workspace: WeakEntity<Workspace>,
|
||||
create_new_window: bool,
|
||||
focus_handle: FocusHandle,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Entity<Self> {
|
||||
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<DismissEvent> for RecentProjects {}
|
||||
|
|
|
|||
|
|
@ -664,6 +664,20 @@ impl RemoteServerProjects {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn popover(
|
||||
fs: Arc<dyn Fs>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
create_new_window: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Entity<Self> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Self>,
|
||||
) -> Option<AnyElement> {
|
||||
fn render_remote_project_connection(&self, cx: &mut Context<Self>) -> Option<AnyElement> {
|
||||
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<Self>,
|
||||
) -> Option<AnyElement> {
|
||||
pub fn render_project_host(&self, cx: &mut Context<Self>) -> Option<AnyElement> {
|
||||
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<Self>,
|
||||
) -> impl IntoElement {
|
||||
pub fn render_project_name(&self, cx: &mut Context<Self>) -> 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<Self>,
|
||||
) -> Option<impl IntoElement> {
|
||||
pub fn render_project_repo(&self, cx: &mut Context<Self>) -> Option<impl IntoElement> {
|
||||
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<Self>) -> bool {
|
||||
self.workspace
|
||||
.update(cx, |workspace, cx| workspace.has_active_modal(window, cx))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue