pagination
This commit is contained in:
parent
464f3a0ae3
commit
4f3e1d3a8d
10 changed files with 77 additions and 6 deletions
|
@ -51,4 +51,6 @@ config :tailwind,
|
|||
cd: Path.expand("../assets", __DIR__)
|
||||
]
|
||||
|
||||
config :flop, repo: Core.Repo
|
||||
|
||||
import_config "#{config_env()}.exs"
|
||||
|
|
|
@ -37,6 +37,13 @@ defmodule Core.Posts do
|
|||
|> Core.Repo.all()
|
||||
end
|
||||
|
||||
def list_published_posts(kind, params \\ %{}) do
|
||||
Post.Query.base()
|
||||
|> Post.Query.published()
|
||||
|> Post.Query.where_kind(kind)
|
||||
|> Flop.validate_and_run(params, for: Schema.Post)
|
||||
end
|
||||
|
||||
def publish_date(%Schema.Post{published_at: nil}), do: nil
|
||||
|
||||
def publish_date(%Schema.Post{published_at: published_at}) do
|
||||
|
|
|
@ -2,6 +2,20 @@ defmodule Schema.Post do
|
|||
@moduledoc false
|
||||
use Schema
|
||||
|
||||
@derive {
|
||||
Flop.Schema,
|
||||
filterable: [],
|
||||
sortable: [:published_at, :id],
|
||||
pagination_types: [:first, :last],
|
||||
default_order: %{
|
||||
order_by: [:published_at, :id],
|
||||
order_directions: [:desc, :desc]
|
||||
},
|
||||
default_pagination_type: :first,
|
||||
default_limit: 20,
|
||||
max_limit: 50
|
||||
}
|
||||
|
||||
@post_kinds ~w[status blog]a
|
||||
|
||||
schema "posts" do
|
||||
|
|
|
@ -211,4 +211,44 @@ defmodule Web.CoreComponents do
|
|||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders pagination controls for navigating through a paginated list.
|
||||
|
||||
## Examples
|
||||
|
||||
<.pagination meta={@meta} path={~p"/blog"} schema={Schema.Post} />
|
||||
"""
|
||||
attr :meta, :map, required: true, doc: "the pagination metadata from Flop"
|
||||
attr :path, :string, required: true, doc: "the base path for pagination links"
|
||||
attr :schema, :atom, required: true, doc: "the schema module for Flop.Phoenix.build_path"
|
||||
attr :class, :string, default: "mt-4", doc: "additional CSS classes"
|
||||
|
||||
def pagination(assigns) do
|
||||
~H"""
|
||||
<div class={["flex justify-between", @class]}>
|
||||
<%= if @meta.has_previous_page? do %>
|
||||
<.link
|
||||
navigate={Flop.Phoenix.build_path(@path, Flop.to_previous_cursor(@meta), for: @schema)}
|
||||
class="text-gray-500 hover:text-gray-800"
|
||||
>
|
||||
Newer posts
|
||||
</.link>
|
||||
<% else %>
|
||||
<div></div>
|
||||
<% end %>
|
||||
|
||||
<%= if @meta.has_next_page? do %>
|
||||
<.link
|
||||
navigate={Flop.Phoenix.build_path(@path, Flop.to_next_cursor(@meta), for: @schema)}
|
||||
class="text-gray-500 hover:text-gray-800"
|
||||
>
|
||||
Older posts
|
||||
</.link>
|
||||
<% else %>
|
||||
<div></div>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
defmodule Web.BlogController do
|
||||
use Web, :controller
|
||||
|
||||
def index(conn, _params) do
|
||||
blogs = Core.Posts.get_published_recent_posts(:blog)
|
||||
def index(conn, params) do
|
||||
{:ok, {blogs, meta}} = Core.Posts.list_published_posts(:blog, params)
|
||||
|
||||
blogs_by_year =
|
||||
blogs
|
||||
|
@ -12,7 +12,7 @@ defmodule Web.BlogController do
|
|||
end)
|
||||
|> Enum.sort_by(fn {year, _} -> year end, :desc)
|
||||
|
||||
render(conn, :index, blogs_by_year: blogs_by_year)
|
||||
render(conn, :index, blogs_by_year: blogs_by_year, meta: meta)
|
||||
end
|
||||
|
||||
def show(conn, %{"year" => year, "month" => month, "day" => day, "slug" => slug}) do
|
||||
|
|
|
@ -26,5 +26,7 @@
|
|||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<.pagination meta={@meta} path={~p"/blog"} schema={Schema.Post} class="my-2" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
defmodule Web.StatusController do
|
||||
use Web, :controller
|
||||
|
||||
def index(conn, _params) do
|
||||
statuses = Core.Posts.get_published_recent_posts(:status)
|
||||
render(conn, :index, statuses: statuses)
|
||||
def index(conn, params) do
|
||||
{:ok, {statuses, meta}} = Core.Posts.list_published_posts(:status, params)
|
||||
render(conn, :index, statuses: statuses, meta: meta)
|
||||
end
|
||||
|
||||
def show(conn, %{"status_id" => status_id}) do
|
||||
|
|
|
@ -8,4 +8,6 @@
|
|||
<.status_entry status={status} />
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<.pagination meta={@meta} path={~p"/microblog"} schema={Schema.Post} class="my-2" />
|
||||
</div>
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -62,6 +62,8 @@ defmodule SlaonelyButSurely.MixProject do
|
|||
{:slugify, "~> 1.3"},
|
||||
{:timex, "~> 3.7"},
|
||||
{:mdex, "~> 0.5.0"},
|
||||
{:flop, "~> 0.26.1"},
|
||||
{:flop_phoenix, "~> 0.24.1"},
|
||||
|
||||
# Added dev and/or test dependencies
|
||||
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
|
||||
|
|
2
mix.lock
2
mix.lock
|
@ -19,6 +19,8 @@
|
|||
"faker": {:hex, :faker, "0.18.0", "943e479319a22ea4e8e39e8e076b81c02827d9302f3d32726c5bf82f430e6e14", [:mix], [], "hexpm", "bfbdd83958d78e2788e99ec9317c4816e651ad05e24cfd1196ce5db5b3e81797"},
|
||||
"file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"},
|
||||
"floki": {:hex, :floki, "0.37.0", "b83e0280bbc6372f2a403b2848013650b16640cd2470aea6701f0632223d719e", [:mix], [], "hexpm", "516a0c15a69f78c47dc8e0b9b3724b29608aa6619379f91b1ffa47109b5d0dd3"},
|
||||
"flop": {:hex, :flop, "0.26.1", "f0e9c6895cf876f667e9ff1c0398e53df87087fcd82d9cea8989332b9c0e1358", [:mix], [{:ecto, "~> 3.11", [hex: :ecto, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "5fcab8a1ee78111159fc4752dc9823862343b6d6bd527ff947ec1e1c27018485"},
|
||||
"flop_phoenix": {:hex, :flop_phoenix, "0.24.1", "0eee8721e984cd9cbbfc90357c355fcf5c57da9e0617159f432d35843d01b671", [:mix], [{:flop, ">= 0.23.0 and < 0.27.0", [hex: :flop, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "543c8eb70a29c0255b778df855f0de303290f88159fc3e008ce0ac4ace48e6ea"},
|
||||
"gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"},
|
||||
"hackney": {:hex, :hackney, "1.22.0", "4efc68df70322d4d2e3d2744e9bd191a39a0cb8d08c35379a08d9fb0f040d595", [:rebar3], [{:certifi, "~> 2.14.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "628569e451820950382be3d3e6481d7c59997e606c7823bddb4ce5d10812dfcb"},
|
||||
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]},
|
||||
|
|
Loading…
Reference in a new issue