1use gpui::{
2 div, AnyElement, ClickEvent, ElementId, InteractiveElement, IntoElement, MouseButton,
3 ParentElement, RenderOnce, SharedString, StatefulInteractiveElement, StyleRefinement, Styled,
4};
5
6use crate::{ActiveTheme as _, StyledExt};
7
8#[derive(IntoElement)]
10pub struct Link {
11 id: ElementId,
12 style: StyleRefinement,
13 href: Option<SharedString>,
14 disabled: bool,
15 on_click: Option<Box<dyn Fn(&ClickEvent, &mut gpui::Window, &mut gpui::App) + 'static>>,
16 children: Vec<AnyElement>,
17}
18
19impl Link {
20 pub fn new(id: impl Into<ElementId>) -> Self {
22 Self {
23 id: id.into(),
24 style: StyleRefinement::default(),
25 href: None,
26 on_click: None,
27 disabled: false,
28 children: Vec::new(),
29 }
30 }
31
32 pub fn href(mut self, href: impl Into<SharedString>) -> Self {
34 self.href = Some(href.into());
35 self
36 }
37
38 pub fn on_click(
43 mut self,
44 handler: impl Fn(&ClickEvent, &mut gpui::Window, &mut gpui::App) + 'static,
45 ) -> Self {
46 self.on_click = Some(Box::new(handler));
47 self
48 }
49
50 pub fn disabled(mut self, disabled: bool) -> Self {
52 self.disabled = disabled;
53 self
54 }
55}
56
57impl Styled for Link {
58 fn style(&mut self) -> &mut gpui::StyleRefinement {
59 &mut self.style
60 }
61}
62
63impl ParentElement for Link {
64 fn extend(&mut self, elements: impl IntoIterator<Item = gpui::AnyElement>) {
65 self.children.extend(elements)
66 }
67}
68
69impl RenderOnce for Link {
70 fn render(self, _: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement {
71 let href = self.href.clone();
72 let on_click = self.on_click;
73
74 div()
75 .id(self.id)
76 .text_color(cx.theme().link)
77 .text_decoration_1()
78 .text_decoration_color(cx.theme().link)
79 .hover(|this| {
80 this.text_color(cx.theme().link.opacity(0.8))
81 .text_decoration_1()
82 })
83 .active(|this| {
84 this.text_color(cx.theme().link.opacity(0.6))
85 .text_decoration_1()
86 })
87 .cursor_pointer()
88 .refine_style(&self.style)
89 .on_mouse_down(MouseButton::Left, |_, _, cx| {
90 cx.stop_propagation();
91 })
92 .on_click({
93 move |e, window, cx| {
94 if let Some(href) = &href {
95 cx.open_url(&href.clone());
96 }
97 if let Some(on_click) = &on_click {
98 on_click(e, window, cx);
99 }
100 }
101 })
102 .children(self.children)
103 }
104}