dioxus_element_plug/components/
card.rs1use dioxus::prelude::*;
2
3pub const CARD: &str = "el-card";
5pub const CARD_HEADER: &str = "el-card__header";
6pub const CARD_BODY: &str = "el-card__body";
7pub const CARD_SHADOW_ALWAYS: &str = "el-card--always";
8pub const CARD_SHADOW_HOVER: &str = "el-card--hover";
9
10#[derive(Props, Clone, PartialEq)]
12pub struct CardProps {
13 pub children: Element,
15
16 #[props(default)]
18 pub header: Option<String>,
19
20 #[props(default = "hover".to_string())]
22 pub shadow: String,
23
24 #[props(default)]
26 pub body_style: Option<String>,
27
28 #[props(default)]
30 pub class: Option<String>,
31
32 #[props(default)]
34 pub style: Option<String>,
35}
36
37#[component]
59pub fn Card(props: CardProps) -> Element {
60 let mut class_names = vec!["el-card".to_string()];
61
62 class_names.push(format!("is-{}-shadow", props.shadow));
63
64 if let Some(ref custom_class) = props.class {
65 class_names.push(custom_class.to_string());
66 }
67
68 let class_string = class_names.join(" ");
69 let card_style = props.style.unwrap_or_default();
70 let body_style = props.body_style.unwrap_or_default();
71
72 rsx! {
73 div {
74 class: "{class_string}",
75 style: "{card_style}",
76
77 if let Some(ref header_text) = props.header {
78 div {
79 class: "el-card__header",
80 "{header_text}"
81 }
82 }
83
84 div {
85 class: "el-card__body",
86 style: "{body_style}",
87 {props.children}
88 }
89 }
90 }
91}
92
93#[derive(Props, Clone, PartialEq)]
95pub struct PanelProps {
96 pub children: Element,
98
99 #[props(default)]
101 pub title: Option<String>,
102
103 #[props(default)]
105 pub subtitle: Option<String>,
106
107 #[props(default = "default".to_string())]
109 pub panel_type: String,
110
111 #[props(default = false)]
113 pub collapsible: bool,
114
115 #[props(default = false)]
117 pub collapsed: bool,
118
119 #[props(default)]
121 pub class: Option<String>,
122
123 #[props(default)]
125 pub style: Option<String>,
126
127 #[props(default)]
129 pub on_toggle: Option<EventHandler<MouseEvent>>,
130}
131
132#[component]
137pub fn Panel(props: PanelProps) -> Element {
138 let mut class_names = vec!["el-panel".to_string()];
139
140 class_names.push(format!("el-panel--{}", props.panel_type));
141
142 if props.collapsible {
143 class_names.push("is-collapsible".to_string());
144 }
145
146 if props.collapsed {
147 class_names.push("is-collapsed".to_string());
148 }
149
150 if let Some(ref custom_class) = props.class {
151 class_names.push(custom_class.to_string());
152 }
153
154 let class_string = class_names.join(" ");
155 let style_string = props.style.unwrap_or_default();
156
157 rsx! {
158 div {
159 class: "{class_string}",
160 style: "{style_string}",
161
162 if props.collapsible {
163 div {
164 class: "el-panel__header is-clickable",
165 onclick: move |event| {
166 if let Some(handler) = props.on_toggle {
167 handler.call(event);
168 }
169 },
170
171 if let Some(ref title_text) = props.title {
172 h3 {
173 class: "el-panel__title",
174 "{title_text}"
175 }
176 }
177
178 if let Some(ref sub_text) = props.subtitle {
179 span {
180 class: "el-panel__subtitle",
181 "{sub_text}"
182 }
183 }
184
185 i {
186 class: if props.collapsed { "el-icon-arrow-down" } else { "el-icon-arrow-up" }
187 }
188 }
189 } else if let Some(ref title_text) = props.title {
190 div {
191 class: "el-panel__header",
192
193 h3 {
194 class: "el-panel__title",
195 "{title_text}"
196 }
197
198 if let Some(ref sub_text) = props.subtitle {
199 span {
200 class: "el-panel__subtitle",
201 "{sub_text}"
202 }
203 }
204 }
205 }
206
207 if !props.collapsible || !props.collapsed {
208 div {
209 class: "el-panel__body",
210 {props.children}
211 }
212 }
213 }
214 }
215}
216
217#[derive(Props, Clone, PartialEq)]
219pub struct BoxProps {
220 pub children: Element,
222
223 #[props(default)]
225 pub padding: Option<String>,
226
227 #[props(default)]
229 pub margin: Option<String>,
230
231 #[props(default)]
233 pub border_radius: Option<String>,
234
235 #[props(default)]
237 pub background: Option<String>,
238
239 #[props(default)]
241 pub border: Option<String>,
242
243 #[props(default)]
245 pub elevation: Option<u32>,
246
247 #[props(default)]
249 pub class: Option<String>,
250
251 #[props(default)]
253 pub style: Option<String>,
254}
255
256#[component]
261pub fn Box(props: BoxProps) -> Element {
262 let mut styles = vec![props.style.unwrap_or_default()];
263
264 if let Some(padding) = props.padding {
265 styles.push(format!("padding: {};", padding));
266 }
267
268 if let Some(margin) = props.margin {
269 styles.push(format!("margin: {};", margin));
270 }
271
272 if let Some(border_radius) = props.border_radius {
273 styles.push(format!("border-radius: {};", border_radius));
274 }
275
276 if let Some(background) = props.background {
277 styles.push(format!("background: {};", background));
278 }
279
280 if let Some(border) = props.border {
281 styles.push(format!("border: {};", border));
282 }
283
284 if let Some(elevation) = props.elevation {
285 let shadow = match elevation {
286 0 => "none",
287 1 => "0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)",
288 2 => "0 3px 6px rgba(0,0,0,0.15), 0 2px 4px rgba(0,0,0,0.12)",
289 3 => "0 10px 20px rgba(0,0,0,0.15), 0 3px 6px rgba(0,0,0,0.10)",
290 4 => "0 15px 25px rgba(0,0,0,0.15), 0 5px 10px rgba(0,0,0,0.05)",
291 5 => "0 20px 40px rgba(0,0,0,0.20)",
292 _ => "0 25px 50px rgba(0,0,0,0.25)",
293 };
294 styles.push(format!("box-shadow: {};", shadow));
295 }
296
297 let style_string = styles.join("");
298
299 let mut class_names = vec!["el-box".to_string()];
300
301 if let Some(ref custom_class) = props.class {
302 class_names.push(custom_class.to_string());
303 }
304
305 if let Some(elevation) = props.elevation {
306 class_names.push(format!("el-box--elevation-{}", elevation));
307 }
308
309 let class_string = class_names.join(" ");
310
311 rsx! {
312 div {
313 class: "{class_string}",
314 style: "{style_string}",
315 {props.children}
316 }
317 }
318}
319
320#[derive(Clone, PartialEq)]
322pub struct AccordionItem {
323 pub title: String,
325 pub content: String,
327 pub disabled: bool,
329}
330
331#[derive(Props, Clone, PartialEq)]
333pub struct AccordionProps {
334 pub items: Vec<AccordionItem>,
336
337 #[props(default)]
339 pub active_index: Option<usize>,
340
341 #[props(default = false)]
343 pub accordion: bool,
344
345 #[props(default = true)]
347 pub animated: bool,
348
349 #[props(default)]
351 pub class: Option<String>,
352
353 #[props(default)]
355 pub style: Option<String>,
356
357 #[props(default)]
359 pub on_change: Option<EventHandler<usize>>,
360}
361
362#[component]
367pub fn Accordion(props: AccordionProps) -> Element {
368 let mut class_names = vec!["el-accordion".to_string()];
369
370 if props.accordion {
371 class_names.push("el-accordion--multiple".to_string());
372 }
373
374 if props.animated {
375 class_names.push("el-accordion--animated".to_string());
376 }
377
378 if let Some(ref custom_class) = props.class {
379 class_names.push(custom_class.to_string());
380 }
381
382 let class_string = class_names.join(" ");
383 let style_string = props.style.unwrap_or_default();
384
385 rsx! {
386 div {
387 class: "{class_string}",
388 style: "{style_string}",
389
390 for (index, item) in props.items.iter().enumerate() {
391 div {
392 class: "el-accordion__item",
393
394 if !props.accordion || props.active_index == Some(index) {
395 div {
396 class: "el-accordion__header",
397
398 button {
399 class: "el-accordion__button",
400 r#type: "button",
401 disabled: item.disabled,
402 onclick: move |_| {
403 if let Some(handler) = props.on_change {
404 handler.call(index);
405 }
406 },
407
408 span {
409 class: "el-accordion__title",
410 "{item.title}"
411 }
412
413 i {
414 class: "el-icon-arrow-down el-accordion__icon"
415 }
416 }
417 }
418
419 div {
420 class: "el-accordion__content",
421
422 div {
423 class: "el-accordion__body",
424 "{item.content}"
425 }
426 }
427 } else {
428 div {
429 class: "el-accordion__header",
430
431 button {
432 class: "el-accordion__button",
433 r#type: "button",
434 disabled: item.disabled,
435 onclick: move |_| {
436 if let Some(handler) = props.on_change {
437 handler.call(index);
438 }
439 },
440
441 span {
442 class: "el-accordion__title",
443 "{item.title}"
444 }
445
446 i {
447 class: "el-icon-arrow-right el-accordion__icon"
448 }
449 }
450 }
451 }
452 }
453 }
454 }
455 }
456}