forked from
smokesignal.events/smokesignal
i18n+filtering fork - fluent-templates v2
1use crate::http::utils::stringify;
2use serde::{Deserialize, Serialize};
3
4pub const PAGE_DEFAULT: i64 = 1;
5pub const PAGE_MIN: i64 = 1;
6pub const PAGE_MAX: i64 = 100;
7pub const PAGE_SIZE_DEFAULT: i64 = 10;
8pub const PAGE_SIZE_MIN: i64 = 5;
9pub const PAGE_SIZE_MAX: i64 = 100;
10
11pub const LIMITED_PAGE_DEFAULT: i64 = 1;
12pub const LIMITED_PAGE_MIN: i64 = 1;
13pub const LIMITED_PAGE_MAX: i64 = 5;
14pub const LIMITED_PAGE_SIZE_DEFAULT: i64 = 5;
15pub const LIMITED_PAGE_SIZE_MIN: i64 = 5;
16pub const LIMITED_PAGE_SIZE_MAX: i64 = 5;
17
18#[derive(Deserialize, Default)]
19pub struct Pagination {
20 pub page: Option<i64>,
21 pub page_size: Option<i64>,
22}
23
24#[derive(Serialize, Debug)]
25pub struct PaginationView {
26 // Legacy fields for backwards compatibility
27 pub previous: Option<i64>,
28 pub previous_url: Option<String>,
29 pub next: Option<i64>,
30 pub next_url: Option<String>,
31
32 // New fields for template compatibility
33 pub current_page: i64,
34 pub has_prev: bool,
35 pub prev_page: i64,
36 pub has_next: bool,
37 pub next_page: i64,
38 pub page_range: Vec<i64>,
39}
40
41impl Pagination {
42 pub fn admin_clamped(&self) -> (i64, i64) {
43 let page = self.page.unwrap_or(1).clamp(1, 25000);
44 let page_size = self.page_size.unwrap_or(1).clamp(20, 100);
45 (page, page_size)
46 }
47
48 pub fn clamped(&self) -> (i64, i64) {
49 let page = self.page.unwrap_or(PAGE_DEFAULT).clamp(PAGE_MIN, PAGE_MAX);
50 let page_size = self
51 .page_size
52 .unwrap_or(PAGE_SIZE_DEFAULT)
53 .clamp(PAGE_SIZE_MIN, PAGE_SIZE_MAX);
54 (page, page_size)
55 }
56}
57
58impl PaginationView {
59 pub fn new(page_size: i64, total: i64, page: i64, params: Vec<(&str, &str)>) -> Self {
60 let total_pages = if total == 0 { 1 } else { (total + page_size - 1) / page_size };
61
62 // Legacy fields for backwards compatibility
63 let (previous, previous_url) = {
64 if page > 1 {
65 let page_value = (page - 1).to_string();
66 let mut page_args: Vec<(&str, &str)> = vec![("page", &page_value)];
67 page_args.extend(params.clone());
68 (Some(page - 1), Some(stringify(page_args)))
69 } else {
70 (None, None)
71 }
72 };
73
74 let (next, next_url) = {
75 if page < total_pages {
76 let page_value = (page + 1).to_string();
77 let mut page_args: Vec<(&str, &str)> = vec![("page", &page_value)];
78 page_args.extend(params.clone());
79 (Some(page + 1), Some(stringify(page_args)))
80 } else {
81 (None, None)
82 }
83 };
84
85 // New fields for template compatibility
86 let current_page = page;
87 let has_prev = page > 1;
88 let prev_page = if has_prev { page - 1 } else { 1 };
89 let has_next = page < total_pages;
90 let next_page = if has_next { page + 1 } else { page };
91
92 // Create page range (show 5 pages around current page)
93 let mut page_range = Vec::new();
94 let range_start = if current_page <= 3 { 1 } else { current_page - 2 };
95 let range_end = std::cmp::min(total_pages, range_start + 4);
96
97 for page_num in range_start..=range_end {
98 page_range.push(page_num);
99 }
100
101 Self {
102 previous,
103 previous_url,
104 next,
105 next_url,
106 current_page,
107 has_prev,
108 prev_page,
109 has_next,
110 next_page,
111 page_range,
112 }
113 }
114}