Skip to main content

dioxus_element_plug/components/
timeline.rs

1use dioxus::prelude::*;
2
3/// TimelineItem timestamp placement
4#[derive(Clone, PartialEq)]
5pub enum TimestampPlacement {
6    Top,
7    Bottom,
8}
9
10/// Timeline props
11#[derive(Props, Clone, PartialEq)]
12pub struct TimelineProps {
13    #[props(default)]
14    pub children: Element,
15
16    #[props(default = false)]
17    pub reverse: bool,
18
19    #[props(default)]
20    pub class: Option<String>,
21
22    #[props(default)]
23    pub style: Option<String>,
24}
25
26/// Timeline component for displaying chronological events
27#[component]
28pub fn Timeline(props: TimelineProps) -> Element {
29    let mut class_names = vec!["el-timeline".to_string()];
30    if props.reverse { class_names.push("is-reverse".to_string()); }
31    if let Some(ref c) = props.class { class_names.push(c.clone()); }
32
33    rsx! {
34        ul {
35            class: "{class_names.join(\" \")}",
36            style: props.style.clone().unwrap_or_default(),
37            {props.children}
38        }
39    }
40}
41
42/// TimelineItem props
43#[derive(Props, Clone, PartialEq)]
44pub struct TimelineItemProps {
45    #[props(default)]
46    pub children: Option<Element>,
47
48    #[props(default)]
49    pub timestamp: Option<String>,
50
51    #[props(default = TimestampPlacement::Bottom)]
52    pub placement: TimestampPlacement,
53
54    #[props(default)]
55    pub icon: Option<String>,
56
57    #[props(default)]
58    pub color: Option<String>,
59
60    #[props(default = "default".to_string())]
61    pub node_type: String,
62
63    #[props(default)]
64    pub class: Option<String>,
65}
66
67/// TimelineItem component for individual timeline events
68#[component]
69pub fn TimelineItem(props: TimelineItemProps) -> Element {
70    let dot_style = props.color.clone().map(|c| format!("background-color: {};", c)).unwrap_or_default();
71
72    rsx! {
73        li {
74            class: "el-timeline-item",
75            div {
76                class: "el-timeline-item__tail",
77            }
78            div {
79                class: "el-timeline-item__node el-timeline-item__node--{props.node_type}",
80                style: "{dot_style}",
81                if let Some(ref icon) = props.icon {
82                    i { class: "{icon}" }
83                }
84            }
85            div {
86                class: "el-timeline-item__wrapper",
87                if let Some(ref timestamp) = props.timestamp {
88                    if props.placement == TimestampPlacement::Top {
89                        div { class: "el-timeline-item__timestamp is-top", "{timestamp}" }
90                    }
91                }
92                div {
93                    class: "el-timeline-item__content",
94                    {props.children}
95                }
96                if let Some(ref timestamp) = props.timestamp {
97                    if props.placement == TimestampPlacement::Bottom {
98                        div { class: "el-timeline-item__timestamp is-bottom", "{timestamp}" }
99                    }
100                }
101            }
102        }
103    }
104}