1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use dioxus::prelude::*;
/// Pagination props
#[derive(Props, Clone, PartialEq)]
pub struct PaginationProps {
/// Total number of items
#[props(default = 0)]
pub total: u32,
/// Current page number
#[props(default = 1)]
pub current_page: u32,
/// Items per page
#[props(default = 10)]
pub page_size: u32,
/// Number of page buttons to show
#[props(default = 7)]
pub pager_count: u32,
/// Whether to show the total count
#[props(default = false)]
pub show_total: bool,
/// Whether to show the page size selector
#[props(default = false)]
pub show_size_picker: bool,
/// Whether to show the "Go to" input
#[props(default = false)]
pub show_jumper: bool,
/// Layout sections
#[props(default = "prev, pager, next".to_string())]
pub layout: String,
/// Whether the pagination is disabled
#[props(default = false)]
pub disabled: bool,
/// Whether to use small size
#[props(default = false)]
pub small: bool,
/// Page size options
#[props(default)]
pub page_sizes: Vec<u32>,
/// Change event handler (current page)
#[props(default)]
pub on_current_change: Option<EventHandler<u32>>,
/// Change event handler (page size)
#[props(default)]
pub on_size_change: Option<EventHandler<u32>>,
#[props(default)]
pub class: Option<String>,
#[props(default)]
pub style: Option<String>,
}
/// Pagination component for navigating paged data
#[component]
pub fn Pagination(props: PaginationProps) -> Element {
let mut class_names = vec!["el-pagination".to_string()];
if props.small { class_names.push("el-pagination--small".to_string()); }
if props.disabled { class_names.push("is-disabled".to_string()); }
if let Some(ref c) = props.class { class_names.push(c.clone()); }
let total_pages = if props.page_size > 0 {
(props.total + props.page_size - 1) / props.page_size
} else {
1
};
let total_pages = total_pages.max(1);
rsx! {
div {
class: "{class_names.join(\" \")}",
style: props.style.clone().unwrap_or_default(),
role: "pagination",
if props.show_total {
span {
class: "el-pagination__total",
"Total {props.total}"
}
}
// Previous button
button {
class: "btn-prev el-pagination__button",
disabled: props.disabled || props.current_page <= 1,
onclick: move |_| {
if !props.disabled && props.current_page > 1 {
if let Some(handler) = props.on_current_change {
handler.call(props.current_page - 1);
}
}
},
"‹"
}
// Page numbers
span {
class: "el-pager",
for page in 1..=total_pages.min(props.pager_count) {
button {
class: {
let mut cls = "el-pager__number".to_string();
if page == props.current_page { cls.push_str(" is-active"); }
cls
},
onclick: move |_| {
if !props.disabled {
if let Some(handler) = props.on_current_change {
handler.call(page);
}
}
},
"{page}"
}
}
if total_pages > props.pager_count {
span { class: "el-icon-more", "..." }
}
}
// Next button
button {
class: "btn-next el-pagination__button",
disabled: props.disabled || props.current_page >= total_pages,
onclick: move |_| {
if !props.disabled && props.current_page < total_pages {
if let Some(handler) = props.on_current_change {
handler.call(props.current_page + 1);
}
}
},
"›"
}
if props.show_jumper {
span {
class: "el-pagination__jump",
"Go to"
input {
r#type: "number",
class: "el-pagination__editor",
value: "{props.current_page}",
disabled: props.disabled,
}
"pages"
}
}
}
}
}