Move templates to components

This commit is contained in:
Mirai Kumiko 2025-06-08 13:32:58 +02:00
parent 4fb1e200f1
commit cd1e5887c5
Signed by: miraikumiko
GPG key ID: 3F178B1B5E0CB278
12 changed files with 15 additions and 14 deletions

View file

@ -1,13 +0,0 @@
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

View file

@ -1,8 +0,0 @@
<.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>

View file

@ -1,23 +0,0 @@
<.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>

View file

@ -1,8 +0,0 @@
<.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>

View file

@ -1,9 +0,0 @@
<.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>

View file

@ -1,15 +0,0 @@
<.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>

View file

@ -1,86 +0,0 @@
defmodule NullaWeb.UserHTML do
use NullaWeb, :html
embed_templates "user_html/*"
@doc """
Renders a user form.
"""
attr :changeset, Ecto.Changeset, required: true
attr :action, :string, required: true
def user_form(assigns)
def format_birthdate(date) do
formatted = Date.to_string(date) |> String.replace("-", "/")
age = Timex.diff(Timex.today(), date, :years)
"#{formatted} (#{age} years old)"
end
def format_registration_date(date) do
now = Timex.now()
formatted = Date.to_string(date) |> String.replace("-", "/")
diff = Timex.diff(now, date, :days)
relative =
cond do
diff == 0 ->
"today"
diff == 1 ->
"1 day ago"
diff < 30 ->
"#{diff} days ago"
diff < 365 ->
months = Timex.diff(now, date, :months)
if months == 1, do: "1 month ago", else: "#{months} months ago"
true ->
years = Timex.diff(now, date, :years)
if years == 1, do: "1 year ago", else: "#{years} years ago"
end
"#{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 < 518_400 ->
days = div(diff, 86400)
"#{days}d ago"
diff < 2_419_200 ->
weeks = div(diff, 604_800)
"#{weeks}w ago"
diff < 28_512_000 ->
months = Timex.diff(now, datetime, :months)
"#{months}mo ago"
true ->
years = Timex.diff(now, datetime, :years)
"#{years}y ago"
end
end
end

View file

@ -1,8 +0,0 @@
<.header>
Edit User {@user.id}
<:subtitle>Use this form to manage user records in your database.</:subtitle>
</.header>
<.user_form changeset={@changeset} action={~p"/users/#{@user}"} />
<.back navigate={~p"/users"}>Back to users</.back>

View file

@ -1,23 +0,0 @@
<.header>
Listing Users
<:actions>
<.link href={~p"/users/new"}>
<.button>New User</.button>
</.link>
</:actions>
</.header>
<.table id="users" rows={@users} row_click={&JS.navigate(~p"/users/#{&1}")}>
<:col :let={user} label="Username">{user.username}</:col>
<:action :let={user}>
<div class="sr-only">
<.link navigate={~p"/users/#{user}"}>Show</.link>
</div>
<.link navigate={~p"/users/#{user}/edit"}>Edit</.link>
</:action>
<:action :let={user}>
<.link href={~p"/users/#{user}"} method="delete" data-confirm="Are you sure?">
Delete
</.link>
</:action>
</.table>

View file

@ -1,8 +0,0 @@
<.header>
New User
<:subtitle>Use this form to manage user records in your database.</:subtitle>
</.header>
<.user_form changeset={@changeset} action={~p"/users"} />
<.back navigate={~p"/users"}>Back to users</.back>

View file

@ -1,126 +0,0 @@
<main class="grid grid-cols-[25%_50%_25%]">
<div class="flex flex-col items-center mt-5 gap-5">
<input
placeholder="Search"
class="border border-gray-300 px-4 py-3 rounded-xl outline-none w-[90%]"
/>
<div class="text-sm rounded-xl border border-gray-300 p-2 w-[90%]">
<textarea
placeholder="What's on your mind?"
class="h-[150px] w-full resize-none border-none focus:ring-0"
></textarea>
<div>
<button class="text-white bg-black px-3 py-1 rounded-xl">Post</button>
</div>
</div>
</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={"/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>
<span class="text-gray-500">@{@user.username}@{@domain}</span>
<div class="text-sm pt-2">
<p>{@user.bio}</p>
</div>
<dl class="mt-2 text-sm text-gray-700 grid grid-cols-[auto,1fr] gap-x-2 gap-y-1 items-center">
<%= if @user.location do %>
<dt class="flex items-center gap-2">
<.icon name="hero-map-pin" class="mt-0.5 h-5 w-5 flex-none" />
</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>
<dd>{format_registration_date(@user.inserted_at)}</dd>
</dl>
<%= if @user.fields do %>
<dl class="mt-5 grid grid-cols-[max-content,1fr] gap-x-5 gap-y-2 items-center">
<%= for {key, value} <- @user.fields do %>
<dt>{key}</dt>
<dd>
<%= if Regex.match?(~r{://}, value) do %>
<a href={value} class="text-[#1D9BF0]">{Regex.replace(~r{^\w+://}, value, "")}</a>
<% else %>
{value}
<% end %>
</dd>
<% end %>
</dl>
<% end %>
<div class="flex mt-5 gap-3">
<a href={~p"/@#{@user.username}"}>1.7K Posts</a>
<a href={~p"/@#{@user.username}/following"}>33 Following</a>
<a href={~p"/@#{@user.username}/followers"}>31 Followers</a>
</div>
</div>
<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]"></div>
</div>
</main>

View file

@ -1,9 +0,0 @@
<.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[:username]} type="text" label="Username" />
<:actions>
<.button>Save User</.button>
</:actions>
</.simple_form>