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,