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}