diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index 8a8dbd8a90..ef5354e82d 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -1168,5 +1168,14 @@ "up": "menu::SelectPrevious", "down": "menu::SelectNext" } + }, + { + "context": "Onboarding", + "use_key_equivalents": true, + "bindings": { + "ctrl-1": "onboarding::ActivateBasicsPage", + "ctrl-2": "onboarding::ActivateEditingPage", + "ctrl-3": "onboarding::ActivateAISetupPage" + } } ] diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 62ba187851..3287e50acb 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -1270,5 +1270,14 @@ "up": "menu::SelectPrevious", "down": "menu::SelectNext" } + }, + { + "context": "Onboarding", + "use_key_equivalents": true, + "bindings": { + "cmd-1": "onboarding::ActivateBasicsPage", + "cmd-2": "onboarding::ActivateEditingPage", + "cmd-3": "onboarding::ActivateAISetupPage" + } } ] diff --git a/crates/onboarding/src/basics_page.rs b/crates/onboarding/src/basics_page.rs index 327256968a..82688e6220 100644 --- a/crates/onboarding/src/basics_page.rs +++ b/crates/onboarding/src/basics_page.rs @@ -153,10 +153,8 @@ fn render_theme_section(window: &mut Window, cx: &mut App) -> impl IntoElement { new_appearance: Appearance, cx: &mut App, ) { - appearance_state.update(cx, |appearance, _| { - *appearance = new_appearance; - }); let fs = ::global(cx); + appearance_state.write(cx, new_appearance); update_settings_file::(fs, cx, move |settings, _| { if settings.theme.as_ref().and_then(ThemeSelection::mode) == Some(ThemeMode::System) { diff --git a/crates/onboarding/src/onboarding.rs b/crates/onboarding/src/onboarding.rs index 21fbeb5d97..2e6025285c 100644 --- a/crates/onboarding/src/onboarding.rs +++ b/crates/onboarding/src/onboarding.rs @@ -6,8 +6,8 @@ use feature_flags::{FeatureFlag, FeatureFlagViewExt as _}; use fs::Fs; use gpui::{ Action, AnyElement, App, AppContext, AsyncWindowContext, Context, Entity, EventEmitter, - FocusHandle, Focusable, IntoElement, Render, SharedString, Subscription, Task, WeakEntity, - Window, actions, + FocusHandle, Focusable, IntoElement, KeyContext, Render, SharedString, Subscription, Task, + WeakEntity, Window, actions, }; use schemars::JsonSchema; use serde::Deserialize; @@ -65,6 +65,18 @@ actions!( ] ); +actions!( + onboarding, + [ + /// Activates the Basics page. + ActivateBasicsPage, + /// Activates the Editing page. + ActivateEditingPage, + /// Activates the AI Setup page. + ActivateAISetupPage, + ] +); + pub fn init(cx: &mut App) { cx.on_action(|_: &OpenOnboarding, cx| { with_active_or_new_workspace(cx, |workspace, window, cx| { @@ -235,67 +247,69 @@ impl Onboarding { }) } - fn render_nav_button( + fn render_nav_buttons( &mut self, - page: SelectedPage, - _: &mut Window, + window: &mut Window, cx: &mut Context, - ) -> impl IntoElement { - let text = match page { - SelectedPage::Basics => "Basics", - SelectedPage::Editing => "Editing", - SelectedPage::AiSetup => "AI Setup", - }; + ) -> [impl IntoElement; 3] { + let pages = [ + SelectedPage::Basics, + SelectedPage::Editing, + SelectedPage::AiSetup, + ]; - let binding = match page { - SelectedPage::Basics => { - KeyBinding::new(vec![gpui::Keystroke::parse("cmd-1").unwrap()], cx) - .map(|kb| kb.size(rems_from_px(12.))) - } - SelectedPage::Editing => { - KeyBinding::new(vec![gpui::Keystroke::parse("cmd-2").unwrap()], cx) - .map(|kb| kb.size(rems_from_px(12.))) - } - SelectedPage::AiSetup => { - KeyBinding::new(vec![gpui::Keystroke::parse("cmd-3").unwrap()], cx) - .map(|kb| kb.size(rems_from_px(12.))) - } - }; + let text = ["Basics", "Editing", "AI Setup"]; - let selected = self.selected_page == page; + let actions: [&dyn Action; 3] = [ + &ActivateBasicsPage, + &ActivateEditingPage, + &ActivateAISetupPage, + ]; - h_flex() - .id(text) - .relative() - .w_full() - .gap_2() - .px_2() - .py_0p5() - .justify_between() - .rounded_sm() - .when(selected, |this| { - this.child( - div() - .h_4() - .w_px() - .bg(cx.theme().colors().text_accent) - .absolute() - .left_0(), - ) - }) - .hover(|style| style.bg(cx.theme().colors().element_hover)) - .child(Label::new(text).map(|this| { - if selected { - this.color(Color::Default) - } else { - this.color(Color::Muted) - } - })) - .child(binding) - .on_click(cx.listener(move |this, _, _, cx| { - this.selected_page = page; - cx.notify(); - })) + let mut binding = actions.map(|action| { + KeyBinding::for_action_in(action, &self.focus_handle, window, cx) + .map(|kb| kb.size(rems_from_px(12.))) + }); + + pages.map(|page| { + let i = page as usize; + let selected = self.selected_page == page; + h_flex() + .id(text[i]) + .relative() + .w_full() + .gap_2() + .px_2() + .py_0p5() + .justify_between() + .rounded_sm() + .when(selected, |this| { + this.child( + div() + .h_4() + .w_px() + .bg(cx.theme().colors().text_accent) + .absolute() + .left_0(), + ) + }) + .hover(|style| style.bg(cx.theme().colors().element_hover)) + .child(Label::new(text[i]).map(|this| { + if selected { + this.color(Color::Default) + } else { + this.color(Color::Muted) + } + })) + .child(binding[i].take().map_or( + gpui::Empty.into_any_element(), + IntoElement::into_any_element, + )) + .on_click(cx.listener(move |this, _, _, cx| { + this.selected_page = page; + cx.notify(); + })) + }) } fn render_nav(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { @@ -335,14 +349,7 @@ impl Onboarding { .border_y_1() .border_color(cx.theme().colors().border_variant.opacity(0.5)) .gap_1() - .children([ - self.render_nav_button(SelectedPage::Basics, window, cx) - .into_element(), - self.render_nav_button(SelectedPage::Editing, window, cx) - .into_element(), - self.render_nav_button(SelectedPage::AiSetup, window, cx) - .into_element(), - ]), + .children(self.render_nav_buttons(window, cx)), ) .child( ButtonLike::new("skip_all") @@ -454,9 +461,26 @@ impl Render for Onboarding { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { h_flex() .image_cache(gpui::retain_all("onboarding-page")) - .key_context("onboarding-page") + .key_context({ + let mut ctx = KeyContext::new_with_defaults(); + ctx.add("Onboarding"); + ctx + }) + .track_focus(&self.focus_handle) .size_full() .bg(cx.theme().colors().editor_background) + .on_action(cx.listener(|this, _: &ActivateBasicsPage, _, cx| { + this.selected_page = SelectedPage::Basics; + cx.notify(); + })) + .on_action(cx.listener(|this, _: &ActivateEditingPage, _, cx| { + this.selected_page = SelectedPage::Editing; + cx.notify(); + })) + .on_action(cx.listener(|this, _: &ActivateAISetupPage, _, cx| { + this.selected_page = SelectedPage::AiSetup; + cx.notify(); + })) .child( h_flex() .max_w(rems_from_px(1100.)) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 8c6da335ab..af317edeee 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -4354,6 +4354,7 @@ mod tests { "menu", "notebook", "notification_panel", + "onboarding", "outline", "outline_panel", "pane",