Compare commits
2 commits
894866ca03
...
f43b4bd038
Author | SHA1 | Date | |
---|---|---|---|
f43b4bd038 | |||
10756907dc |
4 changed files with 83 additions and 70 deletions
|
@ -1,77 +1,92 @@
|
||||||
defmodule NullaWeb.UserHTML do
|
defmodule NullaWeb.ActorHTML do
|
||||||
use NullaWeb, :html
|
use NullaWeb, :html
|
||||||
|
|
||||||
embed_templates "templates/user/*"
|
embed_templates "templates/actor/*"
|
||||||
|
|
||||||
def format_birthdate(date) do
|
def format_birthdate(date) do
|
||||||
formatted = Date.to_string(date) |> String.replace("-", "/")
|
formatted = Date.to_string(date) |> String.replace("-", "/")
|
||||||
age = Timex.diff(Timex.today(), date, :years)
|
|
||||||
|
today = Date.utc_today()
|
||||||
|
|
||||||
|
age =
|
||||||
|
today.year - date.year -
|
||||||
|
if {today.month, today.day} < {date.month, date.day}, do: 1, else: 0
|
||||||
|
|
||||||
"#{formatted} (#{age} years old)"
|
"#{formatted} (#{age} years old)"
|
||||||
end
|
end
|
||||||
|
|
||||||
def format_registration_date(date) do
|
def format_registration_date(date) do
|
||||||
now = Timex.now()
|
now = Date.utc_today()
|
||||||
formatted = Date.to_string(date) |> String.replace("-", "/")
|
formatted = Date.to_string(date) |> String.replace("-", "/")
|
||||||
|
|
||||||
diff = Timex.diff(now, date, :days)
|
diff_days = Date.diff(now, date)
|
||||||
|
|
||||||
relative =
|
cond do
|
||||||
cond do
|
diff_days == 0 ->
|
||||||
diff == 0 ->
|
"#{formatted} (today)"
|
||||||
"today"
|
|
||||||
|
|
||||||
diff == 1 ->
|
diff_days == 1 ->
|
||||||
"1 day ago"
|
"#{formatted} (1 day ago)"
|
||||||
|
|
||||||
diff < 30 ->
|
diff_days < 30 ->
|
||||||
"#{diff} days ago"
|
"#{formatted} (#{diff_days} days ago)"
|
||||||
|
|
||||||
diff < 365 ->
|
diff_days < 365 ->
|
||||||
months = Timex.diff(now, date, :months)
|
year_diff = now.year - date.year
|
||||||
if months == 1, do: "1 month ago", else: "#{months} months ago"
|
month_diff = now.month - date.month
|
||||||
|
day_correction = if now.day < date.day, do: -1, else: 0
|
||||||
|
months = year_diff * 12 + month_diff + day_correction
|
||||||
|
if months == 1 do
|
||||||
|
"#{formatted} (1 month ago)"
|
||||||
|
else
|
||||||
|
"#{formatted} (#{months} months ago)"
|
||||||
|
end
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
years = Timex.diff(now, date, :years)
|
year_diff = now.year - date.year
|
||||||
if years == 1, do: "1 year ago", else: "#{years} years ago"
|
years = if {now.month, now.day} < {date.month, date.day}, do: year_diff - 1, else: year_diff
|
||||||
end
|
if years == 1 do
|
||||||
|
"#{formatted} (1 year ago)"
|
||||||
"#{formatted} (#{relative})"
|
else
|
||||||
|
"#{formatted} (#{years} years ago)"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def format_note_datetime(datetime) do
|
def format_note_datetime(datetime) do
|
||||||
Timex.format!(datetime, "{0D} {Mfull} {YYYY}, {h24}:{m}", :strftime)
|
Calendar.strftime(datetime, "%d %B %Y, %H:%M")
|
||||||
end
|
end
|
||||||
|
|
||||||
def format_note_datetime_diff(datetime) do
|
def format_note_datetime_diff(datetime) do
|
||||||
now = Timex.now()
|
now = DateTime.utc_now()
|
||||||
diff = Timex.diff(now, datetime, :seconds)
|
diff_seconds = DateTime.diff(now, datetime)
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
diff < 60 ->
|
diff_seconds < 60 ->
|
||||||
"now"
|
"now"
|
||||||
|
|
||||||
diff < 3600 ->
|
diff_seconds < 3600 ->
|
||||||
minutes = div(diff, 60)
|
minutes = div(diff_seconds, 60)
|
||||||
"#{minutes}m ago"
|
"#{minutes}m ago"
|
||||||
|
|
||||||
diff < 86400 ->
|
diff_seconds < 86400 ->
|
||||||
hours = div(diff, 3600)
|
hours = div(diff_seconds, 3600)
|
||||||
"#{hours}h ago"
|
"#{hours}h ago"
|
||||||
|
|
||||||
diff < 518_400 ->
|
diff_seconds < 604_800 ->
|
||||||
days = div(diff, 86400)
|
days = div(diff_seconds, 86400)
|
||||||
"#{days}d ago"
|
"#{days}d ago"
|
||||||
|
|
||||||
diff < 2_419_200 ->
|
diff_seconds < 2_592_000 ->
|
||||||
weeks = div(diff, 604_800)
|
weeks = div(diff_seconds, 604_800)
|
||||||
"#{weeks}w ago"
|
"#{weeks}w ago"
|
||||||
|
|
||||||
diff < 28_512_000 ->
|
diff_seconds < 31_536_000 ->
|
||||||
months = Timex.diff(now, datetime, :months)
|
months = div(diff_seconds, 2_592_000)
|
||||||
"#{months}mo ago"
|
"#{months}mo ago"
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
years = Timex.diff(now, datetime, :years)
|
years = div(diff_seconds, 31_536_000)
|
||||||
"#{years}y ago"
|
"#{years}y ago"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="relative border border-gray-300 shadow-md mt-5 rounded-t-xl overflow-hidden">
|
<div class="relative border border-gray-300 shadow-md mt-5 rounded-t-xl overflow-hidden">
|
||||||
<div class="relative w-full aspect-[3/1]">
|
<div class="relative w-full aspect-[3/1]">
|
||||||
<img src={"/files/#{@user.banner}"} class="w-full h-full object-cover" />
|
<img src={@actor.image["url"]} class="w-full h-full object-cover" />
|
||||||
<div class="absolute inset-0 flex items-end justify-between px-4 pb-2 pointer-events-none">
|
<div class="absolute inset-0 flex items-end justify-between px-4 pb-2 pointer-events-none">
|
||||||
<img
|
<img
|
||||||
src={"/files/#{@user.avatar}"}
|
src={@actor.icon["url"]}}
|
||||||
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"
|
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">
|
<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">
|
||||||
|
@ -28,33 +28,33 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[4.5vw] px-4 flex flex-col">
|
<div class="mt-[4.5vw] px-4 flex flex-col">
|
||||||
<span class="text-xl font-bold">{@user.realname}</span>
|
<span class="text-xl font-bold">{@actor.name}</span>
|
||||||
<span class="text-gray-500">@{@user.username}@{@domain}</span>
|
<span class="text-gray-500">@{@actor.preferredUsername}@{@actor.domain}</span>
|
||||||
<div class="text-sm pt-2">
|
<div class="text-sm pt-2">
|
||||||
<p>{@user.bio}</p>
|
<p>{@actor.summary}</p>
|
||||||
</div>
|
</div>
|
||||||
<dl class="mt-2 text-sm text-gray-700 grid grid-cols-[auto,1fr] gap-x-2 gap-y-1 items-center">
|
<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 %>
|
<%= if @actor.vcard_Address do %>
|
||||||
<dt class="flex items-center gap-2">
|
<dt class="flex items-center gap-2">
|
||||||
<.icon name="hero-map-pin" class="mt-0.5 h-5 w-5 flex-none" />
|
<.icon name="hero-map-pin" class="mt-0.5 h-5 w-5 flex-none" />
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{@user.location}</dd>
|
<dd>{@actor.vcard_Address}</dd>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= if @user.birthday do %>
|
<%= if @actor.vcard_bday do %>
|
||||||
<dt class="flex items-center gap-2">
|
<dt class="flex items-center gap-2">
|
||||||
<.icon name="hero-cake" class="mt-0.5 h-5 w-5 flex-none" />
|
<.icon name="hero-cake" class="mt-0.5 h-5 w-5 flex-none" />
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{format_birthdate(@user.birthday)}</dd>
|
<dd>{format_birthdate(@actor.vcard_bday)}</dd>
|
||||||
<% end %>
|
<% end %>
|
||||||
<dt class="flex items-center gap-2">
|
<dt class="flex items-center gap-2">
|
||||||
<.icon name="hero-calendar" class="mt-0.5 h-5 w-5 flex-none" />
|
<.icon name="hero-calendar" class="mt-0.5 h-5 w-5 flex-none" />
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{format_registration_date(@user.inserted_at)}</dd>
|
<dd>{format_registration_date(@actor.published)}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<%= if @user.fields do %>
|
<%= if @actor.attachment do %>
|
||||||
<dl class="mt-5 grid grid-cols-[max-content,1fr] gap-x-5 gap-y-2 items-center">
|
<dl class="mt-5 grid grid-cols-[max-content,1fr] gap-x-5 gap-y-2 items-center">
|
||||||
<%= for {key, value} <- @user.fields do %>
|
<%= for %{"type" => "PropertyValue", "name" => name, "value" => value} <- @actor.attachment do %>
|
||||||
<dt>{key}</dt>
|
<dt>{name}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<%= if Regex.match?(~r{://}, value) do %>
|
<%= if Regex.match?(~r{://}, value) do %>
|
||||||
<a href={value} class="text-[#1D9BF0]">{Regex.replace(~r{^\w+://}, value, "")}</a>
|
<a href={value} class="text-[#1D9BF0]">{Regex.replace(~r{^\w+://}, value, "")}</a>
|
||||||
|
@ -66,30 +66,30 @@
|
||||||
</dl>
|
</dl>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="flex mt-5 gap-3">
|
<div class="flex mt-5 gap-3">
|
||||||
<a href={~p"/@#{@user.username}"}>{length(@notes)} Posts</a>
|
<a href={~p"/@#{@actor.preferredUsername}"}>{length(@notes)} Posts</a>
|
||||||
<a href={~p"/@#{@user.username}/following"}>{@following} Following</a>
|
<a href={~p"/@#{@actor.preferredUsername}/following"}>{@following} Following</a>
|
||||||
<a href={~p"/@#{@user.username}/followers"}>{@followers} Followers</a>
|
<a href={~p"/@#{@actor.preferredUsername}/followers"}>{@followers} Followers</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between px-20 py-2 mt-5 border-y 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"/@#{@actor.preferredUsername}/featured"}>Featured</a>
|
||||||
<a href={~p"/@#{@user.username}"}>Posts</a>
|
<a href={~p"/@#{@actor.preferredUsername}"}>Posts</a>
|
||||||
<a href={~p"/@#{@user.username}/with_replies"}>Posts and replies</a>
|
<a href={~p"/@#{@actor.preferredUsername}/with_replies"}>Posts and replies</a>
|
||||||
<a href={~p"/@#{@user.username}/media"}>Media</a>
|
<a href={~p"/@#{@actor.preferredUsername}/media"}>Media</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<%= for note <- @notes do %>
|
<%= for note <- @notes do %>
|
||||||
<div class="p-4 border-b border-gray-300">
|
<div class="p-4 border-b border-gray-300">
|
||||||
<div class="flex items-start space-x-4">
|
<div class="flex items-start space-x-4">
|
||||||
<img src={"/files/#{@user.avatar}"} class="rounded-full w-[58px] h-[58px]" />
|
<img src={@actor.icon["url"]}} class="rounded-full w-[58px] h-[58px]" />
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex justify-between items-start">
|
<div class="flex justify-between items-start">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<span class="font-semibold text-gray-900 text-sm">
|
<span class="font-semibold text-gray-900 text-sm">
|
||||||
{@user.realname}
|
{@actor.name}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-gray-500 text-sm">
|
<span class="text-gray-500 text-sm">
|
||||||
@{@user.username}@{@domain}
|
@{@actor.preferredUsername}@{@actor.domain}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-2 text-sm text-gray-500">
|
<div class="flex items-center space-x-2 text-sm text-gray-500">
|
|
@ -24,13 +24,12 @@ defmodule NullaWeb.ActorController do
|
||||||
|> send_resp(200, Jason.encode!(ActivityPub.actor(actor)))
|
|> send_resp(200, Jason.encode!(ActivityPub.actor(actor)))
|
||||||
else
|
else
|
||||||
notes = Note.get_latest_notes(actor.id)
|
notes = Note.get_latest_notes(actor.id)
|
||||||
following = Utils.count_following_by_username!(actor.preferredUsername)
|
following = 0
|
||||||
followers = Utils.count_followers_by_username!(actor.preferredUsername)
|
followers = 0
|
||||||
|
|
||||||
render(
|
render(
|
||||||
conn,
|
conn,
|
||||||
:show,
|
:show,
|
||||||
domain: domain,
|
|
||||||
actor: actor,
|
actor: actor,
|
||||||
notes: notes,
|
notes: notes,
|
||||||
following: following,
|
following: following,
|
||||||
|
|
1
mix.exs
1
mix.exs
|
@ -43,7 +43,6 @@ defmodule Nulla.MixProject do
|
||||||
{:phoenix_live_dashboard, "~> 0.8.3"},
|
{:phoenix_live_dashboard, "~> 0.8.3"},
|
||||||
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
|
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
|
||||||
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev},
|
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev},
|
||||||
{:timex, "~> 3.7"},
|
|
||||||
{:heroicons,
|
{:heroicons,
|
||||||
github: "tailwindlabs/heroicons",
|
github: "tailwindlabs/heroicons",
|
||||||
tag: "v2.1.1",
|
tag: "v2.1.1",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue