button_link.rs

  1use gpui::{IntoElement, Role, 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            .role(Role::Link)
 57            .size(ButtonSize::None)
 58            .child(
 59                h_flex()
 60                    .gap_0p5()
 61                    .child(
 62                        Label::new(self.label)
 63                            .size(self.label_size)
 64                            .color(self.label_color)
 65                            .underline(),
 66                    )
 67                    .when(!self.no_icon, |this| {
 68                        this.child(
 69                            Icon::new(IconName::ArrowUpRight)
 70                                .size(IconSize::Small)
 71                                .color(Color::Muted),
 72                        )
 73                    }),
 74            )
 75            .on_click(move |_, _, cx| cx.open_url(&self.link))
 76            .into_any_element()
 77    }
 78}
 79
 80impl Component for ButtonLink {
 81    fn scope() -> ComponentScope {
 82        ComponentScope::Navigation
 83    }
 84
 85    fn description() -> Option<&'static str> {
 86        Some("A button that opens a URL.")
 87    }
 88
 89    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
 90        Some(
 91            v_flex()
 92                .gap_6()
 93                .child(
 94                    example_group(vec![single_example(
 95                        "Simple",
 96                        ButtonLink::new("zed.dev", "https://zed.dev").into_any_element(),
 97                    )])
 98                    .vertical(),
 99                )
100                .into_any_element(),
101        )
102    }
103}