feat: admin panel for notes

This commit is contained in:
Ivan R. 2024-07-29 16:19:47 +05:00
parent 45c91eb3bf
commit 5a00fdf843
Signed by: lumin
GPG key ID: E0937DC7CD6D3817
14 changed files with 224 additions and 24 deletions

View file

@ -255,10 +255,13 @@
}
.back-nav-link {
font-size: 0.875rem;
line-height: 1.25rem;
font-weight: 600;
line-height: 1.5rem;
display: flex;
gap: 8px;
}
.back-nav-link svg {
flex-shrink: 0;
width: 16px;
}
.table-container {

View file

@ -1,18 +1,39 @@
defmodule Comfycamp.Note do
use Ecto.Schema
import Ecto.Changeset
defmodule Comfycamp.Notes do
@moduledoc """
The Notes context.
"""
schema "notes" do
field :title, :string
field :markdown, :string
import Ecto.Query, warn: false
alias Comfycamp.Repo
alias Comfycamp.Notes.Note
timestamps(type: :utc_datetime)
end
@doc false
def changeset(note, attrs) do
def change_note(%Note{} = note, attrs \\ %{}) do
note
|> cast(attrs, [:title, :markdown])
|> validate_required([:title, :markdown])
|> Note.changeset(attrs)
end
def create_note(attrs \\ %{}) do
%Note{}
|> Note.changeset(attrs)
|> Repo.insert()
end
def update_note(%Note{} = note, attrs \\ %{}) do
note
|> Note.changeset(attrs)
|> Repo.update()
end
def delete_note(%Note{} = note) do
Repo.delete(note)
end
def get_note!(id) do
Note
|> Repo.get!(id)
end
def list_notes() do
Repo.all(Note)
end
end

View file

@ -0,0 +1,18 @@
defmodule Comfycamp.Notes.Note do
use Ecto.Schema
import Ecto.Changeset
schema "notes" do
field :title, :string
field :markdown, :string
timestamps(type: :utc_datetime)
end
@doc false
def changeset(note, attrs) do
note
|> cast(attrs, [:title, :markdown])
|> validate_required([:title, :markdown])
end
end

View file

@ -313,8 +313,7 @@ defmodule ComfycampWeb.CoreComponents do
def error(assigns) do
~H"""
<p class="error">
<.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" />
<%= render_slot(@inner_block) %>
<.exclamation_circle_icon /> <%= render_slot(@inner_block) %>
</p>
"""
end
@ -461,10 +460,9 @@ defmodule ComfycampWeb.CoreComponents do
def back(assigns) do
~H"""
<div class="mt-16">
<div>
<.link navigate={@navigate} class="back-nav-link">
<.icon name="hero-arrow-left-solid" class="h-3 w-3" />
<%= render_slot(@inner_block) %>
<.arrow_left_icon /> <%= render_slot(@inner_block) %>
</.link>
</div>
"""

View file

@ -0,0 +1,10 @@
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18" />
</svg>

After

Width:  |  Height:  |  Size: 247 B

View file

@ -2,15 +2,15 @@
<main>
<div class="limiter">
<h1>Comfycamp - админка</h1>
<.link href={~p"/"}>
Главная страница
</.link>
<h1>Панель администратора</h1>
<div class="admin-panel">
<ul>
<li>
<.link href={~p"/admin/posts"}>
Посты
<.link href={~p"/admin/notes"}>
Заметки
</.link>
</li>
<li>

View file

@ -0,0 +1,89 @@
defmodule ComfycampWeb.NotesController do
use ComfycampWeb, :controller
alias Comfycamp.Notes
alias Comfycamp.Notes.Note
def index(conn, _params) do
notes = Notes.list_notes()
conn
|> put_layout(html: :admin)
|> render(:index, page_title: "Заметки", notes: notes)
end
def new(conn, _params) do
changeset = Notes.change_note(%Note{})
conn
|> put_layout(html: :admin)
|> render(:new, page_title: "Новая заметка", changeset: changeset)
end
def edit(conn, %{"id" => id}) do
note = Notes.get_note!(id)
changeset = Notes.change_note(note)
conn
|> put_layout(html: :admin)
|> render(:edit, page_title: "Редактировать заметку", changeset: changeset)
end
def create(conn, %{"note" => note_params}) do
case Notes.create_note(note_params) do
{:ok, note} ->
conn
|> put_flash(:info, "Заметка сохранена.")
|> redirect(to: ~p"/admin/notes/#{note}")
{:error, changeset} ->
conn
|> put_flash(:error, "Ошибка при обновлении заметки.")
|> put_layout(html: :admin)
|> render(:new, page_title: "Создать заметку", changeset: changeset)
end
end
def update(conn, %{"id" => id, "note" => note_params}) do
note = Notes.get_note!(id)
case Notes.update_note(note, note_params) do
{:ok, note} ->
conn
|> put_flash(:info, "Заметка обновлена.")
|> redirect(to: ~p"/admin/notes/#{note}")
{:error, changeset} ->
conn
|> put_flash(:error, "Ошибка при обновлении заметки.")
|> put_layout(html: :admin)
|> render(:edit, page_title: "Редактировать заметку", changeset: changeset)
end
end
def show(conn, %{"id" => id}) do
note = Notes.get_note!(id)
conn
|> put_layout(html: :admin)
|> render(:show, page_title: "Заметка", note: note)
end
def delete(conn, %{"id" => id}) do
note = Notes.get_note!(id)
case Notes.delete_note(note) do
{:ok, _note} ->
conn
|> put_flash(:info, "Заметка удалена.")
|> redirect(to: ~p"/admin/notes")
{:error, changeset} ->
conn
|> put_flash(:error, "Ошибка при удалении заметки.")
|> put_layout(html: :admin)
|> render(:edit, page_title: "Редактировать заметку", changeset: changeset)
end
end
end

View file

@ -0,0 +1,5 @@
defmodule ComfycampWeb.NotesHTML do
use ComfycampWeb, :html
embed_templates "notes_html/*"
end

View file

@ -0,0 +1,4 @@
<div>
<h2>Редактировать заметку</h2>
<.note_form changeset={@changeset} action={~p"/admin/notes/#{@changeset.data.id}"} />
</div>

View file

@ -0,0 +1,17 @@
<div>
<.link href={~p"/admin/notes/new"}>
Создать заметку
</.link>
<ul>
<%= for note <- @notes do %>
<li>
<.link href={~p"/admin/notes/#{note}"}>
<%= note.title %>
</.link>
<%= note.updated_at %>
</li>
<% end %>
</ul>
</div>

View file

@ -0,0 +1,4 @@
<div>
<h2>Новая заметка</h2>
<.note_form changeset={@changeset} action={~p"/admin/notes"} />
</div>

View file

@ -0,0 +1,18 @@
<.simple_form :let={f} for={@changeset} action={@action}>
<.input field={f[:title]} type="text" label="Заголовок" />
<.input field={f[:markdown]} type="textarea" label="Содержание (markdown)" />
<:actions>
<.button>Сохранить</.button>
</:actions>
</.simple_form>
<%= if @changeset.data.id do %>
<.link
href={~p"/admin/notes/#{@changeset.data}"}
method="DELETE"
data-confirm="Вы уверены?"
>
Удалить
</.link>
<% end %>

View file

@ -0,0 +1,13 @@
<div>
<.back navigate={~p"/admin/notes"}>Назад</.back>
<h3><%= @note.title %></h3>
<.link href={~p"/admin/notes/#{@note}/edit"}>
Редактировать
</.link>
<p>Создана: <%= @note.inserted_at %></p>
<p>Обновлена: <%= @note.updated_at %></p>
<pre><%= @note.markdown %></pre>
</div>

View file

@ -89,8 +89,8 @@ defmodule ComfycampWeb.Router do
pipe_through [:browser, :require_authenticated_user, :ensure_admin]
get "/", AdminPageController, :home
get "/posts", AdminPageController, :posts
get "/users", AdminPageController, :users
get "/services", AdminPageController, :services
resources "/notes", NotesController
end
end