1use freya_core::prelude::*;
2use freya_router::prelude::{
3 NavigationTarget,
4 Navigator,
5};
6
7use crate::{
8 get_theme,
9 theming::component_themes::LinkThemePartial,
10 tooltip::{
11 Tooltip,
12 TooltipContainer,
13 },
14};
15
16#[derive(Clone, PartialEq)]
18pub enum LinkTooltip {
19 None,
21 Default,
26 Custom(String),
28}
29
30#[derive(PartialEq)]
31pub struct Link {
32 pub(crate) theme: Option<LinkThemePartial>,
34 to: NavigationTarget,
36 children: Vec<Element>,
38 tooltip: LinkTooltip,
40 key: DiffKey,
42}
43
44impl ChildrenExt for Link {
45 fn get_children(&mut self) -> &mut Vec<Element> {
46 &mut self.children
47 }
48}
49
50impl KeyExt for Link {
51 fn write_key(&mut self) -> &mut DiffKey {
52 &mut self.key
53 }
54}
55
56impl Link {
57 pub fn new(to: impl Into<NavigationTarget>) -> Self {
58 Self {
59 to: to.into(),
60 children: Vec::new(),
61 tooltip: LinkTooltip::Default,
62 theme: None,
63 key: DiffKey::None,
64 }
65 }
66
67 pub fn tooltip(mut self, tooltip: impl Into<LinkTooltip>) -> Self {
68 self.tooltip = tooltip.into();
69 self
70 }
71}
72
73impl Component for Link {
74 fn render(&self) -> impl IntoElement {
75 let theme = get_theme!(&self.theme, link);
76 let mut is_hovering = use_state(|| false);
77
78 let url = if let NavigationTarget::External(ref url) = self.to {
79 Some(url.clone())
80 } else {
81 None
82 };
83
84 let on_pointer_enter = move |_| {
85 is_hovering.set(true);
86 };
87
88 let on_pointer_leave = move |_| {
89 is_hovering.set(false);
90 };
91
92 let on_press = {
93 let to = self.to.clone();
94 let url = url.clone();
95 move |_| {
96 if let Some(url) = &url {
99 let _ = open::that(url);
100 } else {
101 Navigator::get().push(to.clone());
102 }
103 }
104 };
105
106 let color = if *is_hovering.read() {
107 Some(theme.color)
108 } else {
109 None
110 };
111
112 let tooltip_text = match &self.tooltip {
113 LinkTooltip::Default => url.clone(),
114 LinkTooltip::None => None,
115 LinkTooltip::Custom(str) => Some(str.clone()),
116 };
117
118 let link = rect()
119 .on_press(on_press)
120 .on_pointer_enter(on_pointer_enter)
121 .on_pointer_leave(on_pointer_leave)
122 .map(color, |rect, color| rect.color(color))
123 .children(self.children.clone());
124
125 if let Some(tooltip_text) = tooltip_text {
126 TooltipContainer::new(Tooltip::new(tooltip_text))
127 .child(link)
128 .into_element()
129 } else {
130 link.into()
131 }
132 }
133
134 fn render_key(&self) -> DiffKey {
135 self.key.clone().or(self.default_key())
136 }
137}