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.
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 | 348 ++++++++++++++---------
8 files changed, 256 insertions(+), 133 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 0000000000..42d44c3f95
--- /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 0000000000..8bdc054a65
--- /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 0000000000..4577df47ad
--- /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 0000000000..985994ffcf
--- /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 ba1a106413..2ea9ddafd7 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 702dd6a092..4829ee1e37 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 89763c3a42..4f9317203d 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 0be48bd82e..a644fc22dc 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(),
+ v_flex()
+ .w_full()
+ .child(
+ svg()
+ .path("icons/logo_96.svg")
+ .text_color(cx.theme().colors().icon_disabled)
+ .w(px(40.))
+ .h(px(40.))
+ .mx_auto()
+ .mb_4(),
+ )
+ .child(
+ h_flex()
+ .w_full()
+ .justify_center()
+ .child(Headline::new("Welcome to Zed")),
+ )
+ .child(
+ 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()
+ h_flex()
+ .items_start()
+ .gap_8()
.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();
- })),
+ 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("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();
- })),
- )
- .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);
- }),
- )),
- )
- .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);
- })),
- )
- })
- .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);
- })),
- )
- .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 {
@@ -209,35 +292,9 @@ impl Render for WelcomePage {
);
}),
))
- .child(CheckboxWithLabel::new(
- "enable-telemetry",
- Label::new("Send anonymous usage data"),
- 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 metric telemetry".to_string(),
- );
- this.update_settings::(selection, cx, {
- let telemetry = this.telemetry.clone();
-
- move |settings, value| {
- settings.metrics = Some(value);
-
- telemetry.report_setting_event(
- "metric telemetry",
- value.to_string(),
- );
- }
- });
- }),
- ))
.child(CheckboxWithLabel::new(
"enable-crash",
- Label::new("Send crash reports"),
+ Label::new("Send Crash Reports"),
if TelemetrySettings::get_global(cx).diagnostics {
ui::Selection::Selected
} else {
@@ -260,6 +317,32 @@ impl Render for WelcomePage {
}
});
}),
+ ))
+ .child(CheckboxWithLabel::new(
+ "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 metric telemetry".to_string(),
+ );
+ this.update_settings::(selection, cx, {
+ let telemetry = this.telemetry.clone();
+
+ move |settings, value| {
+ settings.metrics = Some(value);
+
+ telemetry.report_setting_event(
+ "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,