diff --git a/demo/src/app.rs b/demo/src/app.rs index e3d4c8f..ba3f23d 100644 --- a/demo/src/app.rs +++ b/demo/src/app.rs @@ -85,13 +85,14 @@ fn TheRouter(is_routing: RwSignal) -> impl IntoView { + - } } { view! { + diff --git a/demo/src/pages/components.rs b/demo/src/pages/components.rs index 11e51d5..6e6b795 100644 --- a/demo/src/pages/components.rs +++ b/demo/src/pages/components.rs @@ -230,6 +230,10 @@ pub(crate) fn gen_menu_data() -> Vec { value: "/components/nav".into(), label: "Nav".into(), }, + MenuItemOption { + value: "pagination".into(), + label: "Pagination".into(), + }, MenuItemOption { value: "/components/popover".into(), label: "Popover".into(), diff --git a/demo_markdown/src/lib.rs b/demo_markdown/src/lib.rs index dd8a5e1..a319ad7 100644 --- a/demo_markdown/src/lib.rs +++ b/demo_markdown/src/lib.rs @@ -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", diff --git a/thaw/Cargo.toml b/thaw/Cargo.toml index fa1c963..a0aabd2 100644 --- a/thaw/Cargo.toml +++ b/thaw/Cargo.toml @@ -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 diff --git a/thaw/src/lib.rs b/thaw/src/lib.rs index be74cd4..9657805 100644 --- a/thaw/src/lib.rs +++ b/thaw/src/lib.rs @@ -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::*; diff --git a/thaw/src/pagination/docs/mod.md b/thaw/src/pagination/docs/mod.md new file mode 100644 index 0000000..30974db --- /dev/null +++ b/thaw/src/pagination/docs/mod.md @@ -0,0 +1,25 @@ +# Pagination + +```rust demo +let page = RwSignal::new(1); + +view! { + +
"Page: " {move || page.get()}
+ +
+} +``` + +### Pagination ranges + +```rust demo +view! { + + + + + + +} +``` diff --git a/thaw/src/pagination/mod.rs b/thaw/src/pagination/mod.rs new file mode 100644 index 0000000..812e236 --- /dev/null +++ b/thaw/src/pagination/mod.rs @@ -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, + #[prop(into)] page_count: MaybeSignal, + #[prop(default = 1.into(), into)] sibling_count: MaybeSignal, + #[prop(optional, into)] class: MaybeProp, +) -> 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! { +
+ + }) + } else { + Either::Right(view! { +
"..."
+ }) + } + }).collect_view() + } + } +
+ } +} + +fn range(start: usize, end: usize) -> Vec { + 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 { + // 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 + } +} diff --git a/thaw/src/pagination/pagination.css b/thaw/src/pagination/pagination.css new file mode 100644 index 0000000..edc5859 --- /dev/null +++ b/thaw/src/pagination/pagination.css @@ -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; +}