fix: Draft replies

This commit is contained in:
Ro 2025-01-27 18:01:04 -06:00
parent 34de8792c0
commit ec6b728611
Signed by: ro
GPG key ID: 5B5AD5A568CDABF9
6 changed files with 101 additions and 38 deletions

View file

@ -31,6 +31,15 @@
# Roadmap
## Individual Post Page
- [ ] Show post
- [~] Reply to post
- [ ] Allow drafting replies
- [ ] CW on reply
- [ ] Upload attachments on replies
- [ ] Show replies to post (chronological order)
## Posting
- [ ] Making polls
@ -51,12 +60,6 @@
- [ ] Displaying polls
- [ ] Voting in polls
## Individual Post Page
- [ ] Show post
- [ ] Reply to post
- [ ] Show replies to post (chronological order)
## DMs
- [ ] Receiving DMs

3
lib/postland/draft.ex Normal file
View file

@ -0,0 +1,3 @@
defmodule Postland.Draft do
defstruct text: "", cw: nil, attachments: []
end

View file

@ -98,6 +98,9 @@ defmodule PostlandWeb.CoreComponents do
"""
end
attr :draft, :any, required: true
attr :upload, :any, required: true
def post_form(assigns) do
user = Postland.Accounts.solo_user()
@ -119,12 +122,12 @@ defmodule PostlandWeb.CoreComponents do
<div class="min-w-0 flex-1 relative">
<div class="overflow-hidden bg-white relative rounded-lg shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-violet-600">
<.form phx-submit="create_post" phx-change="change_post" id="create-post-form">
<div :if={@cw} class="px-3 pt-2 text-orange-700">
<div :if={@draft.cw} class="px-3 pt-2 text-orange-700">
<.icon name="hero-exclamation-triangle" />
<input
id="cw-input"
name="cw"
value={@cw}
value={@draft.cw}
placeholder="add content warning"
class="border-0 bg-transparent py-1.5 text-orange-700 placeholder:text-gray-400 focus:ring-0 outline-none sm:text-sm sm:leading-6"
/>
@ -132,14 +135,14 @@ defmodule PostlandWeb.CoreComponents do
<label for="post-body" class="sr-only">post body</label>
<textarea
rows="3"
name="post"
id="post-body"
name="draft_body"
id="draft-body"
class="block w-full resize-none border-0 bg-transparent py-1.5 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
placeholder="post body"
><%= @post_content %></textarea>
><%= @draft.text %></textarea>
</.form>
<div class="flex">
<div :for={attachment <- @attachments} class="m-2 w-1/2">
<div :for={attachment <- @draft.attachments} class="m-2 w-1/2">
<.attachment_edit attachment={attachment} id={attachment["url"]} />
</div>
</div>
@ -160,7 +163,7 @@ defmodule PostlandWeb.CoreComponents do
</div>
<div
class="h-9 flex items-center text-gray-500"
phx-click={if @cw, do: "remove_cw", else: "add_cw"}
phx-click={if @draft.cw, do: "remove_cw", else: "add_cw"}
>
<.icon name="hero-exclamation-triangle" class="relative top-0.5" />
</div>
@ -294,6 +297,16 @@ defmodule PostlandWeb.CoreComponents do
>
<.icon name="hero-star" />
</a>
<a
href="#"
phx-click="show_reply_form"
phx-value-post-dom-id={@post_dom_id}
phx-value-post-id={@post.id}
class="text-gray-500"
>
<.icon name="hero-arrow-turn-up-left" />
</a>
<.post_form :if={@draft_reply} draft={@draft_reply} upload={@upload} />
<!-- Content goes here -->
<!-- We use less vertical padding on card footers at all sizes than on headers or body sections -->
</div>

View file

@ -7,10 +7,15 @@ defmodule PostlandWeb.TimelineLive do
def render(assigns) do
~H"""
<div id="timeline">
<.post_form post_content={@post} attachments={@attachments} upload={@uploads.files} cw={@cw} />
<.post_form draft={@draft} upload={@uploads.files} />
<div id="timeline-posts" phx-update="stream">
<div :for={{id, post} <- @streams.posts} id={id} class="mt-10">
<.post_card post={post} post_dom_id={id} />
<.post_card
post={post}
post_dom_id={id}
draft_reply={dbg(@draft_replies[post.id])}
upload={@uploads.files}
/>
</div>
</div>
</div>
@ -20,9 +25,8 @@ defmodule PostlandWeb.TimelineLive do
def mount(_params, _session, socket) do
socket =
socket
|> assign(:post, "")
|> assign(:attachments, [])
|> assign(:cw, nil)
|> assign(:draft, %Postland.Draft{})
|> assign(:draft_replies, %{})
|> stream(:posts, Postland.Timeline.timeline())
|> allow_upload(:files,
accept: ["image/*"],
@ -33,12 +37,12 @@ defmodule PostlandWeb.TimelineLive do
{:ok, socket}
end
def handle_event("create_post", %{"post" => post}, socket) do
def handle_event("create_post", %{"draft_body" => draft_body}, socket) do
{:ok, results} =
Postland.Activities.record_markdown_post(
post,
socket.assigns.cw,
socket.assigns.attachments
draft_body,
socket.assigns.draft.cw,
socket.assigns.draft.attachments
)
new_posts =
@ -49,9 +53,7 @@ defmodule PostlandWeb.TimelineLive do
socket =
socket
|> assign(:post, "")
|> assign(:attachments, [])
|> assign(:cw, nil)
|> assign(:draft, %Postland.Draft{})
|> then(fn socket ->
Enum.reduce(new_posts, socket, fn {_id, post}, socket ->
stream_insert(socket, :posts, post, at: 0)
@ -86,7 +88,7 @@ defmodule PostlandWeb.TimelineLive do
end
end
def handle_event("unlike_post", %{"post-id" => id, "post-dom-id" => dom_id}, socket) do
def handle_event("unlike_post", %{"post-id" => id}, socket) do
post = Objects.get_by_id(id)
case Activities.unlike_post(post) do
@ -99,22 +101,47 @@ defmodule PostlandWeb.TimelineLive do
end
end
def handle_event("change_post", %{"post" => post} = params, socket) do
def handle_event("show_reply_form", %{"post-id" => id}, socket) do
post = Objects.get_by_id(id)
draft_replies =
case Map.get(socket.assigns.draft_replies, id) do
nil ->
Map.put(socket.assigns.draft_replies, id, %Postland.Draft{})
_ ->
socket.assigns.draft_replies
end
{:noreply, socket |> assign(:draft_replies, draft_replies) |> stream_insert(:posts, post)}
end
def handle_event("change_post", %{"draft_body" => draft_body} = params, socket) do
cw = Map.get(params, "cw")
{:noreply, socket |> assign(post: post, cw: cw)}
draft =
socket.assigns.draft
|> Map.put(:text, draft_body)
|> Map.put(:cw, cw)
{:noreply, socket |> assign(draft: draft)}
end
def handle_event("remove_attachment", %{"url" => url}, socket) do
attachments =
socket.assigns.attachments
socket.assigns.draft.attachments
|> Enum.reject(fn %{"url" => attachment_url} -> attachment_url == url end)
{:noreply, assign(socket, attachments: attachments)}
draft =
socket.assigns.draft
|> Map.put(:attachments, attachments)
{:noreply, assign(socket, draft: draft)}
end
def handle_event("change_alt_text", %{"alt" => value, "url" => url}, socket) do
attachments =
socket.assigns.attachments
socket.assigns.draft.attachments
|> Enum.map(fn
%{"url" => ^url} = attachment ->
Map.put(attachment, "name", value)
@ -123,15 +150,27 @@ defmodule PostlandWeb.TimelineLive do
other
end)
{:noreply, assign(socket, attachments: attachments)}
draft =
socket.assigns.draft
|> Map.put(:attachments, attachments)
{:noreply, assign(socket, draft: draft)}
end
def handle_event("add_cw", _, socket) do
{:noreply, assign(socket, cw: "")}
draft =
socket.assigns.draft
|> Map.put(:cw, "")
{:noreply, assign(socket, draft: draft)}
end
def handle_event("remove_cw", _, socket) do
{:noreply, assign(socket, cw: nil)}
draft =
socket.assigns.draft
|> Map.put(:cw, nil)
{:noreply, assign(socket, draft: draft)}
end
def handle_progress(:files, entry, socket) do
@ -148,8 +187,13 @@ defmodule PostlandWeb.TimelineLive do
"name" => nil
}
attachments = socket.assigns.attachments ++ [attachment]
{:noreply, assign(socket, attachments: attachments)}
attachments = socket.assigns.draft.attachments ++ [attachment]
draft =
socket.assigns.draft
|> Map.put(:attachments, attachments)
{:noreply, assign(socket, draft: draft)}
else
{:noreply, socket}
end

View file

@ -46,7 +46,7 @@ defmodule Postland.MixProject do
{:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
{:heroicons,
github: "tailwindlabs/heroicons",
tag: "v2.1.1",
tag: "v2.1.5",
sparse: "optimized",
app: false,
compile: false,

View file

@ -22,7 +22,7 @@
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
"floki": {:hex, :floki, "0.37.0", "b83e0280bbc6372f2a403b2848013650b16640cd2470aea6701f0632223d719e", [:mix], [], "hexpm", "516a0c15a69f78c47dc8e0b9b3724b29608aa6619379f91b1ffa47109b5d0dd3"},
"gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"},
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized"]},
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "ad0ad1f6d51bd64dcd67e363d2b2833a8de25154", [tag: "v2.1.5", sparse: "optimized"]},
"hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},