devel #131
12 changed files with 259 additions and 201 deletions
|
@ -1,2 +1,3 @@
|
|||
erlang 25.2.3
|
||||
elixir 1.14.3-otp-25
|
||||
nodejs 18.16.0
|
||||
|
|
|
@ -53,6 +53,8 @@ defmodule Chiya.Channels do
|
|||
"""
|
||||
def get_channel!(id), do: Repo.get!(Channel, id)
|
||||
|
||||
def get_channel(id), do: Repo.get(Channel, id)
|
||||
|
||||
@doc """
|
||||
Gets a single channel with all associated entities preloaded.
|
||||
"""
|
||||
|
|
|
@ -218,6 +218,15 @@ defmodule Chiya.Notes do
|
|||
Repo.delete(note)
|
||||
end
|
||||
|
||||
def publish_note(%Note{} = note, published_at) do
|
||||
{1, nil} =
|
||||
Note
|
||||
|> where([n], n.id == ^note.id)
|
||||
|> Repo.update_all(set: [published_at: published_at])
|
||||
|
||||
{:ok, note}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking note changes.
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ defmodule Chiya.Site.Setting do
|
|||
:custom_css,
|
||||
:custom_html,
|
||||
:home_channel_id,
|
||||
:default_channel_id
|
||||
:default_channel_id,
|
||||
:micropub_channel_id
|
||||
])
|
||||
|> validate_required([:title, :subtitle, :theme, :user_agent])
|
||||
end
|
||||
|
|
|
@ -58,7 +58,7 @@ defmodule ChiyaWeb do
|
|||
layout: {ChiyaWeb.Layouts, :app}
|
||||
|
||||
# Import admin components
|
||||
import ChiyaWeb.AdminComponents
|
||||
import ChiyaWeb.CoreComponents
|
||||
|
||||
unquote(html_helpers())
|
||||
end
|
||||
|
@ -69,7 +69,7 @@ defmodule ChiyaWeb do
|
|||
use Phoenix.LiveComponent
|
||||
|
||||
# Import admin components
|
||||
import ChiyaWeb.AdminComponents
|
||||
import ChiyaWeb.CoreComponents
|
||||
|
||||
unquote(html_helpers())
|
||||
end
|
||||
|
@ -84,7 +84,7 @@ defmodule ChiyaWeb do
|
|||
only: [get_csrf_token: 0, view_module: 1, view_template: 1]
|
||||
|
||||
# Import admin components
|
||||
import ChiyaWeb.AdminComponents
|
||||
import ChiyaWeb.CoreComponents
|
||||
|
||||
# Include general helpers for rendering HTML
|
||||
unquote(html_helpers())
|
||||
|
@ -112,7 +112,6 @@ defmodule ChiyaWeb do
|
|||
# HTML escaping functionality
|
||||
import Phoenix.HTML
|
||||
# Core UI components and translation
|
||||
import ChiyaWeb.CoreComponents
|
||||
import ChiyaWeb.Gettext
|
||||
|
||||
# Shortcut for generating JS commands
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
defmodule ChiyaWeb.AdminComponents do
|
||||
use Phoenix.Component
|
||||
|
||||
use Phoenix.VerifiedRoutes,
|
||||
endpoint: ChiyaWeb.Endpoint,
|
||||
router: ChiyaWeb.Router,
|
||||
statics: ChiyaWeb.static_paths()
|
||||
|
||||
import ChiyaWeb.CoreComponents
|
||||
|
||||
@doc """
|
||||
Renders a horizontal line
|
||||
"""
|
||||
def line(assigns) do
|
||||
~H"""
|
||||
<hr class="my-6 dark:border-gray-700" />
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a UI for uploading files
|
||||
"""
|
||||
|
||||
attr :upload, :map, required: true
|
||||
attr :cancel_upload, :string, default: "cancel-upload"
|
||||
|
||||
def live_upload(assigns) do
|
||||
~H"""
|
||||
<div>
|
||||
<.live_file_input upload={@upload} class="dark:text-gray-300" />
|
||||
|
||||
<section phx-drop-target={@upload.ref}>
|
||||
<%= for entry <- @upload.entries do %>
|
||||
<article class="upload-entry">
|
||||
<figure>
|
||||
<.live_img_preview entry={entry} />
|
||||
<figcaption class="dark:text-gray-100"><%= entry.client_name %></figcaption>
|
||||
</figure>
|
||||
|
||||
<div class="flex">
|
||||
<%!-- entry.progress will update automatically for in-flight entries --%>
|
||||
<progress value={entry.progress} max="100" class="w-full">
|
||||
<%= entry.progress %>%
|
||||
</progress>
|
||||
|
||||
<%!-- a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 --%>
|
||||
<button
|
||||
class="px-2 dark:text-white"
|
||||
type="button"
|
||||
phx-click="cancel-upload"
|
||||
phx-value-ref={entry.ref}
|
||||
aria-label="cancel"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<%!-- Phoenix.Component.upload_errors/2 returns a list of error atoms --%>
|
||||
<%= for err <- upload_errors(@upload, entry) do %>
|
||||
<p class="alert alert-danger"><%= upload_error_to_string(err) %></p>
|
||||
<% end %>
|
||||
</article>
|
||||
<% end %>
|
||||
</section>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders the admin menu bar
|
||||
"""
|
||||
|
||||
attr :current_user, :map, required: true
|
||||
attr :settings, :map, required: true
|
||||
|
||||
def admin_bar(assigns) do
|
||||
~H"""
|
||||
<ul class="sticky top-0 backdrop-blur-sm z-10 flex items-center gap-4 py-3 px-4 sm:px-6 lg:px-8 bg-white/30 dark:bg-black/30">
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/"}
|
||||
class="flex gap-3 text-sm leading-6 font-semibold text-gray-900 dark:text-gray-100 dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
<%= @settings.title %>
|
||||
</.link>
|
||||
</li>
|
||||
<li class="flex-1"></li>
|
||||
<%= if @current_user do %>
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/admin"}
|
||||
class="text-sm leading-6 text-gray-900 dark:text-gray-100 dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
Admin
|
||||
</.link>
|
||||
</li>
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/user/log_out"}
|
||||
method="delete"
|
||||
class="text-sm leading-6 text-gray-900 dark:text-gray-100 dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
Log out
|
||||
</.link>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/user/log_in"}
|
||||
class="text-xs leading-6 text-gray-900 dark:text-gray-100 font-semibold dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
Log in
|
||||
</.link>
|
||||
</li>
|
||||
<% end %>
|
||||
<li>
|
||||
<.darkmode_toggle />
|
||||
</li>
|
||||
</ul>
|
||||
"""
|
||||
end
|
||||
|
||||
defp upload_error_to_string(:too_large), do: "Too large"
|
||||
defp upload_error_to_string(:too_many_files), do: "You have selected too many files"
|
||||
defp upload_error_to_string(:not_accepted), do: "You have selected an unacceptable file type"
|
||||
end
|
|
@ -653,6 +653,118 @@ defmodule ChiyaWeb.CoreComponents do
|
|||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a horizontal line
|
||||
"""
|
||||
def line(assigns) do
|
||||
~H"""
|
||||
<hr class="my-6 dark:border-gray-700" />
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a UI for uploading files
|
||||
"""
|
||||
|
||||
attr :upload, :map, required: true
|
||||
attr :cancel_upload, :string, default: "cancel-upload"
|
||||
|
||||
def live_upload(assigns) do
|
||||
~H"""
|
||||
<div>
|
||||
<.live_file_input upload={@upload} class="dark:text-gray-300" />
|
||||
|
||||
<section phx-drop-target={@upload.ref}>
|
||||
<%= for entry <- @upload.entries do %>
|
||||
<article class="upload-entry">
|
||||
<figure>
|
||||
<.live_img_preview entry={entry} />
|
||||
<figcaption class="dark:text-gray-100"><%= entry.client_name %></figcaption>
|
||||
</figure>
|
||||
|
||||
<div class="flex">
|
||||
<%!-- entry.progress will update automatically for in-flight entries --%>
|
||||
<progress value={entry.progress} max="100" class="w-full">
|
||||
<%= entry.progress %>%
|
||||
</progress>
|
||||
|
||||
<%!-- a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 --%>
|
||||
<button
|
||||
class="px-2 dark:text-white"
|
||||
type="button"
|
||||
phx-click="cancel-upload"
|
||||
phx-value-ref={entry.ref}
|
||||
aria-label="cancel"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<%!-- Phoenix.Component.upload_errors/2 returns a list of error atoms --%>
|
||||
<%= for err <- upload_errors(@upload, entry) do %>
|
||||
<p class="alert alert-danger"><%= upload_error_to_string(err) %></p>
|
||||
<% end %>
|
||||
</article>
|
||||
<% end %>
|
||||
</section>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders the admin menu bar
|
||||
"""
|
||||
|
||||
attr :current_user, :map, required: true
|
||||
attr :settings, :map, required: true
|
||||
|
||||
def admin_bar(assigns) do
|
||||
~H"""
|
||||
<ul class="sticky top-0 backdrop-blur-sm z-10 flex items-center gap-4 py-3 px-4 sm:px-6 lg:px-8 bg-white/30 dark:bg-black/30">
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/"}
|
||||
class="flex gap-3 text-sm leading-6 font-semibold text-gray-900 dark:text-gray-100 dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
<%= @settings.title %>
|
||||
</.link>
|
||||
</li>
|
||||
<li class="flex-1"></li>
|
||||
<%= if @current_user do %>
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/admin"}
|
||||
class="text-sm leading-6 text-gray-900 dark:text-gray-100 dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
Admin
|
||||
</.link>
|
||||
</li>
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/user/log_out"}
|
||||
method="delete"
|
||||
class="text-sm leading-6 text-gray-900 dark:text-gray-100 dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
Log out
|
||||
</.link>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<.link
|
||||
href={~p"/user/log_in"}
|
||||
class="text-xs leading-6 text-gray-900 dark:text-gray-100 font-semibold dark:hover:text-gray-300 hover:text-gray-700"
|
||||
>
|
||||
Log in
|
||||
</.link>
|
||||
</li>
|
||||
<% end %>
|
||||
<li>
|
||||
<.darkmode_toggle />
|
||||
</li>
|
||||
</ul>
|
||||
"""
|
||||
end
|
||||
|
||||
## JS Commands
|
||||
|
||||
def show(js \\ %JS{}, selector) do
|
||||
|
@ -734,4 +846,9 @@ defmodule ChiyaWeb.CoreComponents do
|
|||
def translate_errors(errors, field) when is_list(errors) do
|
||||
for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts})
|
||||
end
|
||||
|
||||
defp upload_error_to_string(:too_large), do: "Too large"
|
||||
defp upload_error_to_string(:too_many_files), do: "You have selected too many files"
|
||||
defp upload_error_to_string(:not_accepted), do: "You have selected an unacceptable file type"
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
defmodule ChiyaWeb.Layouts do
|
||||
use ChiyaWeb, :html
|
||||
|
||||
import ChiyaWeb.PublicComponents
|
||||
import ChiyaWeb.PublicComponents, only: [divider: 1]
|
||||
|
||||
embed_templates "layouts/*"
|
||||
end
|
||||
|
|
|
@ -9,7 +9,35 @@ defmodule ChiyaWeb.PublicComponents do
|
|||
import ChiyaWeb.Format
|
||||
import ChiyaWeb.Markdown, only: [render: 1]
|
||||
import Phoenix.HTML, only: [raw: 1]
|
||||
import ChiyaWeb.CoreComponents
|
||||
|
||||
@doc """
|
||||
Renders a [Hero Icon](https://heroicons.com).
|
||||
|
||||
Hero icons come in three styles – outline, solid, and mini.
|
||||
By default, the outline style is used, but solid an mini may
|
||||
be applied by using the `-solid` and `-mini` suffix.
|
||||
|
||||
You can customize the size and colors of the icons by setting
|
||||
width, height, and background color classes.
|
||||
|
||||
Icons are extracted from your `priv/hero_icons` directory and bundled
|
||||
within your compiled app.css by the plugin in your `assets/tailwind.config.js`.
|
||||
|
||||
## Examples
|
||||
|
||||
<.icon name="hero-cake" />
|
||||
<.icon name="hero-cake-solid" />
|
||||
<.icon name="hero-cake-mini" />
|
||||
<.icon name="hero-bolt" class="bg-blue-500 w-10 h-10" />
|
||||
"""
|
||||
attr :name, :string, required: true
|
||||
attr :class, :string, default: nil
|
||||
|
||||
def icon(%{name: "hero-" <> _} = assigns) do
|
||||
~H"""
|
||||
<span class={[@name, @class]} />
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a middot as divider
|
||||
|
@ -164,58 +192,58 @@ defmodule ChiyaWeb.PublicComponents do
|
|||
end
|
||||
end
|
||||
|
||||
def comment_form(assigns) do
|
||||
~H"""
|
||||
<.simple_form :let={f} for={@changeset} action="" class="bg-theme-background -m-3">
|
||||
<.error :if={@changeset.action}>
|
||||
Oops, something went wrong! Please check the errors below.
|
||||
</.error>
|
||||
<.input
|
||||
field={f[:author_name]}
|
||||
type="text"
|
||||
placeholder="Name"
|
||||
class="bg-theme-background dark:bg-theme-background border-theme-base/20 dark:border-theme-base/20 text-theme-base dark:text-theme-base placeholder-theme-base/40 dark:placeholder-theme-base/60 dark:focus:border-theme-base/60 dark:focus:border-theme-base/60"
|
||||
/>
|
||||
<.input
|
||||
field={f[:content]}
|
||||
type="textarea"
|
||||
placeholder="Content"
|
||||
rows="3"
|
||||
class="bg-theme-background dark:bg-theme-background border-theme-base/20 dark:border-theme-base/20 text-theme-base dark:text-theme-base placeholder-theme-base/60 dark:placeholder-theme-base/60 focus:border-theme-base/60 dark:focus:border-theme-base/60"
|
||||
/>
|
||||
<.input field={f[:note_id]} type="hidden" />
|
||||
<:actions>
|
||||
<.button>Submit Comment</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
"""
|
||||
end
|
||||
# def comment_form(assigns) do
|
||||
# ~H"""
|
||||
# <.simple_form :let={f} for={@changeset} action="" class="bg-theme-background -m-3">
|
||||
# <.error :if={@changeset.action}>
|
||||
# Oops, something went wrong! Please check the errors below.
|
||||
# </.error>
|
||||
# <.input
|
||||
# field={f[:author_name]}
|
||||
# type="text"
|
||||
# placeholder="Name"
|
||||
# class="bg-theme-background dark:bg-theme-background border-theme-base/20 dark:border-theme-base/20 text-theme-base dark:text-theme-base placeholder-theme-base/40 dark:placeholder-theme-base/60 dark:focus:border-theme-base/60 dark:focus:border-theme-base/60"
|
||||
# />
|
||||
# <.input
|
||||
# field={f[:content]}
|
||||
# type="textarea"
|
||||
# placeholder="Content"
|
||||
# rows="3"
|
||||
# class="bg-theme-background dark:bg-theme-background border-theme-base/20 dark:border-theme-base/20 text-theme-base dark:text-theme-base placeholder-theme-base/60 dark:placeholder-theme-base/60 focus:border-theme-base/60 dark:focus:border-theme-base/60"
|
||||
# />
|
||||
# <.input field={f[:note_id]} type="hidden" />
|
||||
# <:actions>
|
||||
# <.button>Submit Comment</.button>
|
||||
# </:actions>
|
||||
# </.simple_form>
|
||||
# """
|
||||
# end
|
||||
|
||||
def comment_list(assigns) do
|
||||
~H"""
|
||||
<%= if not Enum.empty?(assigns.note.comments) do %>
|
||||
<.line />
|
||||
# def comment_list(assigns) do
|
||||
# ~H"""
|
||||
# <%= if not Enum.empty?(assigns.note.comments) do %>
|
||||
# <.line />
|
||||
|
||||
<h2 class="mb-6 text-theme-base"><%= Enum.count(assigns.note.comments) %> Comments</h2>
|
||||
# <h2 class="mb-6 text-theme-base"><%= Enum.count(assigns.note.comments) %> Comments</h2>
|
||||
|
||||
<aside id="comments" class="flex flex-col gap-6">
|
||||
<%= for comment <- assigns.note.comments do %>
|
||||
<article class="text-theme-base bg-theme-base/10 p-1">
|
||||
<header class="flex flex-row justify-between">
|
||||
<strong class="text-theme-primary"><%= comment.author_name %></strong>
|
||||
<span class="text-theme-dim"><%= from_now(comment.inserted_at) %></span>
|
||||
</header>
|
||||
<p><%= comment.content %></p>
|
||||
</article>
|
||||
<% end %>
|
||||
</aside>
|
||||
<% else %>
|
||||
<.line />
|
||||
# <aside id="comments" class="flex flex-col gap-6">
|
||||
# <%= for comment <- assigns.note.comments do %>
|
||||
# <article class="text-theme-base bg-theme-base/10 p-1">
|
||||
# <header class="flex flex-row justify-between">
|
||||
# <strong class="text-theme-primary"><%= comment.author_name %></strong>
|
||||
# <span class="text-theme-dim"><%= from_now(comment.inserted_at) %></span>
|
||||
# </header>
|
||||
# <p><%= comment.content %></p>
|
||||
# </article>
|
||||
# <% end %>
|
||||
# </aside>
|
||||
# <% else %>
|
||||
# <.line />
|
||||
|
||||
<h2 class="mb-6 text-theme-base">No comments yet.</h2>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
# <h2 class="mb-6 text-theme-base">No comments yet.</h2>
|
||||
# <% end %>
|
||||
# """
|
||||
# end
|
||||
|
||||
defp gallery_name(note), do: "gallery-#{note.id}"
|
||||
|
||||
|
|
|
@ -105,10 +105,9 @@ defmodule ChiyaWeb.NoteController do
|
|||
end
|
||||
|
||||
def publish(conn, %{"id" => id}) do
|
||||
note_params = %{published_at: NaiveDateTime.local_now()}
|
||||
note = Notes.get_note_preloaded!(id)
|
||||
|
||||
case Notes.update_note(note, note_params) do
|
||||
case Notes.publish_note(note, NaiveDateTime.local_now()) do
|
||||
{:ok, note} ->
|
||||
conn
|
||||
|> put_flash(:info, "Note published successfully.")
|
||||
|
@ -125,10 +124,9 @@ defmodule ChiyaWeb.NoteController do
|
|||
end
|
||||
|
||||
def unpublish(conn, %{"id" => id}) do
|
||||
note_params = %{published_at: nil}
|
||||
note = Notes.get_note_preloaded!(id)
|
||||
|
||||
case Notes.update_note(note, note_params) do
|
||||
case Notes.publish_note(note, nil) do
|
||||
{:ok, note} ->
|
||||
conn
|
||||
|> put_flash(:info, "Note un-published successfully.")
|
||||
|
|
|
@ -20,9 +20,12 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
|||
Logger.info("Properties: #{inspect(properties)}")
|
||||
Logger.info("Type: #{type}")
|
||||
|
||||
settings = Chiya.Site.get_settings()
|
||||
micropub_channel_id = settings.micropub_channel_id
|
||||
|
||||
with :ok <- verify_token(access_token),
|
||||
{:ok, post_type} <- Props.get_post_type(properties),
|
||||
{:ok, note_attrs} <- get_attrs(type, post_type, properties),
|
||||
{:ok, note_attrs} <- get_attrs(type, post_type, properties, micropub_channel_id),
|
||||
{:ok, note} <- Chiya.Notes.create_note(note_attrs) do
|
||||
Logger.info("Note created!")
|
||||
{:ok, :created, Chiya.Notes.Note.note_url(note)}
|
||||
|
@ -157,16 +160,18 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
|||
end
|
||||
end
|
||||
|
||||
defp get_attrs(type, post_type, properties) do
|
||||
defp get_attrs(type, post_type, properties, default_channel_id) do
|
||||
Logger.info("Creating a #{type}/#{post_type}..")
|
||||
|
||||
channel = Chiya.Channels.get_channel(default_channel_id)
|
||||
|
||||
case post_type do
|
||||
:note -> get_note_attrs(properties)
|
||||
:note -> get_note_attrs(properties, channel)
|
||||
_ -> {:error, :insufficient_scope}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_note_attrs(p) do
|
||||
defp get_note_attrs(p, default_channel) do
|
||||
content = Props.get_content(p)
|
||||
name = Props.get_title(p) || String.slice(content, 0..15)
|
||||
tags = Props.get_tags(p) |> Enum.join(",")
|
||||
|
@ -176,13 +181,19 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
|||
do: NaiveDateTime.local_now(),
|
||||
else: nil
|
||||
|
||||
{:ok,
|
||||
%{
|
||||
attrs = %{
|
||||
content: content,
|
||||
name: name,
|
||||
tags_string: tags,
|
||||
published_at: published_at
|
||||
}}
|
||||
}
|
||||
|
||||
attrs =
|
||||
if default_channel,
|
||||
do: Map.put(attrs, :channel, default_channel),
|
||||
else: attrs
|
||||
|
||||
{:ok, attrs}
|
||||
end
|
||||
|
||||
defp get_hostname(),
|
||||
|
|
|
@ -60,13 +60,21 @@ defmodule ChiyaWeb.NoteShowLive do
|
|||
<article>
|
||||
<a href={"/admin/notes/#{@note.id}/image/#{image.id}"}>
|
||||
<img
|
||||
class="rounded-lg border border-theme-dim w-28 mb-3"
|
||||
class={[
|
||||
"rounded-lg border border-theme-dim w-28 mb-3",
|
||||
image.featured && "border-theme-primary"
|
||||
]}
|
||||
src={ChiyaWeb.Uploaders.NoteImage.url({image.path, image}, :thumb_dithered)}
|
||||
/>
|
||||
<.button phx-click="delete_image" phx-value-id={image.id} data-confirm="Are you sure?">
|
||||
Delete Image
|
||||
</.button>
|
||||
</a>
|
||||
<div class="flex justify-between">
|
||||
<.button phx-click="delete_image" phx-value-id={image.id} data-confirm="Are you sure?">
|
||||
<.icon name="hero-trash" />
|
||||
</.button>
|
||||
<.button phx-click="toggle_favorite" phx-value-id={image.id}>
|
||||
<.icon name="hero-star-solid" />
|
||||
</.button>
|
||||
</div>
|
||||
</article>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -138,6 +146,7 @@ defmodule ChiyaWeb.NoteShowLive do
|
|||
|> assign(:note, Notes.get_note_preloaded!(socket.assigns.note.id))}
|
||||
end
|
||||
|
||||
@impl Phoenix.LiveView
|
||||
def handle_event("validate_edit_image", assigns, socket) do
|
||||
{:noreply,
|
||||
socket
|
||||
|
@ -147,6 +156,7 @@ defmodule ChiyaWeb.NoteShowLive do
|
|||
)}
|
||||
end
|
||||
|
||||
@impl Phoenix.LiveView
|
||||
def handle_event("update_edit_image", %{"id" => id} = assigns, socket) do
|
||||
id
|
||||
|> Notes.get_note_image!()
|
||||
|
@ -164,6 +174,14 @@ defmodule ChiyaWeb.NoteShowLive do
|
|||
{:noreply, assign(socket, :note, Notes.get_note_preloaded!(socket.assigns.note.id))}
|
||||
end
|
||||
|
||||
@impl Phoenix.LiveView
|
||||
def handle_event("toggle_favorite", %{"id" => id}, socket) do
|
||||
image = Notes.get_note_image!(id)
|
||||
Notes.update_note_image(image, %{featured: !image.featured})
|
||||
|
||||
{:noreply, assign(socket, :note, Notes.get_note_preloaded!(socket.assigns.note.id))}
|
||||
end
|
||||
|
||||
defp note_links(notes), do: Enum.map_join(notes, ", ", fn n -> n.name end)
|
||||
defp note_tags(tags), do: Enum.map_join(tags, ", ", fn t -> t.name end)
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue