use maud::{html, Markup, PreEscaped};
#[derive(Debug, Clone)]
pub struct Props {
pub current_page: usize,
pub total_pages: usize,
pub max_visible: usize,
}
impl Default for Props {
fn default() -> Self {
Self {
current_page: 1,
total_pages: 1,
max_visible: 5,
}
}
}
const CHEVRON_LEFT: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>"#;
const CHEVRON_RIGHT: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>"#;
impl Props {
fn visible_pages(&self) -> Vec<usize> {
if self.total_pages <= self.max_visible {
(1..=self.total_pages).collect()
} else {
let mut pages = Vec::new();
pages.push(1);
let start = (self.current_page.saturating_sub(1)).max(2);
let end = (self.current_page + 1).min(self.total_pages - 1);
if start > 2 {
pages.push(0); }
for p in start..=end {
if p > 1 && p < self.total_pages {
pages.push(p);
}
}
if end < self.total_pages - 1 {
pages.push(0); }
pages.push(self.total_pages); pages
}
}
}
pub fn render(props: Props) -> Markup {
let visible = props.visible_pages();
html! {
nav class="mui-pagination" aria-label="Pagination" {
button
class="mui-pagination__btn mui-pagination__btn--prev"
disabled[props.current_page == 1]
{
span class="mui-pagination__btn-icon" { (PreEscaped(CHEVRON_LEFT)) }
"Previous"
}
div class="mui-pagination__pages" {
@for page in visible.iter() {
@if *page == 0 {
span class="mui-pagination__ellipsis" { "..." }
} @else if *page == props.current_page {
button
class="mui-pagination__page"
aria-current="page"
{
(page)
}
} @else {
button class="mui-pagination__page" {
(page)
}
}
}
}
button
class="mui-pagination__btn mui-pagination__btn--next"
disabled[props.current_page == props.total_pages]
{
"Next"
span class="mui-pagination__btn-icon" { (PreEscaped(CHEVRON_RIGHT)) }
}
}
}
}
pub fn showcase() -> Markup {
html! {
div.mui-showcase__grid {
div {
p.mui-showcase__caption { "Search results" }
div style="border:1px solid var(--mui-border);border-radius:var(--mui-radius-lg);padding:1rem;background:var(--mui-bg-card);" {
p style="font-size:0.875rem;color:var(--mui-fg-muted);margin-bottom:0.75rem;" {
"Showing " strong { "21\u{2013}30" } " of " strong { "97" } " results"
}
(render(Props {
current_page: 3,
total_pages: 10,
max_visible: 5,
}))
}
}
div {
p.mui-showcase__caption { "First page" }
(render(Props {
current_page: 1,
total_pages: 10,
max_visible: 5,
}))
}
div {
p.mui-showcase__caption { "Last page" }
(render(Props {
current_page: 10,
total_pages: 10,
max_visible: 5,
}))
}
div {
p.mui-showcase__caption { "Few pages (no ellipsis)" }
(render(Props {
current_page: 2,
total_pages: 3,
max_visible: 5,
}))
}
}
}
}