kayrx_ui/widget/
pagination.rs

1use crate::fabric::prelude::*;
2
3pub enum Msg {
4    TablePageChange(u32),
5    TablePageUp,
6    TablePageDown,
7}
8
9#[derive(Properties, Clone)]
10pub struct Props {
11    pub onupdate: Callback<u32>,
12    pub total_pages: u32,
13    pub current_page: u32,
14}
15
16pub struct Pagination {
17    link: ComponentLink<Self>,
18    onupdate: Callback<u32>,
19    total_pages: u32,
20    current_page: u32,
21}
22
23impl Component for Pagination {
24    type Message = Msg;
25    type Properties = Props;
26
27    fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
28        Pagination {
29            link,
30            onupdate: props.onupdate,
31            total_pages: props.total_pages,
32            current_page: props.current_page,
33        }
34    }
35
36    fn change(&mut self, props: Self::Properties) -> ShouldRender {
37        self.total_pages = props.total_pages;
38        self.current_page = props.current_page;
39        true
40    }
41
42    fn update(&mut self, msg: Self::Message) -> ShouldRender {
43        match msg {
44            Msg::TablePageChange(n) => self.onupdate.emit(n),
45            Msg::TablePageUp => {
46                if self.current_page < self.total_pages {
47                    self.onupdate.emit(self.current_page + 1)
48                }
49            }
50            Msg::TablePageDown => {
51                if self.current_page > 1 {
52                    self.onupdate.emit(self.current_page - 1)
53                }
54            }
55        }
56        true
57    }
58
59    fn view(&self) -> Html {
60        html! {
61            <div class="table-paging">
62                <button class="table-paging__btn" onclick=self.link.callback(|_| Msg::TablePageDown)
63                    disabled={ self.current_page==1 }>{ "«" }</button>
64                { self.view_pagination_button_first() }
65                { self.view_pagination_buttons_first() }
66                { self.view_pagination_delimiter_first() }
67                { self.view_pagination_button_middle() }
68                { self.view_pagination_delimiter_last() }
69                { self.view_pagination_buttons_last() }
70                { self.view_pagination_button_last() }
71                <button class="table-paging__btn" onclick=self.link.callback(|_| Msg::TablePageUp)
72                    disabled={ self.current_page==self.total_pages }>{ "»" }</button>
73            </div>
74        }
75    }
76}
77
78impl Pagination {
79    fn view_pagination_button_is_active(&self, page: u32) -> &str {
80        let current_page = self.current_page;
81
82        if current_page == page {
83            "table-paging__btn--active"
84        } else {
85            "table-paging__btn"
86        }
87    }
88
89    fn view_pagination_button(&self, page: u32) -> Html {
90        html! {
91            <button class={ self.view_pagination_button_is_active(page) }
92                onclick=self.link.callback(move |_| Msg::TablePageChange(page))>{ page }</button>
93        }
94    }
95
96    fn view_pagination_button_first(&self) -> Html {
97        self.view_pagination_button(1)
98    }
99
100    fn view_pagination_delimiter_first(&self) -> Html {
101        let total_pages = self.total_pages;
102        let current_page = self.current_page;
103
104        if total_pages > 5 && current_page > 3 {
105            html! {
106                <button class="table-paging__btn">{ "..." }</button>
107            }
108        } else {
109            html! {}
110        }
111    }
112
113    fn view_pagination_delimiter_last(&self) -> Html {
114        let total_pages = self.total_pages;
115        let current_page = self.current_page;
116
117        if total_pages > 5 && total_pages - current_page > 2 {
118            html! {
119                <button class="table-paging__btn">{ "..." }</button>
120            }
121        } else {
122            html! {}
123        }
124    }
125
126    fn view_pagination_button_last(&self) -> Html {
127        let total_pages = self.total_pages;
128
129        if total_pages > 5 {
130            self.view_pagination_button(total_pages)
131        } else {
132            html! {}
133        }
134    }
135
136    fn view_pagination_button_middle(&self) -> Html {
137        let total_pages = self.total_pages;
138        let current_page = self.current_page;
139        let total_pages_safe = if total_pages < 2 { 2 } else { total_pages };
140
141        if total_pages > 5 && current_page > 3 && current_page < total_pages_safe - 2 {
142            self.view_pagination_button(current_page)
143        } else {
144            html! {}
145        }
146    }
147
148    fn view_pagination_buttons_first(&self) -> Html {
149        let total_pages = self.total_pages;
150        let current_page = self.current_page;
151
152        let max = if total_pages > 5 { 3 } else { 5 };
153        let through = if total_pages > 5 { 4 } else { 6 };
154
155        html! {
156            { for (2..through).filter_map(|page| {
157                if current_page <= max && total_pages >= page {
158                    Some(self.view_pagination_button(page))
159                } else {
160                    None
161                }
162            }) }
163        }
164    }
165
166    fn view_pagination_buttons_last(&self) -> Html {
167        let total_pages = self.total_pages;
168        let current_page = self.current_page;
169        let total_pages_safe = if total_pages < 2 { 2 } else { total_pages };
170
171        html! {
172            {
173                for (total_pages_safe-2..total_pages_safe).filter_map(|page| {
174                    if total_pages > 5 && current_page > 3 && current_page >= total_pages_safe - 2 {
175                        Some(self.view_pagination_button(page))
176                    } else {
177                        None
178                    }
179                })
180            }
181        }
182    }
183}