diff --git a/.tool-versions b/.tool-versions
index ba05ca2..3216775 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,2 +1,3 @@
erlang 25.2.3
elixir 1.14.3-otp-25
+nodejs 18.16.0
diff --git a/lib/chiya/channels.ex b/lib/chiya/channels.ex
index f3afefd..021cf7b 100644
--- a/lib/chiya/channels.ex
+++ b/lib/chiya/channels.ex
@@ -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.
"""
diff --git a/lib/chiya/notes.ex b/lib/chiya/notes.ex
index 414cb2a..b0ceb1f 100644
--- a/lib/chiya/notes.ex
+++ b/lib/chiya/notes.ex
@@ -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.
diff --git a/lib/chiya/site/setting.ex b/lib/chiya/site/setting.ex
index 7ae485b..a8561a1 100644
--- a/lib/chiya/site/setting.ex
+++ b/lib/chiya/site/setting.ex
@@ -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
diff --git a/lib/chiya_web.ex b/lib/chiya_web.ex
index 6de6716..6a8b18d 100644
--- a/lib/chiya_web.ex
+++ b/lib/chiya_web.ex
@@ -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
diff --git a/lib/chiya_web/components/admin_components.ex b/lib/chiya_web/components/admin_components.ex
deleted file mode 100644
index f29e041..0000000
--- a/lib/chiya_web/components/admin_components.ex
+++ /dev/null
@@ -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"""
-
- """
- 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"""
-
- <.live_file_input upload={@upload} class="dark:text-gray-300" />
-
-
- <%= for entry <- @upload.entries do %>
-
-
-
-
- <%!-- entry.progress will update automatically for in-flight entries --%>
-
-
- <%!-- a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 --%>
-
-
-
- <%!-- Phoenix.Component.upload_errors/2 returns a list of error atoms --%>
- <%= for err <- upload_errors(@upload, entry) do %>
- <%= upload_error_to_string(err) %>
- <% end %>
-
- <% end %>
-
-
- """
- end
-
- @doc """
- Renders the admin menu bar
- """
-
- attr :current_user, :map, required: true
- attr :settings, :map, required: true
-
- def admin_bar(assigns) do
- ~H"""
-
- -
- <.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 %>
-
-
-
- <%= if @current_user do %>
- -
- <.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
- 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
-
-
- <% else %>
- -
- <.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
-
-
- <% end %>
- -
- <.darkmode_toggle />
-
-
- """
- 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
diff --git a/lib/chiya_web/components/core_components.ex b/lib/chiya_web/components/core_components.ex
index d43e82a..4924063 100644
--- a/lib/chiya_web/components/core_components.ex
+++ b/lib/chiya_web/components/core_components.ex
@@ -653,6 +653,118 @@ defmodule ChiyaWeb.CoreComponents do
"""
end
+ @doc """
+ Renders a horizontal line
+ """
+ def line(assigns) do
+ ~H"""
+
+ """
+ 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"""
+
+ <.live_file_input upload={@upload} class="dark:text-gray-300" />
+
+
+ <%= for entry <- @upload.entries do %>
+
+
+
+
+ <%!-- entry.progress will update automatically for in-flight entries --%>
+
+
+ <%!-- a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 --%>
+
+
+
+ <%!-- Phoenix.Component.upload_errors/2 returns a list of error atoms --%>
+ <%= for err <- upload_errors(@upload, entry) do %>
+ <%= upload_error_to_string(err) %>
+ <% end %>
+
+ <% end %>
+
+
+ """
+ end
+
+ @doc """
+ Renders the admin menu bar
+ """
+
+ attr :current_user, :map, required: true
+ attr :settings, :map, required: true
+
+ def admin_bar(assigns) do
+ ~H"""
+
+ -
+ <.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 %>
+
+
+
+ <%= if @current_user do %>
+ -
+ <.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
+ 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
+
+
+ <% else %>
+ -
+ <.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
+
+
+ <% end %>
+ -
+ <.darkmode_toggle />
+
+
+ """
+ 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
diff --git a/lib/chiya_web/components/layouts.ex b/lib/chiya_web/components/layouts.ex
index f7fe4e1..2ff0c0c 100644
--- a/lib/chiya_web/components/layouts.ex
+++ b/lib/chiya_web/components/layouts.ex
@@ -1,7 +1,7 @@
defmodule ChiyaWeb.Layouts do
use ChiyaWeb, :html
- import ChiyaWeb.PublicComponents
+ import ChiyaWeb.PublicComponents, only: [divider: 1]
embed_templates "layouts/*"
end
diff --git a/lib/chiya_web/components/public_components.ex b/lib/chiya_web/components/public_components.ex
index 24f3f8a..dde1679 100644
--- a/lib/chiya_web/components/public_components.ex
+++ b/lib/chiya_web/components/public_components.ex
@@ -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"""
+
+ """
+ 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.
-
- <.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
-
-
- """
- 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.
+ #
+ # <.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
+ #
+ #
+ # """
+ # 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 />
- <%= Enum.count(assigns.note.comments) %> Comments
+ # <%= Enum.count(assigns.note.comments) %> Comments
-
- <% else %>
- <.line />
+ #
+ # <% else %>
+ # <.line />
- No comments yet.
- <% end %>
- """
- end
+ # No comments yet.
+ # <% end %>
+ # """
+ # end
defp gallery_name(note), do: "gallery-#{note.id}"
diff --git a/lib/chiya_web/controllers/note_controller.ex b/lib/chiya_web/controllers/note_controller.ex
index 804030b..8be730b 100644
--- a/lib/chiya_web/controllers/note_controller.ex
+++ b/lib/chiya_web/controllers/note_controller.ex
@@ -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.")
diff --git a/lib/chiya_web/indie/micropub_handler.ex b/lib/chiya_web/indie/micropub_handler.ex
index cdbd8e8..d094fe7 100644
--- a/lib/chiya_web/indie/micropub_handler.ex
+++ b/lib/chiya_web/indie/micropub_handler.ex
@@ -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,
- %{
- content: content,
- name: name,
- tags_string: tags,
- published_at: published_at
- }}
+ 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(),
diff --git a/lib/chiya_web/live/note_show_live.ex b/lib/chiya_web/live/note_show_live.ex
index 9cb5d4f..45dd324 100644
--- a/lib/chiya_web/live/note_show_live.ex
+++ b/lib/chiya_web/live/note_show_live.ex
@@ -60,13 +60,21 @@ defmodule ChiyaWeb.NoteShowLive do
- <.button phx-click="delete_image" phx-value-id={image.id} data-confirm="Are you sure?">
- Delete Image
-
+ />
+
+ <.button phx-click="delete_image" phx-value-id={image.id} data-confirm="Are you sure?">
+ <.icon name="hero-trash" />
+
+ <.button phx-click="toggle_favorite" phx-value-id={image.id}>
+ <.icon name="hero-star-solid" />
+
+
<% end %>
@@ -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