From 848042c304dab2fcd4e2bb82db768799911d04fb Mon Sep 17 00:00:00 2001 From: Priec Date: Thu, 25 Jun 2026 15:38:18 +0200 Subject: [PATCH] page is better in shop now --- assets/i18n/en/main.ftl | 1 + assets/i18n/sk/main.ftl | 1 + assets/views/shop/_search.html | 18 ++++++++++++++++++ src/controllers/shop.rs | 28 ++++++++++++++++++++++++---- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/assets/i18n/en/main.ftl b/assets/i18n/en/main.ftl index 31c1a74..82c97e4 100644 --- a/assets/i18n/en/main.ftl +++ b/assets/i18n/en/main.ftl @@ -315,6 +315,7 @@ order-search-placeholder = Search orders… search-empty = Nothing matched your search: results-count = { $count } products sort-label = Sort +per-page-label = Per page sort-relevance = Relevance sort-newest = Newest sort-price_asc = Price: low to high diff --git a/assets/i18n/sk/main.ftl b/assets/i18n/sk/main.ftl index 379c31f..8fbfcdc 100644 --- a/assets/i18n/sk/main.ftl +++ b/assets/i18n/sk/main.ftl @@ -315,6 +315,7 @@ order-search-placeholder = Hľadať objednávky… search-empty = Pre váš výraz sme nič nenašli: results-count = { $count } produktov sort-label = Zoradiť +per-page-label = Na stránku sort-relevance = Relevancia sort-newest = Najnovšie sort-price_asc = Cena: od najnižšej diff --git a/assets/views/shop/_search.html b/assets/views/shop/_search.html index 6aa38e8..48d6b45 100644 --- a/assets/views/shop/_search.html +++ b/assets/views/shop/_search.html @@ -52,6 +52,24 @@ + + + + + +
diff --git a/src/controllers/shop.rs b/src/controllers/shop.rs index f9f35cf..89429d7 100644 --- a/src/controllers/shop.rs +++ b/src/controllers/shop.rs @@ -22,8 +22,21 @@ use crate::{ views::shop as view, }; -/// Results per page in the storefront listing/search. +/// Default results per page in the storefront listing/search. const PER_PAGE: usize = 24; +/// Allowed per-page choices offered in the toolbar; any other value falls back +/// to [`PER_PAGE`]. +const PER_PAGE_OPTIONS: [usize; 3] = [24, 48, 96]; + +/// Resolve the requested per-page count to one of [`PER_PAGE_OPTIONS`], +/// defaulting to [`PER_PAGE`]. +fn resolve_per_page(params: &SearchParams) -> usize { + params + .per_page + .map(|p| p as usize) + .filter(|p| PER_PAGE_OPTIONS.contains(p)) + .unwrap_or(PER_PAGE) +} /// Hard cap on candidates a single text search considers before faceting; well /// above any realistic page of results for this catalog. const SEARCH_CAP: u64 = 1000; @@ -40,6 +53,7 @@ struct SearchParams { in_stock: Option, sort: Option, page: Option, + per_page: Option, } /// A candidate product with everything the listing needs to filter, sort and @@ -81,6 +95,9 @@ fn query_base(params: &SearchParams) -> String { if let Some(s) = params.sort.as_deref().filter(|s| !s.is_empty()) { ser.append_pair("sort", s); } + if let Some(p) = params.per_page.filter(|p| *p as usize != PER_PAGE) { + ser.append_pair("per_page", &p.to_string()); + } ser.finish() } @@ -198,14 +215,15 @@ async fn run_search( } // 7. Paginate. + let per_page = resolve_per_page(params); let total = items.len(); - let pages = total.div_ceil(PER_PAGE).max(1); + let pages = total.div_ceil(per_page).max(1); let page = params.page.unwrap_or(1).clamp(1, pages as u32); - let start = (page as usize - 1) * PER_PAGE; + let start = (page as usize - 1) * per_page; // 8. Render only the current page's cards (images fetched per row). let mut rows = Vec::new(); - for item in items.iter().skip(start).take(PER_PAGE) { + for item in items.iter().skip(start).take(per_page) { let image = product_images::first_for(ctx, item.product.id).await?; let cat_name = item.product.category_id.and_then(|id| category_name.get(&id).cloned()); rows.push(view::product_card( @@ -229,6 +247,8 @@ async fn run_search( "selected_category_id": selected_category.parse::().unwrap_or(-1), "uncategorized_count": uncategorized_count, "sort": sort, + "per_page": per_page, + "per_page_options": PER_PAGE_OPTIONS, "in_stock": in_stock_only, "min_price": params.min_price.clone().unwrap_or_default(), "max_price": params.max_price.clone().unwrap_or_default(),