From db5b1a31b53c26e34ac67312452646820d8eb221 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:12:35 -0300 Subject: [PATCH] settings ui: Add some UX adjustments (#39615) Release Notes: - N/A --- Cargo.lock | 1 + assets/keymaps/default-linux.json | 3 +- assets/keymaps/default-macos.json | 3 +- assets/keymaps/default-windows.json | 3 +- crates/settings_ui/Cargo.toml | 1 + crates/settings_ui/src/settings_ui.rs | 116 ++++++++++++--------- crates/title_bar/src/title_bar.rs | 6 +- crates/ui/src/components/tree_view_item.rs | 14 ++- crates/ui_input/src/numeric_stepper.rs | 4 +- crates/zed_actions/src/lib.rs | 4 +- 10 files changed, 93 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbcf66a20301cfcff8752d2c7e38b5c2b66ea8c3..90975005949206a785e134ef99702a86fa2b9ee2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14384,6 +14384,7 @@ dependencies = [ "workspace", "workspace-hack", "zed-util", + "zed_actions", "zlog", ] diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index eb625eaba1ad39d9268f2b5577c62ac3d35fb4a3..b59a823816ffd81fa78deb1c8fac84f8c654d169 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -30,7 +30,8 @@ "ctrl-+": ["zed::IncreaseBufferFontSize", { "persist": false }], "ctrl--": ["zed::DecreaseBufferFontSize", { "persist": false }], "ctrl-0": ["zed::ResetBufferFontSize", { "persist": false }], - "ctrl-,": "zed::OpenSettings", + "ctrl-,": "zed::OpenSettingsEditor", + "ctrl-alt-,": "zed::OpenSettings", "ctrl-q": "zed::Quit", "f4": "debugger::Start", "shift-f5": "debugger::Stop", diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 3afa795244abc6639e4e1800d13ee02d64ff5177..dc4d74f84d040576c1c02378472618c105f7aac8 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -39,7 +39,8 @@ "cmd-+": ["zed::IncreaseBufferFontSize", { "persist": false }], "cmd--": ["zed::DecreaseBufferFontSize", { "persist": false }], "cmd-0": ["zed::ResetBufferFontSize", { "persist": false }], - "cmd-,": "zed::OpenSettings", + "cmd-,": "zed::OpenSettingsEditor", + "cmd-alt-,": "zed::OpenSettings", "cmd-q": "zed::Quit", "cmd-h": "zed::Hide", "alt-cmd-h": "zed::HideOthers", diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json index 14a3ff6fcd6cd0ca196d2aae98bb9fa80ec211d7..3e513d8603f611b92abaff654ee5676d0be85ad8 100644 --- a/assets/keymaps/default-windows.json +++ b/assets/keymaps/default-windows.json @@ -29,7 +29,8 @@ "ctrl-shift-=": ["zed::IncreaseBufferFontSize", { "persist": false }], "ctrl--": ["zed::DecreaseBufferFontSize", { "persist": false }], "ctrl-0": ["zed::ResetBufferFontSize", { "persist": false }], - "ctrl-,": "zed::OpenSettings", + "ctrl-,": "zed::OpenSettingsEditor", + "ctrl-alt-,": "zed::OpenSettings", "ctrl-q": "zed::Quit", "f4": "debugger::Start", "shift-f5": "debugger::Stop", diff --git a/crates/settings_ui/Cargo.toml b/crates/settings_ui/Cargo.toml index 2839fac954a35456189a7a09a1460efbeb7cdff3..75467ef8d4f23ee3442bb43a483a0b07cbb17599 100644 --- a/crates/settings_ui/Cargo.toml +++ b/crates/settings_ui/Cargo.toml @@ -35,6 +35,7 @@ ui_input.workspace = true util.workspace = true workspace-hack.workspace = true workspace.workspace = true +zed_actions.workspace = true [dev-dependencies] assets.workspace = true diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index aef906c0357a3f07216fc375818927dd21abe446..49afae873bb5e608d14a16f699037bb05abd29d9 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -5,9 +5,9 @@ use editor::{Editor, EditorEvent}; use feature_flags::{FeatureFlag, FeatureFlagAppExt as _}; use fuzzy::StringMatchCandidate; use gpui::{ - App, AppContext as _, Context, Div, Entity, FontWeight, Global, IntoElement, ReadGlobal as _, - Render, ScrollHandle, Task, TitlebarOptions, UniformListScrollHandle, Window, WindowHandle, - WindowOptions, actions, div, point, px, size, uniform_list, + App, Div, Entity, Focusable, FontWeight, Global, ReadGlobal as _, ScrollHandle, Task, + TitlebarOptions, UniformListScrollHandle, Window, WindowHandle, WindowOptions, div, point, + prelude::*, px, size, uniform_list, }; use project::WorktreeId; use settings::{ @@ -27,8 +27,9 @@ use ui::{ ContextMenu, Divider, DropdownMenu, DropdownStyle, IconButtonShape, Switch, SwitchColor, TreeViewItem, WithScrollbar, prelude::*, }; -use ui_input::{NumericStepper, NumericStepperType}; +use ui_input::{NumericStepper, NumericStepperStyle, NumericStepperType}; use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath}; +use zed_actions::OpenSettingsEditor; use crate::components::SettingsEditor; @@ -2704,14 +2705,6 @@ impl FeatureFlag for SettingsUiFeatureFlag { const NAME: &'static str = "settings-ui"; } -actions!( - zed, - [ - /// Opens Settings Editor. - OpenSettingsEditor - ] -); - pub fn init(cx: &mut App) { init_renderers(cx); @@ -2987,17 +2980,18 @@ impl SettingsPageItem { .child( h_flex() .w_full() - .gap_4() + .gap_1() .child(Label::new(SharedString::new_static(setting_item.title))) .when_some( file_set_in.filter(|file_set_in| file_set_in != &file), - |elem, file_set_in| { - elem.child( + |this, file_set_in| { + this.child( Label::new(format!( - "set in {}", + "— set in {}", file_set_in.name() )) - .color(Color::Muted), + .color(Color::Muted) + .size(LabelSize::Small), ) }, ), @@ -3172,6 +3166,10 @@ impl SettingsWindow { this.fetch_files(cx); this.build_ui(cx); + this.search_bar.update(cx, |editor, cx| { + editor.focus_handle(cx).focus(window); + }); + this } @@ -3397,13 +3395,15 @@ impl SettingsWindow { .gap_1() .children(self.files.iter().enumerate().map(|(ix, file)| { Button::new(ix, file.name()) + .toggle_state(file == &self.current_file) + .selected_style(ButtonStyle::Tinted(ui::TintColor::Accent)) .on_click(cx.listener(move |this, _, _window, cx| this.change_file(ix, cx))) })) } fn render_search(&self, _window: &mut Window, cx: &mut App) -> Div { h_flex() - .pt_1() + .py_1() .px_1p5() .gap_1p5() .rounded_sm() @@ -3414,7 +3414,14 @@ impl SettingsWindow { .child(self.search_bar.clone()) } - fn render_nav(&self, window: &mut Window, cx: &mut Context) -> Div { + fn render_nav( + &self, + window: &mut Window, + cx: &mut Context, + ) -> impl IntoElement { + let visible_entries: Vec<_> = self.visible_navbar_entries().collect(); + let visible_count = visible_entries.len(); + v_flex() .w_64() .p_2p5() @@ -3424,39 +3431,46 @@ impl SettingsWindow { .border_r_1() .border_color(cx.theme().colors().border) .bg(cx.theme().colors().panel_background) - .child(self.render_search(window, cx).pb_1()) + .child(self.render_search(window, cx)) .child( - uniform_list( - "settings-ui-nav-bar", - self.navbar_entries.len(), - cx.processor(|this, range: Range, _, cx| { - this.visible_navbar_entries() - .skip(range.start.saturating_sub(1)) - .take(range.len()) - .map(|(ix, entry)| { - TreeViewItem::new(("settings-ui-navbar-entry", ix), entry.title) - .root_item(entry.is_root) - .toggle_state(this.is_navbar_entry_selected(ix)) - .when(entry.is_root, |item| { - item.expanded(entry.expanded).on_toggle(cx.listener( - move |this, _, _, cx| { - this.toggle_navbar_entry(ix); - cx.notify(); - }, - )) + v_flex() + .size_full() + .child( + uniform_list( + "settings-ui-nav-bar", + visible_count, + cx.processor(move |this, range: Range, _, cx| { + let entries: Vec<_> = this.visible_navbar_entries().collect(); + range + .filter_map(|ix| entries.get(ix).copied()) + .map(|(ix, entry)| { + TreeViewItem::new( + ("settings-ui-navbar-entry", ix), + entry.title, + ) + .root_item(entry.is_root) + .toggle_state(this.is_navbar_entry_selected(ix)) + .when(entry.is_root, |item| { + item.expanded(entry.expanded).on_toggle(cx.listener( + move |this, _, _, cx| { + this.toggle_navbar_entry(ix); + cx.notify(); + }, + )) + }) + .on_click(cx.listener(move |this, _, _, cx| { + this.navbar_entry = ix; + cx.notify(); + })) + .into_any_element() }) - .on_click(cx.listener(move |this, _, _, cx| { - this.navbar_entry = ix; - cx.notify(); - })) - .into_any_element() - }) - .collect() - }), - ) - .track_scroll(self.list_handle.clone()) - .size_full() - .flex_grow(), + .collect() + }), + ) + .track_scroll(self.list_handle.clone()) + .flex_grow(), + ) + .vertical_scrollbar_for(self.list_handle.clone(), window, cx), ) } @@ -3638,6 +3652,7 @@ impl Render for SettingsWindow { let ui_font = theme::setup_ui_font(window, cx); div() + .key_context("SettingsWindow") .flex() .flex_row() .size_full() @@ -3773,6 +3788,7 @@ fn render_numeric_stepper( .log_err(); // todo(settings_ui) don't log err } }) + .style(NumericStepperStyle::Outlined) .into_any_element() } diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index b855e8132a1a0c83b827318e1cf675f684b49a3a..85890f017f46fc2e06e2cb6201dbf4fae6d062f3 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -724,11 +724,7 @@ impl TitleBar { }, ) .separator() - .action("Settings", zed_actions::OpenSettings.boxed_clone()) - .action( - "Settings Profiles", - zed_actions::settings_profile_selector::Toggle.boxed_clone(), - ) + .action("Settings", zed_actions::OpenSettingsEditor.boxed_clone()) .action("Keymap Editor", Box::new(zed_actions::OpenKeymapEditor)) .action( "Themes…", diff --git a/crates/ui/src/components/tree_view_item.rs b/crates/ui/src/components/tree_view_item.rs index af3cc34cc9092aef55aadea5d90a2abdb80b087c..73587e0e563d33d8d420fb6c8b5671bf5f150601 100644 --- a/crates/ui/src/components/tree_view_item.rs +++ b/crates/ui/src/components/tree_view_item.rs @@ -139,6 +139,7 @@ impl RenderOnce for TreeViewItem { h_flex() .id("inner_tree_view_item") .group("tree_view_item") + .cursor_pointer() .size_full() .relative() .map(|this| { @@ -207,7 +208,18 @@ impl RenderOnce for TreeViewItem { .when_some(self.on_hover, |this, on_hover| this.on_hover(on_hover)) .when_some( self.on_click.filter(|_| !self.disabled), - |this, on_click| this.cursor_pointer().on_click(on_click), + |this, on_click| { + if self.root_item && self.on_toggle.is_some() { + let on_toggle = self.on_toggle.clone().unwrap(); + + this.on_click(move |event, window, cx| { + on_click(event, window, cx); + on_toggle(event, window, cx); + }) + } else { + this.on_click(on_click) + } + }, ) .when_some(self.on_secondary_mouse_down, |this, on_mouse_down| { this.on_mouse_down(MouseButton::Right, move |event, window, cx| { diff --git a/crates/ui_input/src/numeric_stepper.rs b/crates/ui_input/src/numeric_stepper.rs index fe50f7bc5944599e58da685bb07721f171da29cb..1a02bf84cae70a6a85302a5bd306fa7fc062adb9 100644 --- a/crates/ui_input/src/numeric_stepper.rs +++ b/crates/ui_input/src/numeric_stepper.rs @@ -417,7 +417,6 @@ impl RenderOnce for NumericStepper { }) .child( h_flex() - .h_8() .min_w_16() .w_full() .border_1() @@ -426,9 +425,10 @@ impl RenderOnce for NumericStepper { .child(match *self.mode.read(cx) { NumericStepperMode::Read => h_flex() .id("numeric_stepper_label") + .px_1() .flex_1() .justify_center() - .child(Label::new((self.format)(&self.value)).mx_3()) + .child(Label::new((self.format)(&self.value))) .when_some(tab_index.as_mut(), |this, tab_index| { *tab_index += 1; this.tab_index(*tab_index - 1).focus(|style| { diff --git a/crates/zed_actions/src/lib.rs b/crates/zed_actions/src/lib.rs index 0eedce222982c9a5076dc0c2eecb82446d8d4d95..753918841f11df9b0650487cc2d987e0f693e532 100644 --- a/crates/zed_actions/src/lib.rs +++ b/crates/zed_actions/src/lib.rs @@ -30,8 +30,10 @@ pub struct OpenZedUrl { actions!( zed, [ - /// Opens the settings editor. + /// Opens the settings JSON file. OpenSettings, + /// Opens the settings editor. + OpenSettingsEditor, /// Opens the default keymap file. OpenDefaultKeymap, /// Opens account settings.