leptos_shadcn_breadcrumb/
default.rs1use leptos::prelude::*;
2use tailwind_fuse::tw_merge;
3
4const BREADCRUMB_CLASS: &str = "";
5const BREADCRUMB_LIST_CLASS: &str = "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5";
6const BREADCRUMB_ITEM_CLASS: &str = "inline-flex items-center gap-1.5";
7const BREADCRUMB_LINK_CLASS: &str = "transition-colors hover:text-foreground";
8const BREADCRUMB_PAGE_CLASS: &str = "font-normal text-foreground";
9const BREADCRUMB_SEPARATOR_CLASS: &str = "[&>svg]:size-3.5";
10const BREADCRUMB_ELLIPSIS_CLASS: &str = "flex h-9 w-9 items-center justify-center";
11
12#[component]
13pub fn Breadcrumb(
14 #[prop(optional)] class: MaybeProp<String>,
15 children: Children,
16) -> impl IntoView {
17 let merged_class = tw_merge!(&format!("{} {}",
18 BREADCRUMB_CLASS,
19 class.get().unwrap_or_default()
20 ));
21
22 view! {
23 <nav
24 aria-label="breadcrumb"
25 class={merged_class}
26 >
27 {children()}
28 </nav>
29 }
30}
31
32#[component]
33pub fn BreadcrumbList(
34 #[prop(optional)] class: MaybeProp<String>,
35 children: Children,
36) -> impl IntoView {
37 let merged_class = tw_merge!(&format!("{} {}",
38 BREADCRUMB_LIST_CLASS,
39 class.get().unwrap_or_default()
40 ));
41
42 view! {
43 <ol class={merged_class}>
44 {children()}
45 </ol>
46 }
47}
48
49#[component]
50pub fn BreadcrumbItem(
51 #[prop(optional)] class: MaybeProp<String>,
52 children: Children,
53) -> impl IntoView {
54 let merged_class = tw_merge!(&format!("{} {}",
55 BREADCRUMB_ITEM_CLASS,
56 class.get().unwrap_or_default()
57 ));
58
59 view! {
60 <li class={merged_class}>
61 {children()}
62 </li>
63 }
64}
65
66#[component]
67pub fn BreadcrumbLink(
68 #[prop(optional)] href: MaybeProp<String>,
69 #[prop(optional)] class: MaybeProp<String>,
70 #[prop(optional)] as_child: MaybeProp<bool>,
71 children: Children,
72) -> impl IntoView {
73 let merged_class = tw_merge!(&format!("{} {}",
74 BREADCRUMB_LINK_CLASS,
75 class.get().unwrap_or_default()
76 ));
77
78 let is_as_child = as_child.get().unwrap_or(false);
79
80 if is_as_child {
81 children()
83 } else {
84 view! {
85 <a
86 href={href.get()}
87 class={merged_class}
88 >
89 {children()}
90 </a>
91 }.into_any()
92 }
93}
94
95#[component]
96pub fn BreadcrumbPage(
97 #[prop(optional)] class: MaybeProp<String>,
98 children: Children,
99) -> impl IntoView {
100 let merged_class = tw_merge!(&format!("{} {}",
101 BREADCRUMB_PAGE_CLASS,
102 class.get().unwrap_or_default()
103 ));
104
105 view! {
106 <span
107 role="link"
108 aria-disabled="true"
109 aria-current="page"
110 class={merged_class}
111 >
112 {children()}
113 </span>
114 }
115}
116
117#[component]
118pub fn BreadcrumbSeparator(
119 #[prop(optional)] class: MaybeProp<String>,
120 #[prop(optional)] children: Option<Children>,
121) -> impl IntoView {
122 let merged_class = tw_merge!(&format!("{} {}",
123 BREADCRUMB_SEPARATOR_CLASS,
124 class.get().unwrap_or_default()
125 ));
126
127 view! {
128 <li role="presentation" aria-hidden="true" class={merged_class}>
129 {if let Some(children) = children {
130 children().into_any()
131 } else {
132 view! {
133 <svg
134 width="15"
135 height="15"
136 viewBox="0 0 15 15"
137 fill="none"
138 xmlns="http://www.w3.org/2000/svg"
139 >
140 <path
141 d="m5.5 4.5 3 3-3 3"
142 stroke="currentColor"
143 stroke-width="1"
144 stroke-linecap="round"
145 stroke-linejoin="round"
146 />
147 </svg>
148 }.into_any()
149 }}
150 </li>
151 }
152}
153
154#[component]
155pub fn BreadcrumbEllipsis(
156 #[prop(optional)] class: MaybeProp<String>,
157) -> impl IntoView {
158 let merged_class = tw_merge!(&format!("{} {}",
159 BREADCRUMB_ELLIPSIS_CLASS,
160 class.get().unwrap_or_default()
161 ));
162
163 view! {
164 <span
165 role="presentation"
166 aria-hidden="true"
167 class={merged_class}
168 >
169 <svg
170 width="15"
171 height="15"
172 viewBox="0 0 15 15"
173 fill="none"
174 xmlns="http://www.w3.org/2000/svg"
175 >
176 <path
177 d="M3 6.5a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM7.5 6.5a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM13.5 8a1.5 1.5 0 1 0-3 0 1.5 1.5 0 0 0 3 0Z"
178 fill="currentColor"
179 />
180 </svg>
181 <span class="sr-only">"More"</span>
182 </span>
183 }
184}