|
| 1 | +use dioxus::prelude::*; |
| 2 | + |
| 3 | +#[derive(Copy, Clone, PartialEq, Default)] |
| 4 | +#[non_exhaustive] |
| 5 | +pub enum PaginationLinkSize { |
| 6 | + #[default] |
| 7 | + Icon, |
| 8 | + Default, |
| 9 | +} |
| 10 | + |
| 11 | +impl PaginationLinkSize { |
| 12 | + pub fn class(&self) -> &'static str { |
| 13 | + match self { |
| 14 | + PaginationLinkSize::Icon => "icon", |
| 15 | + PaginationLinkSize::Default => "default", |
| 16 | + } |
| 17 | + } |
| 18 | +} |
| 19 | + |
| 20 | +#[derive(Copy, Clone, PartialEq)] |
| 21 | +#[non_exhaustive] |
| 22 | +pub enum PaginationLinkKind { |
| 23 | + Previous, |
| 24 | + Next, |
| 25 | +} |
| 26 | + |
| 27 | +impl PaginationLinkKind { |
| 28 | + pub fn attr(&self) -> &'static str { |
| 29 | + match self { |
| 30 | + PaginationLinkKind::Previous => "previous", |
| 31 | + PaginationLinkKind::Next => "next", |
| 32 | + } |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +#[component] |
| 37 | +pub fn Pagination( |
| 38 | + #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>, |
| 39 | + children: Element, |
| 40 | +) -> Element { |
| 41 | + rsx! { |
| 42 | + document::Link { rel: "stylesheet", href: asset!("./style.css") } |
| 43 | + nav { |
| 44 | + class: "pagination", |
| 45 | + "data-slot": "pagination", |
| 46 | + role: "navigation", |
| 47 | + aria_label: "pagination", |
| 48 | + ..attributes, |
| 49 | + {children} |
| 50 | + } |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +#[component] |
| 55 | +pub fn PaginationContent( |
| 56 | + #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>, |
| 57 | + children: Element, |
| 58 | +) -> Element { |
| 59 | + rsx! { |
| 60 | + ul { |
| 61 | + class: "pagination-content", |
| 62 | + "data-slot": "pagination-content", |
| 63 | + ..attributes, |
| 64 | + {children} |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +#[component] |
| 70 | +pub fn PaginationItem( |
| 71 | + #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>, |
| 72 | + children: Element, |
| 73 | +) -> Element { |
| 74 | + rsx! { |
| 75 | + li { |
| 76 | + class: "pagination-item", |
| 77 | + "data-slot": "pagination-item", |
| 78 | + ..attributes, |
| 79 | + {children} |
| 80 | + } |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +#[derive(Props, Clone, PartialEq)] |
| 85 | +pub struct PaginationLinkProps { |
| 86 | + #[props(default)] |
| 87 | + pub is_active: bool, |
| 88 | + #[props(default)] |
| 89 | + pub size: PaginationLinkSize, |
| 90 | + #[props(default)] |
| 91 | + pub data_kind: Option<PaginationLinkKind>, |
| 92 | + onclick: Option<EventHandler<MouseEvent>>, |
| 93 | + onmousedown: Option<EventHandler<MouseEvent>>, |
| 94 | + onmouseup: Option<EventHandler<MouseEvent>>, |
| 95 | + #[props(extends = GlobalAttributes)] |
| 96 | + #[props(extends = a)] |
| 97 | + pub attributes: Vec<Attribute>, |
| 98 | + pub children: Element, |
| 99 | +} |
| 100 | + |
| 101 | +#[component] |
| 102 | +pub fn PaginationLink(props: PaginationLinkProps) -> Element { |
| 103 | + let aria_current = if props.is_active { Some("page") } else { None }; |
| 104 | + let data_kind = props.data_kind.map(|kind| kind.attr()); |
| 105 | + rsx! { |
| 106 | + a { |
| 107 | + class: "pagination-link", |
| 108 | + "data-slot": "pagination-link", |
| 109 | + "data-active": props.is_active, |
| 110 | + "data-size": props.size.class(), |
| 111 | + "data-kind": data_kind, |
| 112 | + aria_current: aria_current, |
| 113 | + onclick: move |event| { |
| 114 | + if let Some(f) = &props.onclick { |
| 115 | + f.call(event); |
| 116 | + } |
| 117 | + }, |
| 118 | + onmousedown: move |event| { |
| 119 | + if let Some(f) = &props.onmousedown { |
| 120 | + f.call(event); |
| 121 | + } |
| 122 | + }, |
| 123 | + onmouseup: move |event| { |
| 124 | + if let Some(f) = &props.onmouseup { |
| 125 | + f.call(event); |
| 126 | + } |
| 127 | + }, |
| 128 | + ..props.attributes, |
| 129 | + {props.children} |
| 130 | + } |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +#[component] |
| 135 | +pub fn PaginationPrevious( |
| 136 | + onclick: Option<EventHandler<MouseEvent>>, |
| 137 | + onmousedown: Option<EventHandler<MouseEvent>>, |
| 138 | + onmouseup: Option<EventHandler<MouseEvent>>, |
| 139 | + #[props(extends = GlobalAttributes)] |
| 140 | + #[props(extends = a)] |
| 141 | + attributes: Vec<Attribute>, |
| 142 | +) -> Element { |
| 143 | + rsx! { |
| 144 | + PaginationLink { |
| 145 | + size: PaginationLinkSize::Default, |
| 146 | + aria_label: "Go to previous page", |
| 147 | + data_kind: Some(PaginationLinkKind::Previous), |
| 148 | + onclick, |
| 149 | + onmousedown, |
| 150 | + onmouseup, |
| 151 | + attributes, |
| 152 | + // ChevronLeft icon from lucide https://lucide.dev/icons/chevron-left |
| 153 | + svg { |
| 154 | + class: "pagination-icon", |
| 155 | + view_box: "0 0 24 24", |
| 156 | + xmlns: "http://www.w3.org/2000/svg", |
| 157 | + polyline { points: "15 6 9 12 15 18" } |
| 158 | + } |
| 159 | + span { class: "pagination-label", "Previous" } |
| 160 | + } |
| 161 | + } |
| 162 | +} |
| 163 | + |
| 164 | +#[component] |
| 165 | +pub fn PaginationNext( |
| 166 | + onclick: Option<EventHandler<MouseEvent>>, |
| 167 | + onmousedown: Option<EventHandler<MouseEvent>>, |
| 168 | + onmouseup: Option<EventHandler<MouseEvent>>, |
| 169 | + #[props(extends = GlobalAttributes)] |
| 170 | + #[props(extends = a)] |
| 171 | + attributes: Vec<Attribute>, |
| 172 | +) -> Element { |
| 173 | + rsx! { |
| 174 | + PaginationLink { |
| 175 | + size: PaginationLinkSize::Default, |
| 176 | + aria_label: "Go to next page", |
| 177 | + data_kind: Some(PaginationLinkKind::Next), |
| 178 | + onclick, |
| 179 | + onmousedown, |
| 180 | + onmouseup, |
| 181 | + attributes, |
| 182 | + span { class: "pagination-label", "Next" } |
| 183 | + // ChevronRight icon from lucide https://lucide.dev/icons/chevron-right |
| 184 | + svg { |
| 185 | + class: "pagination-icon", |
| 186 | + view_box: "0 0 24 24", |
| 187 | + xmlns: "http://www.w3.org/2000/svg", |
| 188 | + polyline { points: "9 6 15 12 9 18" } |
| 189 | + } |
| 190 | + } |
| 191 | + } |
| 192 | +} |
| 193 | + |
| 194 | +#[component] |
| 195 | +pub fn PaginationEllipsis( |
| 196 | + #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>, |
| 197 | +) -> Element { |
| 198 | + rsx! { |
| 199 | + span { |
| 200 | + class: "pagination-ellipsis", |
| 201 | + "data-slot": "pagination-ellipsis", |
| 202 | + aria_hidden: "true", |
| 203 | + ..attributes, |
| 204 | + // MoreHorizontal icon from lucide https://lucide.dev/icons/more-horizontal |
| 205 | + svg { |
| 206 | + class: "pagination-icon", |
| 207 | + view_box: "0 0 24 24", |
| 208 | + xmlns: "http://www.w3.org/2000/svg", |
| 209 | + circle { cx: "5", cy: "12", r: "1.5" } |
| 210 | + circle { cx: "12", cy: "12", r: "1.5" } |
| 211 | + circle { cx: "19", cy: "12", r: "1.5" } |
| 212 | + } |
| 213 | + span { class: "sr-only", "More pages" } |
| 214 | + } |
| 215 | + } |
| 216 | +} |
0 commit comments