1use std::sync::Arc;
2
3use client::telemetry::Telemetry;
4use gpui::{AnyElement, Div, StyleRefinement};
5use smallvec::SmallVec;
6use ui::{prelude::*, ButtonLike};
7
8#[derive(IntoElement)]
9pub struct FeatureUpsell {
10 base: Div,
11 telemetry: Arc<Telemetry>,
12 text: SharedString,
13 docs_url: Option<SharedString>,
14 children: SmallVec<[AnyElement; 2]>,
15}
16
17impl FeatureUpsell {
18 pub fn new(telemetry: Arc<Telemetry>, text: impl Into<SharedString>) -> Self {
19 Self {
20 base: h_flex(),
21 telemetry,
22 text: text.into(),
23 docs_url: None,
24 children: SmallVec::new(),
25 }
26 }
27
28 pub fn docs_url(mut self, docs_url: impl Into<SharedString>) -> Self {
29 self.docs_url = Some(docs_url.into());
30 self
31 }
32}
33
34impl ParentElement for FeatureUpsell {
35 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
36 self.children.extend(elements)
37 }
38}
39
40// Style methods.
41impl FeatureUpsell {
42 fn style(&mut self) -> &mut StyleRefinement {
43 self.base.style()
44 }
45
46 gpui::border_style_methods!({
47 visibility: pub
48 });
49}
50
51impl RenderOnce for FeatureUpsell {
52 fn render(self, cx: &mut WindowContext) -> impl IntoElement {
53 self.base
54 .p_4()
55 .justify_between()
56 .border_color(cx.theme().colors().border)
57 .child(v_flex().overflow_hidden().child(Label::new(self.text)))
58 .child(h_flex().gap_2().children(self.children).when_some(
59 self.docs_url,
60 |el, docs_url| {
61 el.child(
62 ButtonLike::new("open_docs")
63 .child(
64 h_flex()
65 .gap_2()
66 .child(Label::new("View docs"))
67 .child(Icon::new(IconName::ArrowUpRight)),
68 )
69 .on_click({
70 let telemetry = self.telemetry.clone();
71 let docs_url = docs_url.clone();
72 move |_event, cx| {
73 telemetry.report_app_event(format!(
74 "feature upsell: viewed docs ({docs_url})"
75 ));
76 cx.open_url(&docs_url)
77 }
78 }),
79 )
80 },
81 ))
82 }
83}