Initial Commit
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
defmodule RiverConnectWeb.Components.UI.Pagination do
|
||||
@moduledoc """
|
||||
Implementation of pagination component for navigation between pages of content.
|
||||
|
||||
## Examples:
|
||||
|
||||
<.pagination>
|
||||
<.pagination_content>
|
||||
<.pagination_item>
|
||||
<.pagination_previous href="#" />
|
||||
</.pagination_item>
|
||||
<.pagination_item>
|
||||
<.pagination_link href="#" is_active={@page == 1}>1</.pagination_link>
|
||||
</.pagination_item>
|
||||
<.pagination_item>
|
||||
<.pagination_link href="#" is_active={@page == 2}>2</.pagination_link>
|
||||
</.pagination_item>
|
||||
<.pagination_item>
|
||||
<.pagination_link href="#" is_active={@page == 3}>3</.pagination_link>
|
||||
</.pagination_item>
|
||||
<.pagination_item>
|
||||
<.pagination_ellipsis />
|
||||
</.pagination_item>
|
||||
<.pagination_item>
|
||||
<.pagination_next href="#" />
|
||||
</.pagination_item>
|
||||
</.pagination_content>
|
||||
</.pagination>
|
||||
"""
|
||||
use RiverConnectWeb.Components.UI, :component
|
||||
|
||||
@doc """
|
||||
Renders a pagination component.
|
||||
"""
|
||||
attr :class, :string, default: nil
|
||||
attr :rest, :global
|
||||
slot :inner_block, required: true
|
||||
|
||||
def pagination(assigns) do
|
||||
~H"""
|
||||
<nav
|
||||
aria-label="pagination"
|
||||
role="pagination"
|
||||
class={
|
||||
classes([
|
||||
"mx-auto flex w-full justify-center",
|
||||
@class
|
||||
])
|
||||
}
|
||||
{@rest}
|
||||
>
|
||||
{render_slot(@inner_block)}
|
||||
</nav>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders pagination content wrapper.
|
||||
"""
|
||||
attr :class, :string, default: nil
|
||||
attr :rest, :global
|
||||
slot :inner_block, required: true
|
||||
|
||||
def pagination_content(assigns) do
|
||||
~H"""
|
||||
<ul
|
||||
class={
|
||||
classes([
|
||||
"flex flex-row items-center gap-1",
|
||||
@class
|
||||
])
|
||||
}
|
||||
{@rest}
|
||||
>
|
||||
{render_slot(@inner_block)}
|
||||
</ul>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a pagination item container.
|
||||
"""
|
||||
attr :class, :string, default: nil
|
||||
attr :rest, :global
|
||||
slot :inner_block, required: true
|
||||
|
||||
def pagination_item(assigns) do
|
||||
~H"""
|
||||
<li
|
||||
class={
|
||||
classes([
|
||||
"",
|
||||
@class
|
||||
])
|
||||
}
|
||||
{@rest}
|
||||
>
|
||||
{render_slot(@inner_block)}
|
||||
</li>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a pagination link.
|
||||
|
||||
## Options
|
||||
|
||||
* `:is_active` - Whether this link represents the current page
|
||||
* `:size` - Link size variant (default, sm, lg, icon)
|
||||
"""
|
||||
attr :"is-active", :boolean, default: false
|
||||
attr :size, :string, default: "icon", values: ~w(default sm lg icon)
|
||||
attr :class, :string, default: nil
|
||||
attr :rest, :global
|
||||
slot :inner_block, required: true
|
||||
|
||||
def pagination_link(assigns) do
|
||||
is_active = assigns[:"is-active"] in [true, "true"]
|
||||
|
||||
assigns =
|
||||
assigns
|
||||
|> assign(
|
||||
:variation_class,
|
||||
variant(%{size: assigns[:size], variant: (is_active && "outline") || "ghost"})
|
||||
)
|
||||
|> assign(:"is-active", is_active)
|
||||
|
||||
~H"""
|
||||
<.link
|
||||
aria-current={(assigns[:"is-active"] && "page") || ""}
|
||||
class={
|
||||
classes([
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:ring-ring focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50",
|
||||
@variation_class,
|
||||
@class
|
||||
])
|
||||
}
|
||||
{@rest}
|
||||
>
|
||||
{render_slot(@inner_block)}
|
||||
</.link>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a next page button.
|
||||
"""
|
||||
attr :class, :string, default: nil
|
||||
attr :rest, :global
|
||||
|
||||
def pagination_next(assigns) do
|
||||
~H"""
|
||||
<.pagination_link
|
||||
aria-label="Go to next page"
|
||||
size="default"
|
||||
class={classes(["gap-1 pr-2.5", @class])}
|
||||
{@rest}
|
||||
>
|
||||
<span>Next</span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
class="size-6 w-3.5"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5" />
|
||||
</svg>
|
||||
</.pagination_link>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a previous page button.
|
||||
"""
|
||||
attr :class, :string, default: nil
|
||||
attr :rest, :global
|
||||
|
||||
def pagination_previous(assigns) do
|
||||
~H"""
|
||||
<.pagination_link
|
||||
aria-label="Go to previous page"
|
||||
size="default"
|
||||
class={classes(["gap-1 pr-2.5", @class])}
|
||||
{@rest}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
class="size-6 w-3.5"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
|
||||
</svg>
|
||||
<span>Previous</span>
|
||||
</.pagination_link>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders an ellipsis for page ranges.
|
||||
"""
|
||||
attr :class, :string, default: nil
|
||||
attr :rest, :global
|
||||
|
||||
def pagination_ellipsis(assigns) do
|
||||
~H"""
|
||||
<span
|
||||
class={
|
||||
classes([
|
||||
"flex h-9 w-9 items-center justify-center",
|
||||
@class
|
||||
])
|
||||
}
|
||||
{@rest}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke="currentColor"
|
||||
class="size-6 w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M6.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM12.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0ZM18.75 12a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span class="sr-only">More pages</span>
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
@variants %{
|
||||
variant: %{
|
||||
"outline" =>
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
"ghost" => "hover:bg-accent hover:text-accent-foreground"
|
||||
},
|
||||
size: %{
|
||||
"default" => "h-9 px-4 py-2",
|
||||
"sm" => "h-8 rounded-md px-3 text-xs",
|
||||
"lg" => "h-10 rounded-md px-8",
|
||||
"icon" => "h-9 w-9"
|
||||
}
|
||||
}
|
||||
|
||||
defp variant(props) do
|
||||
variants =
|
||||
Map.take(props, ~w(variant size)a)
|
||||
|
||||
Enum.map_join(variants, " ", fn {key, value} -> @variants[key][value] end)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user