mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-23 06:19: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("loading-bar") view=LoadingBarMdPage/>
|
||||||
<Route path=StaticSegment("message-bar") view=MessageBarMdPage/>
|
<Route path=StaticSegment("message-bar") view=MessageBarMdPage/>
|
||||||
<Route path=StaticSegment("nav") view=NavMdPage/>
|
<Route path=StaticSegment("nav") view=NavMdPage/>
|
||||||
|
<Route path=StaticSegment("pagination") view=PaginationMdPage/>
|
||||||
<Route path=StaticSegment("popover") view=PopoverMdPage/>
|
<Route path=StaticSegment("popover") view=PopoverMdPage/>
|
||||||
<Route path=StaticSegment("progress-bar") view=ProgressBarMdPage/>
|
<Route path=StaticSegment("progress-bar") view=ProgressBarMdPage/>
|
||||||
<Route path=StaticSegment("radio") view=RadioMdPage/>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
view! {
|
view! {
|
||||||
|
<Route path=StaticSegment("radio") view=RadioMdPage/>
|
||||||
<Route path=StaticSegment("scrollbar") view=ScrollbarMdPage/>
|
<Route path=StaticSegment("scrollbar") view=ScrollbarMdPage/>
|
||||||
<Route path=StaticSegment("skeleton") view=SkeletonMdPage/>
|
<Route path=StaticSegment("skeleton") view=SkeletonMdPage/>
|
||||||
<Route path=StaticSegment("slider") view=SliderMdPage/>
|
<Route path=StaticSegment("slider") view=SliderMdPage/>
|
||||||
|
|
|
@ -230,6 +230,10 @@ pub(crate) fn gen_menu_data() -> Vec<MenuGroupOption> {
|
||||||
value: "/components/nav".into(),
|
value: "/components/nav".into(),
|
||||||
label: "Nav".into(),
|
label: "Nav".into(),
|
||||||
},
|
},
|
||||||
|
MenuItemOption {
|
||||||
|
value: "pagination".into(),
|
||||||
|
label: "Pagination".into(),
|
||||||
|
},
|
||||||
MenuItemOption {
|
MenuItemOption {
|
||||||
value: "/components/popover".into(),
|
value: "/components/popover".into(),
|
||||||
label: "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",
|
"MenuMdPage" => "../docs/menu/mod.md",
|
||||||
"MessageBarMdPage" => "../docs/message_bar/mod.md",
|
"MessageBarMdPage" => "../docs/message_bar/mod.md",
|
||||||
"NavMdPage" => "../docs/nav/mod.md",
|
"NavMdPage" => "../docs/nav/mod.md",
|
||||||
|
"PaginationMdPage" => "../../thaw/src/pagination/docs/mod.md",
|
||||||
"PopoverMdPage" => "../docs/popover/mod.md",
|
"PopoverMdPage" => "../docs/popover/mod.md",
|
||||||
"ProgressBarMdPage" => "../docs/progress_bar/mod.md",
|
"ProgressBarMdPage" => "../docs/progress_bar/mod.md",
|
||||||
"RadioMdPage" => "../docs/radio/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"
|
homepage = "https://github.com/thaw-ui/thaw"
|
||||||
repository = "https://github.com/thaw-ui/thaw"
|
repository = "https://github.com/thaw-ui/thaw"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
exclude = ["src/**/*.md"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# 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 menu;
|
||||||
mod message_bar;
|
mod message_bar;
|
||||||
mod nav;
|
mod nav;
|
||||||
|
mod pagination;
|
||||||
mod popover;
|
mod popover;
|
||||||
mod progress_bar;
|
mod progress_bar;
|
||||||
mod radio;
|
mod radio;
|
||||||
|
@ -75,6 +76,7 @@ pub use loading_bar::*;
|
||||||
pub use menu::*;
|
pub use menu::*;
|
||||||
pub use message_bar::*;
|
pub use message_bar::*;
|
||||||
pub use nav::*;
|
pub use nav::*;
|
||||||
|
pub use pagination::*;
|
||||||
pub use popover::*;
|
pub use popover::*;
|
||||||
pub use progress_bar::*;
|
pub use progress_bar::*;
|
||||||
pub use radio::*;
|
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