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.

<img width="700" alt="Screenshot 2024-11-12 at 12 45 27"
src="https://github.com/user-attachments/assets/9933bf94-f57a-43e2-8da3-bfbfd9fd24d0">

Release Notes:

- N/A
This commit is contained in:
Danilo Leal 2024-11-12 18:41:20 -03:00 committed by GitHub
parent 47ca3401ce
commit a7eb3a9b9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 256 additions and 133 deletions

1
assets/icons/blocks.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-blocks"><rect width="7" height="7" x="14" y="3" rx="1"/><path d="M10 21V8a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H3"/></svg>

After

Width:  |  Height:  |  Size: 368 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-keyboard"><path d="M10 8h.01"/><path d="M12 12h.01"/><path d="M14 8h.01"/><path d="M16 12h.01"/><path d="M18 8h.01"/><path d="M6 8h.01"/><path d="M7 16h10"/><path d="M8 12h.01"/><rect width="20" height="16" x="2" y="4" rx="2"/></svg>

After

Width:  |  Height:  |  Size: 436 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-phone-incoming"><polyline points="16 2 16 8 22 8"/><line x1="22" x2="16" y1="2" y2="8"/><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>

After

Width:  |  Height:  |  Size: 594 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-swatch-book"><path d="M11 17a4 4 0 0 1-8 0V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2Z"/><path d="M16.7 13H19a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H7"/><path d="M 7 17h.01"/><path d="m11 8 2.3-2.3a2.4 2.4 0 0 1 3.404.004L18.6 7.6a2.4 2.4 0 0 1 .026 3.434L9.9 19.8"/></svg>

After

Width:  |  Height:  |  Size: 456 B

View file

@ -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()
})

View file

@ -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<IconName>,
icon_size: IconSize,
handler: Rc<dyn Fn(Option<&FocusHandle>, &mut WindowContext)>,
action: Option<Box<dyn Action>>,
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 {

View file

@ -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,

View file

@ -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::<TelemetrySettings>(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::<TelemetrySettings>(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<T: Settings>(
&mut self,
selection: &Selection,