From a7eb3a9b9fc2c604c18624555e0cc1713dc312c4 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Tue, 12 Nov 2024 18:41:20 -0300 Subject: [PATCH] Add "Book Onboarding" action across the app (#20503) This PR adds a small UI touch-up to the welcome page so we can introduce the "Book Onboarding" over there, as well as adding it to the user menu (both in the signed in and signed out states). The actual URL these buttons take to will still be updated to the correct destination. Screenshot 2024-11-12 at 12 45 27 Release Notes: - N/A --- assets/icons/blocks.svg | 1 + assets/icons/keyboard.svg | 1 + assets/icons/phone_incoming.svg | 1 + assets/icons/swatch_book.svg | 1 + crates/title_bar/src/title_bar.rs | 18 ++ crates/ui/src/components/context_menu.rs | 15 +- crates/ui/src/components/icon.rs | 4 + crates/welcome/src/welcome.rs | 306 +++++++++++++++-------- 8 files changed, 235 insertions(+), 112 deletions(-) create mode 100644 assets/icons/blocks.svg create mode 100644 assets/icons/keyboard.svg create mode 100644 assets/icons/phone_incoming.svg create mode 100644 assets/icons/swatch_book.svg diff --git a/assets/icons/blocks.svg b/assets/icons/blocks.svg new file mode 100644 index 0000000000000000000000000000000000000000..42d44c3f959ae08555966826243008cff8874574 --- /dev/null +++ b/assets/icons/blocks.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/keyboard.svg b/assets/icons/keyboard.svg new file mode 100644 index 0000000000000000000000000000000000000000..8bdc054a655322edae801dcf5bf6a6afef82a362 --- /dev/null +++ b/assets/icons/keyboard.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/phone_incoming.svg b/assets/icons/phone_incoming.svg new file mode 100644 index 0000000000000000000000000000000000000000..4577df47ad51af2d6c77f523de5e6ff0d188b4ec --- /dev/null +++ b/assets/icons/phone_incoming.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/swatch_book.svg b/assets/icons/swatch_book.svg new file mode 100644 index 0000000000000000000000000000000000000000..985994ffcf6780b6f35a3cb67bc0a461f186d842 --- /dev/null +++ b/assets/icons/swatch_book.svg @@ -0,0 +1 @@ + diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index ba1a106413df5b526c8a7352ae1b6185d84cabb4..2ea9ddafd77ac568960f81d4a2704987e28f0734 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -30,6 +30,7 @@ use ui::{ use util::ResultExt; use vcs_menu::{BranchList, OpenRecent as ToggleVcsMenu}; use workspace::{notifications::NotifyResultExt, Workspace}; +use zed_actions::OpenBrowser; #[cfg(feature = "stories")] pub use stories::*; @@ -37,6 +38,8 @@ pub use stories::*; const MAX_PROJECT_NAME_LENGTH: usize = 40; const MAX_BRANCH_NAME_LENGTH: usize = 40; +const BOOK_ONBOARDING: &str = "https://dub.sh/zed-onboarding"; + actions!( collab, [ @@ -580,6 +583,13 @@ impl TitleBar { .action("Themes…", theme_selector::Toggle::default().boxed_clone()) .action("Extensions", extensions_ui::Extensions.boxed_clone()) .separator() + .link( + "Book Onboarding", + OpenBrowser { + url: BOOK_ONBOARDING.to_string(), + } + .boxed_clone(), + ) .action("Sign Out", client::SignOut.boxed_clone()) }) .into() @@ -608,6 +618,14 @@ impl TitleBar { .action("Key Bindings", Box::new(zed_actions::OpenKeymap)) .action("Themes…", theme_selector::Toggle::default().boxed_clone()) .action("Extensions", extensions_ui::Extensions.boxed_clone()) + .separator() + .link( + "Book Onboarding", + OpenBrowser { + url: BOOK_ONBOARDING.to_string(), + } + .boxed_clone(), + ) }) .into() }) diff --git a/crates/ui/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs index 702dd6a09236e2151085d514f9da9171b73039df..4829ee1e37c940384aa6ff69aa2ddea2587e4349 100644 --- a/crates/ui/src/components/context_menu.rs +++ b/crates/ui/src/components/context_menu.rs @@ -1,7 +1,7 @@ #![allow(missing_docs)] use crate::{ - h_flex, prelude::*, utils::WithRemSize, v_flex, Icon, IconName, KeyBinding, Label, List, - ListItem, ListSeparator, ListSubHeader, + h_flex, prelude::*, utils::WithRemSize, v_flex, Icon, IconName, IconSize, KeyBinding, Label, + List, ListItem, ListSeparator, ListSubHeader, }; use gpui::{ px, Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, @@ -20,6 +20,7 @@ enum ContextMenuItem { toggle: Option<(IconPosition, bool)>, label: SharedString, icon: Option, + icon_size: IconSize, handler: Rc, &mut WindowContext)>, action: Option>, disabled: bool, @@ -103,6 +104,7 @@ impl ContextMenu { label: label.into(), handler: Rc::new(move |_, cx| handler(cx)), icon: None, + icon_size: IconSize::Small, action, disabled: false, }); @@ -122,6 +124,7 @@ impl ContextMenu { label: label.into(), handler: Rc::new(move |_, cx| handler(cx)), icon: None, + icon_size: IconSize::Small, action, disabled: false, }); @@ -171,6 +174,7 @@ impl ContextMenu { cx.dispatch_action(action.boxed_clone()); }), icon: None, + icon_size: IconSize::Small, disabled: false, }); self @@ -193,6 +197,7 @@ impl ContextMenu { cx.dispatch_action(action.boxed_clone()); }), icon: None, + icon_size: IconSize::Small, disabled: true, }); self @@ -206,6 +211,7 @@ impl ContextMenu { action: Some(action.boxed_clone()), handler: Rc::new(move |_, cx| cx.dispatch_action(action.boxed_clone())), icon: Some(IconName::ArrowUpRight), + icon_size: IconSize::XSmall, disabled: false, }); self @@ -393,6 +399,7 @@ impl Render for ContextMenu { label, handler, icon, + icon_size, action, disabled, } => { @@ -403,12 +410,12 @@ impl Render for ContextMenu { } else { Color::Default }; - let label_element = if let Some(icon) = icon { + let label_element = if let Some(icon_name) = icon { h_flex() .gap_1() .child(Label::new(label.clone()).color(color)) .child( - Icon::new(*icon).size(IconSize::Small).color(color), + Icon::new(*icon_name).size(*icon_size).color(color), ) .into_any_element() } else { diff --git a/crates/ui/src/components/icon.rs b/crates/ui/src/components/icon.rs index 89763c3a421ec4c26e6f425c5612f1c1cc4373b9..4f9317203d7f846c55f37a1e347cbb349b260cc2 100644 --- a/crates/ui/src/components/icon.rs +++ b/crates/ui/src/components/icon.rs @@ -135,6 +135,7 @@ pub enum IconName { BellDot, BellOff, BellRing, + Blocks, Bolt, Book, BookCopy, @@ -202,6 +203,7 @@ pub enum IconName { Indicator, IndicatorX, InlayHint, + Keyboard, Library, LineHeight, Link, @@ -227,6 +229,7 @@ pub enum IconName { PocketKnife, Public, PullRequest, + PhoneIncoming, Quote, RefreshTitle, Regex, @@ -269,6 +272,7 @@ pub enum IconName { SupermavenDisabled, SupermavenError, SupermavenInit, + SwatchBook, Tab, Terminal, Trash, diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 0be48bd82ef952c6679385b163f4dcddb1cd7d78..a644fc22dcca9ff3815fd5bb5695c0805079327b 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -26,6 +26,7 @@ actions!(welcome, [ResetHints]); pub const FIRST_OPEN: &str = "first_open"; pub const DOCS_URL: &str = "https://zed.dev/docs/"; +const BOOK_ONBOARDING: &str = "https://dub.sh/zed-onboarding"; pub fn init(cx: &mut AppContext) { BaseKeymap::register(cx); @@ -75,125 +76,207 @@ impl Render for WelcomePage { .track_focus(&self.focus_handle(cx)) .child( v_flex() - .w_80() - .gap_6() + .gap_8() .mx_auto() - .child( - svg() - .path("icons/logo_96.svg") - .text_color(cx.theme().colors().icon_disabled) - .w(px(80.)) - .h(px(80.)) - .mx_auto(), - ) .child( v_flex() - .gap_2() + .w_full() .child( - Button::new("choose-theme", "Choose Theme") - .full_width() - .on_click(cx.listener(|this, _, cx| { - this.telemetry.report_app_event( - "welcome page: change theme".to_string(), - ); - this.workspace - .update(cx, |workspace, cx| { - theme_selector::toggle( - workspace, - &Default::default(), - cx, - ) - }) - .ok(); - })), + svg() + .path("icons/logo_96.svg") + .text_color(cx.theme().colors().icon_disabled) + .w(px(40.)) + .h(px(40.)) + .mx_auto() + .mb_4(), ) .child( - Button::new("choose-keymap", "Choose Keymap") - .full_width() - .on_click(cx.listener(|this, _, cx| { - this.telemetry.report_app_event( - "welcome page: change keymap".to_string(), - ); - this.workspace - .update(cx, |workspace, cx| { - base_keymap_picker::toggle( - workspace, - &Default::default(), - cx, - ) - }) - .ok(); - })), + h_flex() + .w_full() + .justify_center() + .child(Headline::new("Welcome to Zed")), ) .child( - Button::new("edit settings", "Edit Settings") - .full_width() - .on_click(cx.listener(|this, _, cx| { - this.telemetry.report_app_event( - "welcome page: edit settings".to_string(), - ); - cx.dispatch_action(Box::new(zed_actions::OpenSettings)); - })), - ) - .child(Button::new("view docs", "View Docs").full_width().on_click( - cx.listener(|this, _, cx| { - this.telemetry - .report_app_event("welcome page: view docs".to_string()); - cx.open_url(DOCS_URL); - }), - )), + h_flex().w_full().justify_center().child( + Label::new("The editor for what's next") + .color(Color::Muted) + .italic(true), + ), + ), ) .child( - v_flex() - .gap_2() - .when(cfg!(target_os = "macos"), |el| { - el.child( - Button::new("install-cli", "Install the CLI") - .full_width() - .on_click(cx.listener(|this, _, cx| { - this.telemetry.report_app_event( - "welcome page: install cli".to_string(), - ); - cx.app_mut() - .spawn(|cx| async move { - install_cli::install_cli(&cx).await - }) - .detach_and_log_err(cx); - })), - ) - }) + h_flex() + .items_start() + .gap_8() .child( - Button::new("sign-in-to-copilot", "Sign in to GitHub Copilot") - .full_width() - .on_click(cx.listener(|this, _, cx| { - this.telemetry.report_app_event( - "welcome page: sign in to copilot".to_string(), - ); - inline_completion_button::initiate_sign_in(cx); - })), + v_flex() + .gap_2() + .pr_8() + .border_r_1() + .border_color(cx.theme().colors().border_variant) + .child( + self.section_label(cx).child( + Label::new("Get Started") + .size(LabelSize::XSmall) + .color(Color::Muted), + ), + ) + .child( + Button::new("choose-theme", "Choose a Theme") + .icon(IconName::SwatchBook) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click(cx.listener(|this, _, cx| { + this.telemetry.report_app_event( + "welcome page: change theme".to_string(), + ); + this.workspace + .update(cx, |workspace, cx| { + theme_selector::toggle( + workspace, + &Default::default(), + cx, + ) + }) + .ok(); + })), + ) + .child( + Button::new("choose-keymap", "Choose a Keymap") + .icon(IconName::Keyboard) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click(cx.listener(|this, _, cx| { + this.telemetry.report_app_event( + "welcome page: change keymap".to_string(), + ); + this.workspace + .update(cx, |workspace, cx| { + base_keymap_picker::toggle( + workspace, + &Default::default(), + cx, + ) + }) + .ok(); + })), + ) + .child( + Button::new( + "sign-in-to-copilot", + "Sign in to GitHub Copilot", + ) + .icon(IconName::Copilot) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click( + cx.listener(|this, _, cx| { + this.telemetry.report_app_event( + "welcome page: sign in to copilot".to_string(), + ); + inline_completion_button::initiate_sign_in(cx); + }), + ), + ) + .child( + Button::new("edit settings", "Edit Settings") + .icon(IconName::Settings) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click(cx.listener(|this, _, cx| { + this.telemetry.report_app_event( + "welcome page: edit settings".to_string(), + ); + cx.dispatch_action(Box::new( + zed_actions::OpenSettings, + )); + })), + ), ) .child( - Button::new("explore extensions", "Explore extensions") - .full_width() - .on_click(cx.listener(|this, _, cx| { - this.telemetry.report_app_event( - "welcome page: open extensions".to_string(), - ); - cx.dispatch_action(Box::new(extensions_ui::Extensions)); - })), + v_flex() + .gap_2() + .child( + self.section_label(cx).child( + Label::new("Resources") + .size(LabelSize::XSmall) + .color(Color::Muted), + ), + ) + .when(cfg!(target_os = "macos"), |el| { + el.child( + Button::new("install-cli", "Install the CLI") + .icon(IconName::Terminal) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click(cx.listener(|this, _, cx| { + this.telemetry.report_app_event( + "welcome page: install cli".to_string(), + ); + cx.app_mut() + .spawn(|cx| async move { + install_cli::install_cli(&cx).await + }) + .detach_and_log_err(cx); + })), + ) + }) + .child( + Button::new("view-docs", "View Documentation") + .icon(IconName::FileCode) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click(cx.listener(|this, _, cx| { + this.telemetry.report_app_event( + "welcome page: view docs".to_string(), + ); + cx.open_url(DOCS_URL); + })), + ) + .child( + Button::new("explore-extensions", "Explore Extensions") + .icon(IconName::Blocks) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click(cx.listener(|this, _, cx| { + this.telemetry.report_app_event( + "welcome page: open extensions".to_string(), + ); + cx.dispatch_action(Box::new( + extensions_ui::Extensions, + )); + })), + ) + .child( + Button::new("book-onboarding", "Book Onboarding") + .icon(IconName::PhoneIncoming) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .icon_position(IconPosition::Start) + .on_click(cx.listener(|_, _, cx| { + cx.open_url(BOOK_ONBOARDING); + })), + ), ), ) .child( v_flex() .p_3() .gap_2() - .bg(cx.theme().colors().elevated_surface_background) + .bg(cx.theme().colors().element_background) .border_1() - .border_color(cx.theme().colors().border) + .border_color(cx.theme().colors().border_variant) .rounded_md() .child(CheckboxWithLabel::new( "enable-vim", - Label::new("Enable vim mode"), + Label::new("Enable Vim Mode"), if VimModeSetting::get_global(cx).0 { ui::Selection::Selected } else { @@ -210,25 +293,25 @@ impl Render for WelcomePage { }), )) .child(CheckboxWithLabel::new( - "enable-telemetry", - Label::new("Send anonymous usage data"), - if TelemetrySettings::get_global(cx).metrics { + "enable-crash", + Label::new("Send Crash Reports"), + if TelemetrySettings::get_global(cx).diagnostics { ui::Selection::Selected } else { ui::Selection::Unselected }, cx.listener(move |this, selection, cx| { this.telemetry.report_app_event( - "welcome page: toggle metric telemetry".to_string(), + "welcome page: toggle diagnostic telemetry".to_string(), ); this.update_settings::(selection, cx, { let telemetry = this.telemetry.clone(); move |settings, value| { - settings.metrics = Some(value); + settings.diagnostics = Some(value); telemetry.report_setting_event( - "metric telemetry", + "diagnostic telemetry", value.to_string(), ); } @@ -236,25 +319,25 @@ impl Render for WelcomePage { }), )) .child(CheckboxWithLabel::new( - "enable-crash", - Label::new("Send crash reports"), - if TelemetrySettings::get_global(cx).diagnostics { + "enable-telemetry", + Label::new("Send Telemetry"), + if TelemetrySettings::get_global(cx).metrics { ui::Selection::Selected } else { ui::Selection::Unselected }, cx.listener(move |this, selection, cx| { this.telemetry.report_app_event( - "welcome page: toggle diagnostic telemetry".to_string(), + "welcome page: toggle metric telemetry".to_string(), ); this.update_settings::(selection, cx, { let telemetry = this.telemetry.clone(); move |settings, value| { - settings.diagnostics = Some(value); + settings.metrics = Some(value); telemetry.report_setting_event( - "diagnostic telemetry", + "metric telemetry", value.to_string(), ); } @@ -287,6 +370,13 @@ impl WelcomePage { this } + fn section_label(&self, cx: &WindowContext) -> Div { + div() + .pl_1() + .font_buffer(cx) + .text_color(Color::Muted.color(cx)) + } + fn update_settings( &mut self, selection: &Selection,