1use gpui::{
2 ClickEvent, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, MouseDownEvent, Render,
3 svg,
4};
5use ui::{TintColor, prelude::*};
6use workspace::{ModalView, Workspace};
7
8use crate::git_panel::GitPanel;
9
10macro_rules! git_onboarding_event {
11 ($name:expr) => {
12 telemetry::event!($name, source = "Git Onboarding");
13 };
14 ($name:expr, $($key:ident $(= $value:expr)?),+ $(,)?) => {
15 telemetry::event!($name, source = "Git Onboarding", $($key $(= $value)?),+);
16 };
17}
18
19/// Introduces user to the Git Panel and overall improved Git support
20pub struct GitOnboardingModal {
21 focus_handle: FocusHandle,
22 workspace: Entity<Workspace>,
23}
24
25impl GitOnboardingModal {
26 pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context<Workspace>) {
27 let workspace_entity = cx.entity();
28 workspace.toggle_modal(window, cx, |_window, cx| Self {
29 workspace: workspace_entity,
30 focus_handle: cx.focus_handle(),
31 });
32 }
33
34 fn open_panel(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
35 self.workspace.update(cx, |workspace, cx| {
36 workspace.focus_panel::<GitPanel>(window, cx);
37 });
38
39 cx.emit(DismissEvent);
40
41 git_onboarding_event!("Open Panel Clicked");
42 }
43
44 fn view_blog(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
45 cx.open_url("https://zed.dev/blog/git");
46 cx.notify();
47
48 git_onboarding_event!("Blog Link Clicked");
49 }
50
51 fn cancel(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
52 cx.emit(DismissEvent);
53 }
54}
55
56impl EventEmitter<DismissEvent> for GitOnboardingModal {}
57
58impl Focusable for GitOnboardingModal {
59 fn focus_handle(&self, _cx: &App) -> FocusHandle {
60 self.focus_handle.clone()
61 }
62}
63
64impl ModalView for GitOnboardingModal {}
65
66impl Render for GitOnboardingModal {
67 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
68 let window_height = window.viewport_size().height;
69 let max_height = window_height - px(200.);
70
71 let base = v_flex()
72 .id("git-onboarding")
73 .key_context("GitOnboardingModal")
74 .relative()
75 .w(px(450.))
76 .h_full()
77 .max_h(max_height)
78 .p_4()
79 .gap_2()
80 .elevation_3(cx)
81 .track_focus(&self.focus_handle(cx))
82 .overflow_hidden()
83 .on_action(cx.listener(Self::cancel))
84 .on_action(cx.listener(|_, _: &menu::Cancel, _window, cx| {
85 git_onboarding_event!("Cancelled", trigger = "Action");
86 cx.emit(DismissEvent);
87 }))
88 .on_any_mouse_down(cx.listener(|this, _: &MouseDownEvent, window, _cx| {
89 this.focus_handle.focus(window);
90 }))
91 .child(
92 div().p_1p5().absolute().inset_0().h(px(160.)).child(
93 svg()
94 .path("icons/git_onboarding_bg.svg")
95 .text_color(cx.theme().colors().icon_disabled)
96 .w(px(420.))
97 .h(px(128.))
98 .overflow_hidden(),
99 ),
100 )
101 .child(
102 v_flex()
103 .w_full()
104 .gap_1()
105 .child(
106 Label::new("Introducing")
107 .size(LabelSize::Small)
108 .color(Color::Muted),
109 )
110 .child(Headline::new("Native Git Support").size(HeadlineSize::Large)),
111 )
112 .child(h_flex().absolute().top_2().right_2().child(
113 IconButton::new("cancel", IconName::Close).on_click(cx.listener(
114 |_, _: &ClickEvent, _window, cx| {
115 git_onboarding_event!("Cancelled", trigger = "X click");
116 cx.emit(DismissEvent);
117 },
118 )),
119 ));
120
121 let open_panel_button = Button::new("open-panel", "Get Started with the Git Panel")
122 .icon_size(IconSize::Indicator)
123 .style(ButtonStyle::Tinted(TintColor::Accent))
124 .full_width()
125 .on_click(cx.listener(Self::open_panel));
126
127 let blog_post_button = Button::new("view-blog", "Check out the Blog Post")
128 .icon(IconName::ArrowUpRight)
129 .icon_size(IconSize::Indicator)
130 .icon_color(Color::Muted)
131 .full_width()
132 .on_click(cx.listener(Self::view_blog));
133
134 let copy = "First-class support for staging, committing, pulling, pushing, viewing diffs, and more. All without leaving Zed.";
135
136 base.child(Label::new(copy).color(Color::Muted)).child(
137 v_flex()
138 .w_full()
139 .mt_2()
140 .gap_2()
141 .child(open_panel_button)
142 .child(blog_post_button),
143 )
144 }
145}