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 {
21 Self {
22 id: id.into(),
23 style: StyleRefinement::default(),
24 href: None,
25 on_click: None,
26 disabled: false,
27 children: Vec::new(),
28 }
29 }
30
31 pub fn href(mut self, href: impl Into<SharedString>) -> Self {
32 self.href = Some(href.into());
33 self
34 }
35
36 pub fn on_click(
37 mut self,
38 handler: impl Fn(&ClickEvent, &mut gpui::Window, &mut gpui::App) + 'static,
39 ) -> Self {
40 self.on_click = Some(Box::new(handler));
41 self
42 }
43
44 pub fn disabled(mut self, disabled: bool) -> Self {
45 self.disabled = disabled;
46 self
47 }
48}
49
50impl Styled for Link {
51 fn style(&mut self) -> &mut gpui::StyleRefinement {
52 &mut self.style
53 }
54}
55
56impl ParentElement for Link {
57 fn extend(&mut self, elements: impl IntoIterator<Item = gpui::AnyElement>) {
58 self.children.extend(elements)
59 }
60}
61
62impl RenderOnce for Link {
63 fn render(self, _: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement {
64 let href = self.href.clone();
65 let on_click = self.on_click;
66
67 div()
68 .id(self.id)
69 .text_color(cx.theme().link)
70 .text_decoration_1()
71 .text_decoration_color(cx.theme().link)
72 .hover(|this| {
73 this.text_color(cx.theme().link.opacity(0.8))
74 .text_decoration_1()
75 })
76 .active(|this| {
77 this.text_color(cx.theme().link.opacity(0.6))
78 .text_decoration_1()
79 })
80 .cursor_pointer()
81 .refine_style(&self.style)
82 .on_mouse_down(MouseButton::Left, |_, _, cx| {
83 cx.stop_propagation();
84 })
85 .on_click({
86 move |e, window, cx| {
87 if let Some(href) = &href {
88 cx.open_url(&href.clone());
89 }
90 if let Some(on_click) = &on_click {
91 on_click(e, window, cx);
92 }
93 }
94 })
95 .children(self.children)
96 }
97}