starting to get public pages working
This commit is contained in:
parent
f8859e8070
commit
a7a270101d
11 changed files with 209 additions and 22 deletions
|
@ -31,6 +31,20 @@ defmodule Core.Posts do
|
|||
|> Core.Repo.all()
|
||||
end
|
||||
|
||||
def get_published_recent_posts(kind) do
|
||||
Post.Query.recent_posts(kind, @recent_posts_count)
|
||||
|> Post.Query.published()
|
||||
|> Core.Repo.all()
|
||||
end
|
||||
|
||||
def publish_date(%Schema.Post{published_at: nil}), do: nil
|
||||
|
||||
def publish_date(%Schema.Post{published_at: published_at}) do
|
||||
published_at
|
||||
|> DateTime.shift_zone!("America/New_York")
|
||||
|> DateTime.to_date()
|
||||
end
|
||||
|
||||
def change_post(%Schema.Post{} = post \\ %Schema.Post{}, attrs) do
|
||||
Post.content_changeset(post, attrs)
|
||||
end
|
||||
|
|
|
@ -110,6 +110,13 @@ defmodule Core.Posts.Post do
|
|||
|> limit(^count)
|
||||
end
|
||||
|
||||
def recent_posts(query \\ base(), kind, count) do
|
||||
query
|
||||
|> where_kind(kind)
|
||||
|> default_order()
|
||||
|> limit(^count)
|
||||
end
|
||||
|
||||
def where_publish_date_and_slug(query \\ current(), publish_date, slug) do
|
||||
where(
|
||||
query,
|
||||
|
|
|
@ -112,4 +112,85 @@ defmodule Web.CoreComponents do
|
|||
</button>
|
||||
"""
|
||||
end
|
||||
|
||||
attr :format, :string, required: true
|
||||
attr :value, :any, default: nil
|
||||
attr :formatter, :atom, default: :default
|
||||
attr :timezone, :string, default: "America/New_York"
|
||||
attr :global, :global
|
||||
|
||||
def timex(%{value: nil} = assigns) do
|
||||
~H"""
|
||||
<time datetime="">--</time>
|
||||
"""
|
||||
end
|
||||
|
||||
def timex(%{value: value, timezone: timezone} = assigns) do
|
||||
assigns =
|
||||
assign_new(assigns, :local_value, fn ->
|
||||
case value do
|
||||
%DateTime{} = datetime ->
|
||||
datetime
|
||||
|
||||
%NaiveDateTime{} = naive ->
|
||||
naive
|
||||
|> DateTime.from_naive!("Etc/UTC")
|
||||
|> DateTime.shift_zone!(timezone)
|
||||
end
|
||||
end)
|
||||
|
||||
~H"""
|
||||
<time
|
||||
datetime={Timex.format!(@local_value, "{ISO:Extended}")}
|
||||
title={Timex.format!(@local_value, "{Mshort} {D}, {YYYY}, {h12}:{m} {AM} {Zabbr}")}
|
||||
{@global}
|
||||
>
|
||||
{Timex.format!(@local_value, @format, timex_formatter(@formatter))}
|
||||
</time>
|
||||
"""
|
||||
end
|
||||
|
||||
defp timex_formatter(formatter) do
|
||||
Module.concat(Timex.Format.DateTime.Formatters, :string.titlecase("#{formatter}"))
|
||||
end
|
||||
|
||||
attr :id, :string, required: true
|
||||
attr :posts, :any, required: true
|
||||
|
||||
slot :inner_block, required: true
|
||||
|
||||
def post_list(assigns) do
|
||||
~H"""
|
||||
<ol id={@id} phx-update={if is_struct(@posts, Phoenix.LiveView.LiveStream), do: "phx-update"}>
|
||||
<li
|
||||
:for={{dom_id, item} <- normalize_posts(@posts)}
|
||||
id={dom_id}
|
||||
class="flex flex-row justify-between"
|
||||
>
|
||||
<span>{render_slot(@inner_block, item)}</span>
|
||||
<span>
|
||||
<%= if item.deleted_at do %>
|
||||
deleted
|
||||
<% else %>
|
||||
<%= if item.published_at do %>
|
||||
<%= case item.kind do %>
|
||||
<% :blog -> %>
|
||||
<.timex value={item.published_at} format="{YYYY}-{0M}-{0D}" />
|
||||
<% :status -> %>
|
||||
<.timex value={item.published_at} format="{relative}" formatter={:relative} />
|
||||
<% end %>
|
||||
<% else %>
|
||||
draft
|
||||
<% end %>
|
||||
<% end %>
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
"""
|
||||
end
|
||||
|
||||
defp normalize_posts(%Phoenix.LiveView.LiveStream{} = stream), do: stream
|
||||
|
||||
defp normalize_posts(posts) when is_list(posts),
|
||||
do: Enum.with_index(posts, &{"#{&1.kind}-#{&2}", &1})
|
||||
end
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
</.link>
|
||||
<nav>
|
||||
<ul class="flex flex-row gap-x-2">
|
||||
<li><.link href="#">writing</.link></li>
|
||||
<li><.link href="#">microblog</.link></li>
|
||||
<li><.link href={~p"/blog"}>writing</.link></li>
|
||||
<li><.link href={~p"/microblog"}>microblog</.link></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
|
|
|
@ -22,6 +22,12 @@ defmodule Web.PostController do
|
|||
|> render_post(status)
|
||||
end
|
||||
|
||||
def index(%{assigns: %{kind: kind}} = conn, _params) when kind in ~w[blog status]a do
|
||||
posts = Core.Posts.get_published_recent_posts(kind)
|
||||
|
||||
render(conn, :index, posts: posts)
|
||||
end
|
||||
|
||||
defp render_post(conn, %Schema.Post{kind: :blog} = blog) do
|
||||
render(conn, :show_blog, blog: blog)
|
||||
end
|
||||
|
|
|
@ -2,4 +2,10 @@ defmodule Web.PostHTML do
|
|||
use Web, :html
|
||||
|
||||
embed_templates "post_html/*"
|
||||
|
||||
def blog_path(%Schema.Post{} = blog) do
|
||||
if date = Core.Posts.publish_date(blog) do
|
||||
~p"/blog/#{date.year}/#{date.month}/#{date.day}/#{blog.slug}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
8
lib/web/controllers/post_html/index.html.heex
Normal file
8
lib/web/controllers/post_html/index.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
|||
<.post_list :let={post} id="recent-posts" posts={@posts}>
|
||||
<%= case post.kind do %>
|
||||
<% :blog -> %>
|
||||
<.link navigate={blog_path(post)}>{post.title}</.link>
|
||||
<% :status -> %>
|
||||
{post.body}
|
||||
<% end %>
|
||||
</.post_list>
|
|
@ -23,7 +23,7 @@ defmodule Web.AdminDashboardLive do
|
|||
<h2 class="font-bold text-xl">recent statuses</h2>
|
||||
<.link navigate={~p"/admin/posts/new?kind=status"}>new status</.link>
|
||||
</header>
|
||||
<.post_list :let={status} id="recent-statuses" stream={@streams.statuses}>
|
||||
<.post_list :let={status} id="recent-statuses" posts={@streams.statuses}>
|
||||
<.link navigate={~p"/admin/posts/#{status}"}>{status.body}</.link>
|
||||
</.post_list>
|
||||
</section>
|
||||
|
@ -33,26 +33,11 @@ defmodule Web.AdminDashboardLive do
|
|||
<h2 class="font-bold text-xl">recent blogs</h2>
|
||||
<.link navigate={~p"/admin/posts/new?kind=blog"}>new blog</.link>
|
||||
</header>
|
||||
<.post_list :let={blog} id="recent-blogs" stream={@streams.blogs}>
|
||||
<.post_list :let={blog} id="recent-blogs" posts={@streams.blogs}>
|
||||
<.link navigate={~p"/admin/posts/#{blog}"}>{blog.title}</.link>
|
||||
</.post_list>
|
||||
</section>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
attr :id, :string, required: true
|
||||
attr :stream, :any, required: true
|
||||
|
||||
slot :inner_block, required: true
|
||||
|
||||
def post_list(assigns) do
|
||||
~H"""
|
||||
<ol id={@id} phx-update="stream">
|
||||
<li :for={{dom_id, item} <- @stream} id={dom_id}>
|
||||
{render_slot(@inner_block, item)}
|
||||
</li>
|
||||
</ol>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,12 @@ defmodule Web.AdminPostLive do
|
|||
post = Core.Posts.get!(post_id)
|
||||
form = Core.Posts.change_post(post, %{}) |> to_form()
|
||||
|
||||
socket = assign(socket, post: post, form: form)
|
||||
socket =
|
||||
assign(socket,
|
||||
post: post,
|
||||
form: form,
|
||||
page_title: page_title(post, socket.assigns.live_action)
|
||||
)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
@ -19,7 +24,12 @@ defmodule Web.AdminPostLive do
|
|||
post = %Schema.Post{kind: String.to_existing_atom(kind)}
|
||||
form = Core.Posts.change_post(post, %{}) |> to_form()
|
||||
|
||||
socket = assign(socket, post: post, form: form)
|
||||
socket =
|
||||
assign(socket,
|
||||
post: post,
|
||||
form: form,
|
||||
page_title: page_title(post, socket.assigns.live_action)
|
||||
)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
@ -54,6 +64,58 @@ defmodule Web.AdminPostLive do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("publish", _, %{assigns: %{post: post}} = socket) do
|
||||
socket =
|
||||
case Core.Posts.publish_post(post) do
|
||||
{:ok, post} ->
|
||||
assign(socket, post: post)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("unpublish", _, %{assigns: %{post: post}} = socket) do
|
||||
socket =
|
||||
case Core.Posts.unpublish_post(post) do
|
||||
{:ok, post} ->
|
||||
assign(socket, post: post)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("delete", _, %{assigns: %{post: post}} = socket) do
|
||||
socket =
|
||||
case Core.Posts.delete_post(post) do
|
||||
{:ok, post} ->
|
||||
assign(socket, post: post)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("undelete", _, %{assigns: %{post: post}} = socket) do
|
||||
socket =
|
||||
case Core.Posts.undelete_post(post) do
|
||||
{:ok, post} ->
|
||||
assign(socket, post: post)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<main>
|
||||
|
@ -73,6 +135,21 @@ defmodule Web.AdminPostLive do
|
|||
|
||||
<.button type="submit">save</.button>
|
||||
</.form>
|
||||
|
||||
<%= if @live_action == :edit do %>
|
||||
<div>
|
||||
<%= if @post.published_at do %>
|
||||
<.button phx-click="unpublish">unpublish</.button>
|
||||
<% else %>
|
||||
<.button phx-click="publish">publish</.button>
|
||||
<% end %>
|
||||
<%= if @post.deleted_at do %>
|
||||
<.button phx-click="undelete">undelete</.button>
|
||||
<% else %>
|
||||
<.button phx-click="delete">delete</.button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</main>
|
||||
"""
|
||||
end
|
||||
|
|
|
@ -45,7 +45,9 @@ defmodule Web.Router do
|
|||
|
||||
delete "/admin/users/log_out", UserSessionController, :delete
|
||||
|
||||
get "/:year/:month/:day/:slug", PostController, :show
|
||||
get "/blog", PostController, :index, assigns: %{kind: :blog}
|
||||
get "/blog/:year/:month/:day/:slug", PostController, :show
|
||||
get "/microblog", PostController, :index, assigns: %{kind: :status}
|
||||
get "/status/:status_id", PostController, :show
|
||||
|
||||
# live_session :current_user, on_mount: [{Web.UserAuth, :mount_current_user}] do
|
||||
|
|
1
mix.exs
1
mix.exs
|
@ -60,6 +60,7 @@ defmodule SlaonelyButSurely.MixProject do
|
|||
{:boundary, "~> 0.10.4"},
|
||||
{:tzdata, "~> 1.1"},
|
||||
{:slugify, "~> 1.3"},
|
||||
{:timex, "~> 3.7"},
|
||||
|
||||
# Added dev and/or test dependencies
|
||||
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
|
||||
|
|
Loading…
Reference in a new issue