1use topcoat::{context::Cx, icon::IconData, view::Attributes};
4
5pub(crate) fn runtime_link(cx: &Cx, href: &str) -> Attributes {
7 topcoat::runtime::link_attrs(cx, href.to_string(), topcoat::runtime::prefetch_mode(cx))
8}
9
10#[derive(Clone, Default, PartialEq, Eq)]
12pub enum NavTarget {
13 #[default]
15 Derived,
16 Url(String),
18}
19
20impl NavTarget {
21 pub fn url(&self) -> Option<&str> {
23 match self {
24 Self::Derived => None,
25 Self::Url(url) => Some(url),
26 }
27 }
28}
29
30impl std::fmt::Debug for NavTarget {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 Self::Derived => f.write_str("Derived"),
34 Self::Url(url) => f.debug_tuple("Url").field(url).finish(),
35 }
36 }
37}
38
39#[derive(Clone, Debug, Default)]
41pub struct NavigationItem {
42 pub label: String,
43 pub target: NavTarget,
45 pub order: i32,
47 pub icon: Option<IconData>,
49}
50
51impl NavigationItem {
52 pub fn at(label: impl Into<String>, url: impl Into<String>) -> Self {
54 Self {
55 label: label.into(),
56 target: NavTarget::Url(url.into()),
57 order: 0,
58 icon: None,
59 }
60 }
61
62 #[must_use]
64 pub fn icon(mut self, icon: IconData) -> Self {
65 self.icon = Some(icon);
66 self
67 }
68
69 pub(crate) fn resolved(mut self, url: &str) -> Self {
71 if matches!(self.target, NavTarget::Derived) {
72 self.target = NavTarget::Url(url.to_string());
73 }
74 self
75 }
76
77 pub fn url(&self) -> Option<&str> {
79 self.target.url()
80 }
81
82 pub fn is_current_path(&self, current_path: &str) -> bool {
84 let Some(url) = self.url() else {
85 return false;
86 };
87 if current_path == url {
88 return true;
89 }
90 current_path
91 .strip_prefix(url)
92 .is_some_and(|rest| rest.starts_with('/'))
93 }
94}
95
96#[cfg(test)]
97mod tests;