Add models and migrations
This commit is contained in:
parent
182523d36d
commit
9e542bc790
33 changed files with 597 additions and 125 deletions
62
lib/nulla_web/controllers/note_controller.ex
Normal file
62
lib/nulla_web/controllers/note_controller.ex
Normal file
|
@ -0,0 +1,62 @@
|
|||
defmodule NullaWeb.NoteController do
|
||||
use NullaWeb, :controller
|
||||
|
||||
alias Nulla.Notes
|
||||
alias Nulla.Models.Note
|
||||
|
||||
def index(conn, _params) do
|
||||
notes = Notes.list_notes()
|
||||
render(conn, :index, notes: notes)
|
||||
end
|
||||
|
||||
def new(conn, _params) do
|
||||
changeset = Notes.change_note(%Note{})
|
||||
render(conn, :new, changeset: changeset)
|
||||
end
|
||||
|
||||
def create(conn, %{"note" => note_params}) do
|
||||
case Notes.create_note(note_params) do
|
||||
{:ok, note} ->
|
||||
conn
|
||||
|> put_flash(:info, "Note created successfully.")
|
||||
|> redirect(to: ~p"/notes/#{note}")
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
render(conn, :new, changeset: changeset)
|
||||
end
|
||||
end
|
||||
|
||||
def show(conn, %{"id" => id}) do
|
||||
note = Notes.get_note!(id)
|
||||
render(conn, :show, note: note)
|
||||
end
|
||||
|
||||
def edit(conn, %{"id" => id}) do
|
||||
note = Notes.get_note!(id)
|
||||
changeset = Notes.change_note(note)
|
||||
render(conn, :edit, note: note, changeset: changeset)
|
||||
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, "Note updated successfully.")
|
||||
|> redirect(to: ~p"/notes/#{note}")
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
render(conn, :edit, note: note, changeset: changeset)
|
||||
end
|
||||
end
|
||||
|
||||
def delete(conn, %{"id" => id}) do
|
||||
note = Notes.get_note!(id)
|
||||
{:ok, _note} = Notes.delete_note(note)
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Note deleted successfully.")
|
||||
|> redirect(to: ~p"/notes")
|
||||
end
|
||||
end
|
13
lib/nulla_web/controllers/note_html.ex
Normal file
13
lib/nulla_web/controllers/note_html.ex
Normal file
|
@ -0,0 +1,13 @@
|
|||
defmodule NullaWeb.NoteHTML do
|
||||
use NullaWeb, :html
|
||||
|
||||
embed_templates "note_html/*"
|
||||
|
||||
@doc """
|
||||
Renders a note form.
|
||||
"""
|
||||
attr :changeset, Ecto.Changeset, required: true
|
||||
attr :action, :string, required: true
|
||||
|
||||
def note_form(assigns)
|
||||
end
|
8
lib/nulla_web/controllers/note_html/edit.html.heex
Normal file
8
lib/nulla_web/controllers/note_html/edit.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
|||
<.header>
|
||||
Edit Note {@note.id}
|
||||
<:subtitle>Use this form to manage note records in your database.</:subtitle>
|
||||
</.header>
|
||||
|
||||
<.note_form changeset={@changeset} action={~p"/notes/#{@note}"} />
|
||||
|
||||
<.back navigate={~p"/notes"}>Back to notes</.back>
|
23
lib/nulla_web/controllers/note_html/index.html.heex
Normal file
23
lib/nulla_web/controllers/note_html/index.html.heex
Normal file
|
@ -0,0 +1,23 @@
|
|||
<.header>
|
||||
Listing Notes
|
||||
<:actions>
|
||||
<.link href={~p"/notes/new"}>
|
||||
<.button>New Note</.button>
|
||||
</.link>
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
<.table id="notes" rows={@notes} row_click={&JS.navigate(~p"/notes/#{&1}")}>
|
||||
<:col :let={note} label="Content">{note.content}</:col>
|
||||
<:action :let={note}>
|
||||
<div class="sr-only">
|
||||
<.link navigate={~p"/notes/#{note}"}>Show</.link>
|
||||
</div>
|
||||
<.link navigate={~p"/notes/#{note}/edit"}>Edit</.link>
|
||||
</:action>
|
||||
<:action :let={note}>
|
||||
<.link href={~p"/notes/#{note}"} method="delete" data-confirm="Are you sure?">
|
||||
Delete
|
||||
</.link>
|
||||
</:action>
|
||||
</.table>
|
8
lib/nulla_web/controllers/note_html/new.html.heex
Normal file
8
lib/nulla_web/controllers/note_html/new.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
|||
<.header>
|
||||
New Note
|
||||
<:subtitle>Use this form to manage note records in your database.</:subtitle>
|
||||
</.header>
|
||||
|
||||
<.note_form changeset={@changeset} action={~p"/notes"} />
|
||||
|
||||
<.back navigate={~p"/notes"}>Back to notes</.back>
|
9
lib/nulla_web/controllers/note_html/note_form.html.heex
Normal file
9
lib/nulla_web/controllers/note_html/note_form.html.heex
Normal file
|
@ -0,0 +1,9 @@
|
|||
<.simple_form :let={f} for={@changeset} action={@action}>
|
||||
<.error :if={@changeset.action}>
|
||||
Oops, something went wrong! Please check the errors below.
|
||||
</.error>
|
||||
<.input field={f[:content]} type="text" label="Content" />
|
||||
<:actions>
|
||||
<.button>Save Note</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
15
lib/nulla_web/controllers/note_html/show.html.heex
Normal file
15
lib/nulla_web/controllers/note_html/show.html.heex
Normal file
|
@ -0,0 +1,15 @@
|
|||
<.header>
|
||||
Note {@note.id}
|
||||
<:subtitle>This is a note record from your database.</:subtitle>
|
||||
<:actions>
|
||||
<.link href={~p"/notes/#{@note}/edit"}>
|
||||
<.button>Edit note</.button>
|
||||
</.link>
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
<.list>
|
||||
<:item title="Content">{@note.content}</:item>
|
||||
</.list>
|
||||
|
||||
<.back navigate={~p"/notes"}>Back to notes</.back>
|
|
@ -1,21 +1,23 @@
|
|||
defmodule NullaWeb.UserController do
|
||||
use NullaWeb, :controller
|
||||
alias Nulla.Users
|
||||
alias Nulla.InstanceSettings
|
||||
alias Nulla.Models.User
|
||||
alias Nulla.Models.Note
|
||||
alias Nulla.Models.InstanceSettings
|
||||
alias Nulla.ActivityPub
|
||||
|
||||
def show(conn, %{"username" => username}) do
|
||||
accept = List.first(get_req_header(conn, "accept"))
|
||||
instance_settings = InstanceSettings.get_instance_settings!()
|
||||
domain = instance_settings.domain
|
||||
user = Users.get_user_by_username!(username)
|
||||
user = User.get_user_by_username!(username)
|
||||
notes = Note.get_all_notes!(user.id)
|
||||
|
||||
if accept in ["application/activity+json", "application/ld+json"] do
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(ActivityPub.ap_user(domain, user))
|
||||
else
|
||||
render(conn, :show, user: user, domain: domain, layout: false)
|
||||
render(conn, :show, domain: domain, user: user, notes: notes, layout: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,4 +38,42 @@ defmodule NullaWeb.UserHTML do
|
|||
|
||||
"#{formatted} (#{relative})"
|
||||
end
|
||||
|
||||
def format_note_datetime(datetime) do
|
||||
Timex.format!(datetime, "{0D} {Mfull} {YYYY}, {h24}:{m}", :strftime)
|
||||
end
|
||||
|
||||
def format_note_datetime_diff(datetime) do
|
||||
now = Timex.now()
|
||||
diff = Timex.diff(now, datetime, :seconds)
|
||||
|
||||
cond do
|
||||
diff < 60 ->
|
||||
"now"
|
||||
|
||||
diff < 3600 ->
|
||||
minutes = div(diff, 60)
|
||||
"#{minutes}m ago"
|
||||
|
||||
diff < 86400 ->
|
||||
hours = div(diff, 3600)
|
||||
"#{hours}h ago"
|
||||
|
||||
diff < 518400 ->
|
||||
days = div(diff, 86400)
|
||||
"#{days}d ago"
|
||||
|
||||
diff < 2419200 ->
|
||||
weeks = div(diff, 604800)
|
||||
"#{weeks}w ago"
|
||||
|
||||
diff < 28512000 ->
|
||||
months = Timex.diff(now, datetime, :months)
|
||||
"#{months}mo ago"
|
||||
|
||||
true ->
|
||||
years = Timex.diff(now, datetime, :years)
|
||||
"#{years}y ago"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
</div>
|
||||
<div class="relative border border-gray-300 shadow-md mt-5 rounded-t-xl overflow-hidden">
|
||||
<div class="relative w-full aspect-[3/1]">
|
||||
<img src={~p"/images/banner.jpg"} class="w-full h-full object-cover" />
|
||||
<img src={~p"/images/avatar.jpg"} class="absolute left-4 bottom-0 translate-y-1/2 rounded-full border-4 border-white w-[8.33vw] h-[8.33vw] min-w-[80px] min-h-[80px] max-w-[160px] max-h-[160px]"/>
|
||||
<img src={"/files/#{@user.banner}"} class="w-full h-full object-cover" />
|
||||
<div class="absolute inset-0 flex items-end justify-between px-4 pb-2 pointer-events-none">
|
||||
<img src={"/files/#{@user.avatar}"} class="translate-y-1/2 rounded-full border-4 border-white w-[8.33vw] h-[8.33vw] min-w-[80px] min-h-[80px] max-w-[160px] max-h-[160px] pointer-events-auto"/>
|
||||
<button class="px-8 py-2 rounded-full text-sm font-semibold border transition bg-black text-white border-black hover:bg-gray-900 pointer-events-auto">Follow</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-[4.5vw] px-4 flex flex-col">
|
||||
<span class="text-xl font-bold">{@user.realname}</span>
|
||||
|
@ -26,14 +29,12 @@
|
|||
</dt>
|
||||
<dd><%= @user.location %></dd>
|
||||
<% end %>
|
||||
|
||||
<%= if @user.birthday do %>
|
||||
<dt class="flex items-center gap-2">
|
||||
<.icon name="hero-cake" class="mt-0.5 h-5 w-5 flex-none" />
|
||||
</dt>
|
||||
<dd><%= format_birthdate(@user.birthday) %></dd>
|
||||
<% end %>
|
||||
|
||||
<dt class="flex items-center gap-2">
|
||||
<.icon name="hero-calendar" class="mt-0.5 h-5 w-5 flex-none" />
|
||||
</dt>
|
||||
|
@ -59,12 +60,54 @@
|
|||
<a href={~p"/@#{@user.username}/followers"}>31 Followers</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between px-20 py-2 mt-5 border border-gray-300">
|
||||
<div class="flex justify-between px-20 py-2 mt-5 border-y border-gray-300">
|
||||
<a href={~p"/@#{@user.username}/featured"}>Featured</a>
|
||||
<a href={~p"/@#{@user.username}"}>Posts</a>
|
||||
<a href={~p"/@#{@user.username}/with_replies"}>Posts and replies</a>
|
||||
<a href={~p"/@#{@user.username}/media"}>Media</a>
|
||||
</div>
|
||||
<div>
|
||||
<%= for note <- @notes do %>
|
||||
<div class="p-4 border-b border-gray-300">
|
||||
<div class="flex items-start space-x-4">
|
||||
<img src={"/files/#{@user.avatar}"} class="rounded-full w-[58px] h-[58px]"/>
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between items-start">
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="font-semibold text-gray-900 text-sm">
|
||||
<%= @user.realname %>
|
||||
</span>
|
||||
<span class="text-gray-500 text-sm">
|
||||
@<%= @user.username %>@<%= @domain %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 text-sm text-gray-500">
|
||||
<%= case note.visibility do %>
|
||||
<% :public -> %>
|
||||
<.icon name="hero-globe-americas" class="h-5 w-5" />
|
||||
<% :unlisted -> %>
|
||||
<.icon name="hero-moon" class="h-5 w-5" />
|
||||
<% :followers -> %>
|
||||
<.icon name="hero-lock-closed" class="h-5 w-5" />
|
||||
<% :private -> %>
|
||||
<.icon name="hero-at-symbol" class="h-5 w-5" />
|
||||
<% end %>
|
||||
<span><%= format_note_datetime_diff(note.inserted_at) %></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-gray-800">
|
||||
<p><%= note.content %></p>
|
||||
</div>
|
||||
<div class="flex gap-10 mt-4">
|
||||
<button><.icon name="hero-chat-bubble-left" class="h-5 w-5" /></button>
|
||||
<button><.icon name="hero-arrow-path-rounded-square" class="h-5 w-5" /></button>
|
||||
<button><.icon name="hero-plus" class="h-5 w-5" /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-center mt-5 gap-5">
|
||||
<div class="text-sm rounded-xl border border-gray-300 p-4 w-[90%] h-[300px]">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue