From 2352d4658d0a6ff084e793e4f2fab781be3f5f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Sun, 10 May 2026 00:45:21 -0400 Subject: [PATCH] Persist settings nav across every settings sub-page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- crates/ely_app/src/shell/chrome/mod.rs | 2 +- .../src/shell/chrome/settings_layout.rs | 12 ++- crates/ely_app/src/shell/internal_pages.rs | 76 +++++++++++++++---- .../src/shell/internal_pages/settings.rs | 5 +- crates/ely_app/src/shell/navigation.rs | 6 +- 5 files changed, 77 insertions(+), 24 deletions(-) diff --git a/crates/ely_app/src/shell/chrome/mod.rs b/crates/ely_app/src/shell/chrome/mod.rs index efc2010..8aa7749 100644 --- a/crates/ely_app/src/shell/chrome/mod.rs +++ b/crates/ely_app/src/shell/chrome/mod.rs @@ -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, diff --git a/crates/ely_app/src/shell/chrome/settings_layout.rs b/crates/ely_app/src/shell/chrome/settings_layout.rs index 48b73e8..a990c51 100644 --- a/crates/ely_app/src/shell/chrome/settings_layout.rs +++ b/crates/ely_app/src/shell/chrome/settings_layout.rs @@ -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, ) -> 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() } diff --git a/crates/ely_app/src/shell/internal_pages.rs b/crates/ely_app/src/shell/internal_pages.rs index ec13717..5b8c6e4 100644 --- a/crates/ely_app/src/shell/internal_pages.rs +++ b/crates/ely_app/src/shell/internal_pages.rs @@ -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) } diff --git a/crates/ely_app/src/shell/internal_pages/settings.rs b/crates/ely_app/src/shell/internal_pages/settings.rs index f0f27ad..efbac5c 100644 --- a/crates/ely_app/src/shell/internal_pages/settings.rs +++ b/crates/ely_app/src/shell/internal_pages/settings.rs @@ -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, ) -> 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) } } diff --git a/crates/ely_app/src/shell/navigation.rs b/crates/ely_app/src/shell/navigation.rs index 8312e0e..9dcaaeb 100644 --- a/crates/ely_app/src/shell/navigation.rs +++ b/crates/ely_app/src/shell/navigation.rs @@ -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(); } }