Skip to main content

ui/components/button/
button_link.rs

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 the app.
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("example.com", "https://example.com").into_any_element(),
96                    )])
97                    .vertical(),
98                )
99                .into_any_element(),
100        )
101    }
102}