defmodule PetalComponents.Pagination do
use Phoenix.Component
alias PetalComponents.Link
import PetalComponents.Helpers
import PetalComponents.PaginationInternal
attr(:path, :string, default: "/:page", doc: "page path")
attr(:class, :string, default: "", doc: "Parent div CSS class")
attr(:link_type, :string,
default: "a",
values: ["a", "live_patch", "live_redirect"]
)
attr(:total_pages, :integer, default: nil, doc: "sets a total page count")
attr(:current_page, :integer, default: nil, doc: "sets the current page")
attr(:sibling_count, :integer, default: 1, doc: "sets a sibling count")
attr(:boundary_count, :integer, default: 1, doc: "sets a boundary count")
attr(:rest, :global)
@doc """
In the `path` param you can specify :page as the place your page number will appear.
e.g "/posts/:page" => "/posts/1"
"""
def pagination(assigns) do
~H"""
<div {@rest} class={"#{@class} pc-pagination"}>
<ul class="pc-pagination__inner">
<%= for item <- get_pagination_items(@total_pages, @current_page, @sibling_count, @boundary_count) do %>
<%= if item.type == "prev" and item.enabled? do %>
<div>
<Link.a
link_type={@link_type}
to={get_path(@path, item.number, @current_page)}
class="pc-pagination__item__previous"
>
<Heroicons.chevron_left solid class="pc-pagination__item__previous__chevron" />
</Link.a>
</div>
<% end %>
<%= if item.type == "page" do %>
<li>
<%= if item.current? do %>
<span class={get_box_class(item)}><%= item.number %></span>
<% else %>
<Link.a
link_type={@link_type}
to={get_path(@path, item.number, @current_page)}
class={get_box_class(item)}
>
<%= item.number %>
</Link.a>
<% end %>
</li>
<% end %>
<%= if item.type == "..." do %>
<li>
<span class="pc-pagination__item__ellipsis">
...
</span>
</li>
<% end %>
<%= if item.type == "next" and item.enabled? do %>
<div>
<Link.a
link_type={@link_type}
to={get_path(@path, item.number, @current_page)}
class="pc-pagination__item__next"
>
<Heroicons.chevron_right solid class="pc-pagination__item__next__chevron" />
</Link.a>
</div>
<% end %>
<% end %>
</ul>
</div>
"""
end
defp get_box_class(item) do
base_classes = "pc-pagination__item"
active_classes =
if item.current?,
do: "pc-pagination__item--is-current",
else: "pc-pagination__item--is-not-current"
rounded_classes =
case item do
%{first?: true, last?: true} ->
"pc-pagination__item--with-single-box"
%{first?: true, last?: false} ->
"pc-pagination__item--with-multiple-boxes--left"
%{first?: false, last?: true} ->
"pc-pagination__item--with-multiple-boxes--right"
_ ->
"pc-pagination__item--rounded-catch-all"
end
build_class([base_classes, active_classes, rounded_classes])
end
defp get_path(path, page_number, current_page) when is_binary(path) do
get_path(&String.replace(path, ":page", Integer.to_string(&1)), page_number, current_page)
end
defp get_path(fun, "previous", current_page) when is_function(fun, 1) do
get_path(fun, current_page - 1, current_page)
end
defp get_path(fun, "next", current_page) when is_function(fun, 1) do
get_path(fun, current_page + 1, current_page)
end
defp get_path(fun, page_number, _current_page) when is_function(fun, 1) do
then(page_number, fun)
end
end