Persist settings nav across every settings sub-page

Each ely://settings/* route used to render its content alone, with no
nav column — so clicking a sidebar item replaced the entire page and
read to users as a brand-new tab opening. Move the nav column into a
shared render_settings_shell wrapper and route every settings/* URL
through it. ely://sync/status reuses the sync route highlight.

Also stop in-place navigation from stealing focus to the omnibar so
the destination page keeps focus for scroll and interaction.
This commit is contained in:
2026-05-10 00:45:21 -04:00
parent fcac3268ad
commit 2352d4658d
5 changed files with 77 additions and 24 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ pub(crate) use brand_glyph::{accent_color_for_host, render_glyph_for};
pub(crate) use command_overlay::render_command_overlay;
pub(crate) use home::render_home_page;
pub(crate) use plugin_detail_view::render_plugin_detail_view;
pub(crate) use settings_layout::render_settings_landing;
pub(crate) use settings_layout::render_settings_shell;
pub(crate) use sidebar::{panel_bg, panel_shadow};
pub(crate) use sidebar_header::{
render_sidebar_header, render_workspace_disclosure, render_workspace_disclosure_backdrop,
@@ -7,7 +7,6 @@ use gpui::{
use gpui_component::{IconName, scroll::ScrollableElement};
use crate::shell::ElyShell;
use crate::shell::chrome::render_appearance_form;
struct NavGroup {
label: &'static str,
@@ -111,10 +110,15 @@ const NAV_GROUPS: &[NavGroup] = &[
},
];
pub(crate) fn render_settings_landing(
shell: &mut ElyShell,
/// Wrap a settings sub-page so the persistent left nav column sits next
/// to the page-specific content. Every `ely://settings/*` route renders
/// through here, so navigating sub-pages reads as "the panel on the
/// right swapped" instead of "the layout disappeared and a new tab
/// opened" — the prior behavior that misread to users as a tab spawn.
pub(crate) fn render_settings_shell(
snapshot: &BrowserSnapshot,
active_route: &str,
content: AnyElement,
cx: &mut Context<ElyShell>,
) -> AnyElement {
div()
@@ -122,7 +126,7 @@ pub(crate) fn render_settings_landing(
.h_full()
.flex()
.child(render_nav_column(snapshot, active_route, cx))
.child(render_appearance_form(shell, snapshot, cx))
.child(content)
.into_any_element()
}
+60 -16
View File
@@ -47,6 +47,7 @@ use gpui_component::{IconName, StyledExt, scroll::ScrollableElement};
use super::ElyShell;
use super::archive_labels::archive_detail_label;
use super::chrome::render_settings_shell;
impl ElyShell {
pub(super) fn render_web_canvas(
@@ -83,23 +84,66 @@ impl ElyShell {
}
"ely://about" => self.render_about_page(snapshot),
"ely://settings" => self.render_settings_page(snapshot, cx),
"ely://settings/advanced" => self.render_advanced_page(snapshot),
"ely://settings/appearance" => self.render_appearance_page(snapshot, cx),
"ely://settings/general" => self.render_general_page(snapshot, cx),
"ely://settings/sidebar-tabs" => self.render_sidebar_tabs_page(snapshot, cx),
"ely://settings/search" => self.render_search_page(snapshot, cx),
"ely://settings/privacy-security" => self.render_privacy_security_page(snapshot, cx),
"ely://settings/downloads" => self.render_download_settings_page(snapshot, cx),
"ely://settings/spaces" => self.render_spaces_page(snapshot, cx),
"ely://settings/site-permissions" => {
self.render_site_permissions_settings_page(snapshot, cx)
url @ "ely://settings/advanced" => {
let content = self.render_advanced_page(snapshot);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/appearance" => {
let content = self.render_appearance_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/general" => {
let content = self.render_general_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/sidebar-tabs" => {
let content = self.render_sidebar_tabs_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/search" => {
let content = self.render_search_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/privacy-security" => {
let content = self.render_privacy_security_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/downloads" => {
let content = self.render_download_settings_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/spaces" => {
let content = self.render_spaces_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/site-permissions" => {
let content = self.render_site_permissions_settings_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/shortcuts" => {
let content = self.render_shortcuts_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/plugins" => {
let content = self.render_plugins_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/profiles" => {
let content = self.render_profiles_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/sync" => {
let content = self.render_sync_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
url @ "ely://settings/updates" => {
let content = self.render_updates_page(snapshot, cx);
render_settings_shell(snapshot, url, content, cx)
}
"ely://sync/status" => {
let content = self.render_sync_page(snapshot, cx);
render_settings_shell(snapshot, "ely://settings/sync", content, cx)
}
"ely://settings/shortcuts" => self.render_shortcuts_page(snapshot, cx),
"ely://settings/plugins" => self.render_plugins_page(snapshot, cx),
"ely://settings/profiles" => self.render_profiles_page(snapshot, cx),
"ely://settings/sync" => self.render_sync_page(snapshot, cx),
"ely://settings/updates" => self.render_updates_page(snapshot, cx),
"ely://sync/status" => self.render_sync_page(snapshot, cx),
url if super::web_surface::is_external_web_url(url) => {
self.render_external_web_canvas(tab, snapshot, cx)
}
@@ -2,7 +2,7 @@ use ely_browser_core::BrowserSnapshot;
use gpui::{AnyElement, Context};
use super::ElyShell;
use crate::shell::chrome::render_settings_landing;
use crate::shell::chrome::{render_appearance_form, render_settings_shell};
impl ElyShell {
pub(super) fn render_settings_page(
@@ -10,6 +10,7 @@ impl ElyShell {
snapshot: &BrowserSnapshot,
cx: &mut Context<Self>,
) -> AnyElement {
render_settings_landing(self, snapshot, "ely://settings/appearance", cx)
let content = render_appearance_form(self, snapshot, cx);
render_settings_shell(snapshot, "ely://settings/appearance", content, cx)
}
}
+5 -1
View File
@@ -58,6 +58,11 @@ impl ElyShell {
/// Navigate the active tab to `url` without creating a new tab.
/// Falls back to opening a new tab only if there's no active tab
/// to navigate (the BrowserCore returns `TabNotFound`).
///
/// Note: in-place navigation does NOT steal focus to the omnibar.
/// Settings nav clicks, home pills, and disclosure rows expect
/// focus to stay on the page so the user can immediately scroll
/// or interact with the destination.
pub(crate) fn navigate_active_tab(
&mut self,
url: UrlText,
@@ -69,7 +74,6 @@ impl ElyShell {
core.open_tab(url);
}
self.sync_address_input(window, cx);
self.focus_address_bar(window, cx);
cx.notify();
}
}