1use gpui::{IntoElement, Window, prelude::*};
2
3use crate::{ButtonLike, prelude::*};
4
5/// A button that takes an underline to look like a regular web link.
6/// It also contains an arrow icon to communicate the link takes you out of Zed.
7///
8/// # Usage Example
9///
10/// ```
11/// use ui::ButtonLink;
12///
13/// let button_link = ButtonLink::new("Click me", "https://example.com");
14/// ```
15#[derive(IntoElement, RegisterComponent)]
16pub struct ButtonLink {
17 label: SharedString,
18 label_size: LabelSize,
19 label_color: Color,
20 link: String,
21 no_icon: bool,
22}
23
24impl ButtonLink {
25 pub fn new(label: impl Into<SharedString>, link: impl Into<String>) -> Self {
26 Self {
27 link: link.into(),
28 label: label.into(),
29 label_size: LabelSize::Default,
30 label_color: Color::Default,
31 no_icon: false,
32 }
33 }
34
35 pub fn no_icon(mut self, no_icon: bool) -> Self {
36 self.no_icon = no_icon;
37 self
38 }
39
40 pub fn label_size(mut self, label_size: LabelSize) -> Self {
41 self.label_size = label_size;
42 self
43 }
44
45 pub fn label_color(mut self, label_color: Color) -> Self {
46 self.label_color = label_color;
47 self
48 }
49}
50
51impl RenderOnce for ButtonLink {
52 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
53 let id = format!("{}-{}", self.label, self.link);
54
55 ButtonLike::new(id)
56 .size(ButtonSize::None)
57 .child(
58 h_flex()
59 .gap_0p5()
60 .child(
61 Label::new(self.label)
62 .size(self.label_size)
63 .color(self.label_color)
64 .underline(),
65 )
66 .when(!self.no_icon, |this| {
67 this.child(
68 Icon::new(IconName::ArrowUpRight)
69 .size(IconSize::Small)
70 .color(Color::Muted),
71 )
72 }),
73 )
74 .on_click(move |_, _, cx| cx.open_url(&self.link))
75 .into_any_element()
76 }
77}
78
79impl Component for ButtonLink {
80 fn scope() -> ComponentScope {
81 ComponentScope::Navigation
82 }
83
84 fn description() -> Option<&'static str> {
85 Some("A button that opens a URL.")
86 }
87
88 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
89 Some(
90 v_flex()
91 .gap_6()
92 .child(
93 example_group(vec![single_example(
94 "Simple",
95 ButtonLink::new("zed.dev", "https://zed.dev").into_any_element(),
96 )])
97 .vertical(),
98 )
99 .into_any_element(),
100 )
101 }
102}