mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
feat: adds Pagination
This commit is contained in:
parent
9e0bf0eaa7
commit
0b8a89caab
8 changed files with 193 additions and 1 deletions
|
@ -85,13 +85,14 @@ fn TheRouter(is_routing: RwSignal<bool>) -> impl IntoView {
|
|||
<Route path=StaticSegment("loading-bar") view=LoadingBarMdPage/>
|
||||
<Route path=StaticSegment("message-bar") view=MessageBarMdPage/>
|
||||
<Route path=StaticSegment("nav") view=NavMdPage/>
|
||||
<Route path=StaticSegment("pagination") view=PaginationMdPage/>
|
||||
<Route path=StaticSegment("popover") view=PopoverMdPage/>
|
||||
<Route path=StaticSegment("progress-bar") view=ProgressBarMdPage/>
|
||||
<Route path=StaticSegment("radio") view=RadioMdPage/>
|
||||
}
|
||||
}
|
||||
{
|
||||
view! {
|
||||
<Route path=StaticSegment("radio") view=RadioMdPage/>
|
||||
<Route path=StaticSegment("scrollbar") view=ScrollbarMdPage/>
|
||||
<Route path=StaticSegment("skeleton") view=SkeletonMdPage/>
|
||||
<Route path=StaticSegment("slider") view=SliderMdPage/>
|
||||
|
|
|
@ -230,6 +230,10 @@ pub(crate) fn gen_menu_data() -> Vec<MenuGroupOption> {
|
|||
value: "/components/nav".into(),
|
||||
label: "Nav".into(),
|
||||
},
|
||||
MenuItemOption {
|
||||
value: "pagination".into(),
|
||||
label: "Pagination".into(),
|
||||
},
|
||||
MenuItemOption {
|
||||
value: "/components/popover".into(),
|
||||
label: "Popover".into(),
|
||||
|
|
|
@ -54,6 +54,7 @@ pub fn include_md(_token_stream: proc_macro::TokenStream) -> proc_macro::TokenSt
|
|||
"MenuMdPage" => "../docs/menu/mod.md",
|
||||
"MessageBarMdPage" => "../docs/message_bar/mod.md",
|
||||
"NavMdPage" => "../docs/nav/mod.md",
|
||||
"PaginationMdPage" => "../../thaw/src/pagination/docs/mod.md",
|
||||
"PopoverMdPage" => "../docs/popover/mod.md",
|
||||
"ProgressBarMdPage" => "../docs/progress_bar/mod.md",
|
||||
"RadioMdPage" => "../docs/radio/mod.md",
|
||||
|
|
|
@ -9,6 +9,7 @@ description = "An easy to use leptos component library"
|
|||
homepage = "https://github.com/thaw-ui/thaw"
|
||||
repository = "https://github.com/thaw-ui/thaw"
|
||||
license = "MIT"
|
||||
exclude = ["src/**/*.md"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ mod loading_bar;
|
|||
mod menu;
|
||||
mod message_bar;
|
||||
mod nav;
|
||||
mod pagination;
|
||||
mod popover;
|
||||
mod progress_bar;
|
||||
mod radio;
|
||||
|
@ -75,6 +76,7 @@ pub use loading_bar::*;
|
|||
pub use menu::*;
|
||||
pub use message_bar::*;
|
||||
pub use nav::*;
|
||||
pub use pagination::*;
|
||||
pub use popover::*;
|
||||
pub use progress_bar::*;
|
||||
pub use radio::*;
|
||||
|
|
25
thaw/src/pagination/docs/mod.md
Normal file
25
thaw/src/pagination/docs/mod.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Pagination
|
||||
|
||||
```rust demo
|
||||
let page = RwSignal::new(1);
|
||||
|
||||
view! {
|
||||
<Space vertical=true>
|
||||
<div>"Page: " {move || page.get()}</div>
|
||||
<Pagination page page_count=10 />
|
||||
</Space>
|
||||
}
|
||||
```
|
||||
|
||||
### Pagination ranges
|
||||
|
||||
```rust demo
|
||||
view! {
|
||||
<Space vertical=true>
|
||||
<Pagination page_count=100 sibling_count=0 />
|
||||
<Pagination page_count=100 sibling_count=1 />
|
||||
<Pagination page_count=100 sibling_count=2 />
|
||||
<Pagination page_count=100 sibling_count=3 />
|
||||
</Space>
|
||||
}
|
||||
```
|
143
thaw/src/pagination/mod.rs
Normal file
143
thaw/src/pagination/mod.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
use crate::{Button, ButtonAppearance};
|
||||
use leptos::{either::Either, prelude::*};
|
||||
use std::cmp::min;
|
||||
use thaw_utils::{class_list, mount_style, Model};
|
||||
|
||||
#[component]
|
||||
pub fn Pagination(
|
||||
#[prop(default = 1.into(), into)] page: Model<usize>,
|
||||
#[prop(into)] page_count: MaybeSignal<usize>,
|
||||
#[prop(default = 1.into(), into)] sibling_count: MaybeSignal<usize>,
|
||||
#[prop(optional, into)] class: MaybeProp<String>,
|
||||
) -> impl IntoView {
|
||||
mount_style("pagination", include_str!("./pagination.css"));
|
||||
|
||||
let no_next = Memo::new(move |_| page.get() == page_count.get());
|
||||
let no_previous = Memo::new(move |_| page.get() == 1);
|
||||
|
||||
let on_click_previous = move |_| {
|
||||
page.update(|val| *val -= 1);
|
||||
};
|
||||
|
||||
let on_click_next = move |_| {
|
||||
page.update(|val| *val += 1);
|
||||
};
|
||||
|
||||
view! {
|
||||
<div class=class_list!["thaw-pagination", class]>
|
||||
<Button
|
||||
class="thaw-pagination-item"
|
||||
on_click=on_click_previous
|
||||
icon=icondata_ai::AiLeftOutlined
|
||||
disabled=no_previous
|
||||
/>
|
||||
{
|
||||
move || {
|
||||
use_pagination(page.get(), page_count.get(), sibling_count.get()).into_iter().map(|item| {
|
||||
if let PaginationItem::Number(nb) = item {
|
||||
Either::Left(view! {
|
||||
<Button
|
||||
class="thaw-pagination-item"
|
||||
appearance=Memo::new(move |_| if page.get() == nb {
|
||||
ButtonAppearance::Primary
|
||||
} else {
|
||||
ButtonAppearance::Secondary
|
||||
})
|
||||
on_click=move |_| {
|
||||
if page.get() != nb {
|
||||
page.set(nb)
|
||||
}
|
||||
}
|
||||
>
|
||||
{nb}
|
||||
</Button>
|
||||
})
|
||||
} else {
|
||||
Either::Right(view! {
|
||||
<div class="thaw-pagination-item">"..."</div>
|
||||
})
|
||||
}
|
||||
}).collect_view()
|
||||
}
|
||||
}
|
||||
<Button
|
||||
class="thaw-pagination-item"
|
||||
on_click=on_click_next
|
||||
icon=icondata_ai::AiRightOutlined
|
||||
disabled=no_next
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
fn range(start: usize, end: usize) -> Vec<PaginationItem> {
|
||||
let mut ret = vec![];
|
||||
for idx in start..=end {
|
||||
ret.push(PaginationItem::Number(idx));
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
enum PaginationItem {
|
||||
DotLeft,
|
||||
DotRight,
|
||||
Number(usize),
|
||||
}
|
||||
|
||||
fn use_pagination(page: usize, count: usize, sibling_count: usize) -> Vec<PaginationItem> {
|
||||
// Pages count is determined as siblingCount + firstPage + lastPage + currentPage + 2*DOTS
|
||||
let total_page_numbers = sibling_count + 5;
|
||||
// Case 1:
|
||||
// If the number of pages is less than the page numbers we want to show in our
|
||||
// paginationComponent, we return the range [1..totalPageCount]
|
||||
if total_page_numbers >= count {
|
||||
return range(1, count);
|
||||
}
|
||||
let current_page = page;
|
||||
// Calculate left and right sibling index and make sure they are within range 1 and totalPageCount
|
||||
let left_sibling_index = if current_page > sibling_count + 1 {
|
||||
current_page - sibling_count
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let right_sibling_index = min(current_page + sibling_count, count);
|
||||
// We do not show dots just when there is just one page number to be inserted between the extremes of sibling and the page limits i.e 1 and totalPageCount.
|
||||
// Hence we are using leftSiblingIndex > 2 and rightSiblingIndex < totalPageCount - 2
|
||||
let should_show_left_dots = left_sibling_index > 2;
|
||||
let should_show_right_dots = right_sibling_index < count - 2;
|
||||
|
||||
let first_page_index = 1;
|
||||
let last_page_index = count;
|
||||
|
||||
// Case 2: No left dots to show, but rights dots to be shown
|
||||
if !should_show_left_dots && should_show_right_dots {
|
||||
let left_item_count = 3 + 2 * sibling_count;
|
||||
let mut left_range = range(1, left_item_count);
|
||||
left_range.push(PaginationItem::DotRight);
|
||||
left_range.push(PaginationItem::Number(count));
|
||||
left_range
|
||||
} else if should_show_left_dots && !should_show_right_dots {
|
||||
// Case 3: No right dots to show, but left dots to be shown
|
||||
let right_item_count = 3 + 2 * sibling_count;
|
||||
let mut right_range = range(count - right_item_count + 1, count);
|
||||
let mut ret = vec![
|
||||
PaginationItem::Number(first_page_index),
|
||||
PaginationItem::DotLeft,
|
||||
];
|
||||
ret.append(&mut right_range);
|
||||
ret
|
||||
} else {
|
||||
// Case 4: Both left and right dots to be shown
|
||||
let mut middle_range = range(left_sibling_index, right_sibling_index);
|
||||
let mut range = vec![
|
||||
PaginationItem::Number(first_page_index),
|
||||
PaginationItem::DotLeft,
|
||||
];
|
||||
range.append(&mut middle_range);
|
||||
range.append(&mut vec![
|
||||
PaginationItem::DotRight,
|
||||
PaginationItem::Number(last_page_index),
|
||||
]);
|
||||
range
|
||||
}
|
||||
}
|
15
thaw/src/pagination/pagination.css
Normal file
15
thaw/src/pagination/pagination.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
.thaw-pagination {
|
||||
display: flex;
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
.thaw-pagination-item,
|
||||
.thaw-button.thaw-pagination-item {
|
||||
max-width: 32px;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
div.thaw-pagination-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
Loading…
Add table
Reference in a new issue