add pagination across all admin and shop views
All checks were successful
deploy / deploy (push) Successful in 1m38s

URL-based offset pagination with ?page=N for bookmarkable pages.
Admin views use push_patch, shop collection uses navigate links.
Responsive on mobile with horizontal-scroll tables and stacking
pagination controls. Includes dev seed script for testing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-01 09:42:34 +00:00
parent 7f6fd012a5
commit 3480b326a9
21 changed files with 1485 additions and 211 deletions

View File

@@ -1714,4 +1714,84 @@ defmodule BerrypodWeb.ShopComponents.Product do
</div>
"""
end
# ── Shop pagination ────────────────────────────────────────────
@doc """
Renders pagination controls for the shop collection page.
Uses URL navigation (`<.link navigate=...>`) so pages are bookmarkable.
## Attributes
* `page` - Required. A `%Berrypod.Pagination{}` struct.
* `base_path` - Required. The base URL path (e.g. "/collections/all").
* `params` - Extra query params to preserve (e.g. %{"sort" => "newest"}).
"""
attr :page, Berrypod.Pagination, required: true
attr :base_path, :string, required: true
attr :params, :map, default: %{}
def shop_pagination(assigns) do
assigns =
assigns
|> assign(:showing, Berrypod.Pagination.showing_text(assigns.page))
|> assign(:numbers, Berrypod.Pagination.page_numbers(assigns.page))
~H"""
<nav
:if={@page.total_pages > 1}
aria-label="Pagination"
class="shop-pagination"
>
<p class="shop-pagination-showing">{@showing}</p>
<div class="shop-pagination-buttons">
<.link
:if={@page.page > 1}
navigate={pagination_url(@base_path, @page.page - 1, @params)}
class="shop-pagination-btn"
aria-label="Previous page"
>
&lsaquo; Prev
</.link>
<%= for item <- @numbers do %>
<%= case item do %>
<% :ellipsis -> %>
<span class="shop-pagination-ellipsis" aria-hidden="true">&hellip;</span>
<% n -> %>
<.link
navigate={pagination_url(@base_path, n, @params)}
aria-label={"Page #{n}"}
aria-current={n == @page.page && "page"}
class={["shop-pagination-btn", n == @page.page && "shop-pagination-btn-active"]}
>
{n}
</.link>
<% end %>
<% end %>
<.link
:if={@page.page < @page.total_pages}
navigate={pagination_url(@base_path, @page.page + 1, @params)}
class="shop-pagination-btn"
aria-label="Next page"
>
Next &rsaquo;
</.link>
</div>
</nav>
"""
end
defp pagination_url(base_path, page, params) do
query = if page > 1, do: Map.put(params, "page", to_string(page)), else: params
if query == %{} do
base_path
else
base_path <> "?" <> URI.encode_query(query)
end
end
end