24319b1bff
To open source the project down the line, it makes sense to have either everything custom or using OSS components in order to keep licensing as simple as possible.
222 lines
8.3 KiB
Plaintext
222 lines
8.3 KiB
Plaintext
<div>
|
|
<h1 class="mt-5 text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
|
{gettext("Basics")}
|
|
</h1>
|
|
<%!-- TODO: replace with OSS version --%>
|
|
<dl class="mt-5 grid grid-cols-2 gap-5 sm:grid-cols-5">
|
|
<.album_preview
|
|
record={@latest_record}
|
|
title={gettext("Latest purchase")}
|
|
class="col-span-2 sm:col-span-3"
|
|
/>
|
|
<.counter
|
|
title={gettext("Total collection")}
|
|
count={@collection_count}
|
|
path={~p"/collection"}
|
|
/>
|
|
<.counter title={gettext("Total wishlist")} count={@wishlist_count} path={~p"/wishlist"} />
|
|
</dl>
|
|
</div>
|
|
|
|
<div>
|
|
<h1 class="mt-5 text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
|
{gettext("Formats")}
|
|
</h1>
|
|
<%!-- TODO: replace with OSS version --%>
|
|
<dl class={[
|
|
"mt-5 grid divide-zinc-200 dark:divide-slate-300/50 overflow-hidden rounded-md bg-white dark:bg-zinc-800 shadow divide-x",
|
|
stats_class(@collection_count_by_format)
|
|
]}>
|
|
<div :for={{format, count} <- @collection_count_by_format} class="px-2 py-5 sm:px-4">
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 text-center max-sm:text-xs break-keep">
|
|
{Record.format_long_label(format)}
|
|
</dt>
|
|
<dd class="mt-1 text-center">
|
|
<a
|
|
class="text-xl lg:text-2xl font-semibold hover:text-zinc-500 dark:text-zinc-300 dark:hover:text-zinc-200"
|
|
href={~p"/collection?query=format:#{format}"}
|
|
>
|
|
{count}
|
|
</a>
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<div>
|
|
<h1 class="mt-5 text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
|
{gettext("Types")}
|
|
</h1>
|
|
<%!-- TODO: replace with OSS version --%>
|
|
<dl class={[
|
|
"mt-5 grid divide-zinc-200 dark:divide-slate-300/50 overflow-hidden rounded-md bg-white dark:bg-zinc-800 shadow divide-x",
|
|
stats_class(@collection_count_by_type)
|
|
]}>
|
|
<div :for={{type, count} <- @collection_count_by_type} class="px-2 py-5 sm:px-4">
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 text-center max-sm:text-xs break-keep">
|
|
{Record.type_long_label(type)}
|
|
</dt>
|
|
<dd class="mt-1 text-center">
|
|
<a
|
|
class="text-xl lg:text-2xl font-semibold hover:text-zinc-500 dark:text-zinc-300 dark:hover:text-zinc-200"
|
|
href={~p"/collection?query=type:#{type}"}
|
|
>
|
|
{count}
|
|
</a>
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="flow-root">
|
|
<div class="mt-5 flex justify-between items-center">
|
|
<h1 class="text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
|
{gettext("Scrobble activity")}
|
|
</h1>
|
|
<button
|
|
type="button"
|
|
class="phx-click-loading:animate-spin text-zinc-500 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-300"
|
|
phx-click={JS.push("refresh_lastfm_feed")}
|
|
>
|
|
<span class="sr-only">{gettext("Refresh LastFm Feed")}</span>
|
|
<.icon name="hero-arrow-path" class="-mt-1 h-5 w-5" aria-hidden="true" data-slot="icon" />
|
|
</button>
|
|
</div>
|
|
<%!-- TODO: replace with OSS version --%>
|
|
<ul
|
|
id="scrobble-activity"
|
|
role="list"
|
|
class="mt-5 rounded-md px-4 py-5 shadow"
|
|
phx-update="stream"
|
|
>
|
|
<li :for={{id, track} <- @streams.recent_tracks} id={id} class="group">
|
|
<div class="relative pb-8 group-last:pb-0">
|
|
<span
|
|
class="group-last:hidden absolute left-6 top-6 -ml-px h-full w-0.5 bg-zinc-200"
|
|
aria-hidden="true"
|
|
>
|
|
</span>
|
|
<div class="relative flex space-x-3 items-center justify-between">
|
|
<div class="flex min-w-0 justify-between space-x-4 items-center">
|
|
<img class="h-12 w-12 rounded-md shadow" src={track.cover_url} alt={track.title} />
|
|
<div>
|
|
<p class="font-semibold text-sm block text-zinc-500 dark:text-zinc-400">
|
|
{track.artist.name}
|
|
</p>
|
|
<p class="font-semibold text-sm md:text-base text-zinc-700 dark:text-zinc-300">
|
|
{track.title}
|
|
</p>
|
|
<p class="font-semibold text-sm text-zinc-500 dark:text-zinc-400">
|
|
{track.album.title}
|
|
</p>
|
|
<time
|
|
datetime={format_scrobbled_at_uts(track.scrobbled_at_uts)}
|
|
class="whitespace-nowrap text-right text-xs sm:text-sm text-zinc-500 dark:text-zinc-400"
|
|
>
|
|
{track.scrobbled_at_label}
|
|
</time>
|
|
</div>
|
|
</div>
|
|
|
|
<span
|
|
:if={track.album.musicbrainz_id == ""}
|
|
class={[
|
|
"inline-flex items-center rounded-md",
|
|
"px-2 py-1 text-xs font-medium",
|
|
"ring-1 ring-inset",
|
|
"bg-zinc-50 dark:bg-zinc-500/10",
|
|
"text-zinc-700 dark:text-zinc-400",
|
|
"ring-zinc-600/20 dark:ring-zinc-500/20"
|
|
]}
|
|
>
|
|
{gettext("No MB ID")}
|
|
</span>
|
|
<span
|
|
:if={track.album.musicbrainz_id in @collected_release_ids}
|
|
class={[
|
|
"inline-flex items-center rounded-md",
|
|
"px-2 py-1 text-xs font-medium",
|
|
"ring-1 ring-inset",
|
|
"bg-green-50 dark:bg-green-500/10",
|
|
"text-green-700 dark:text-green-400",
|
|
"ring-green-600/20 dark:ring-green-500/20"
|
|
]}
|
|
>
|
|
{gettext("Collected")}
|
|
</span>
|
|
<span
|
|
:if={track.album.musicbrainz_id in @wishlisted_release_ids}
|
|
class={[
|
|
"inline-flex items-center rounded-md",
|
|
"px-2 py-1 text-xs font-medium",
|
|
"ring-1 ring-inset",
|
|
"bg-yellow-50 dark:bg-yellow-400/10",
|
|
"text-yellow-800 dark:text-yellow-500",
|
|
"ring-yellow-600/20 dark:ring-yellow-400/20"
|
|
]}
|
|
>
|
|
{gettext("Wishlisted")}
|
|
</span>
|
|
|
|
<div
|
|
:if={
|
|
track.album.musicbrainz_id !== "" and
|
|
track.album.musicbrainz_id not in @collected_release_ids and
|
|
track.album.musicbrainz_id not in @wishlisted_release_ids
|
|
}
|
|
class="relative flex-none"
|
|
>
|
|
<button
|
|
type="button"
|
|
class="text-zinc-500 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-300"
|
|
aria-expanded="false"
|
|
aria-haspopup="true"
|
|
phx-click={toggle_actions_menu(track.scrobbled_at_uts)}
|
|
phx-click-away={close_actions_menu(track.scrobbled_at_uts)}
|
|
>
|
|
<span class="sr-only">{gettext("Choose which format to import")}</span>
|
|
<.icon name="hero-star" class="-mt-1 h-5 w-5" aria-hidden="true" data-slot="icon" />
|
|
</button>
|
|
<!--
|
|
Dropdown menu, show/hide based on menu state.
|
|
|
|
Entering: "transition ease-out duration-100"
|
|
From: "transform opacity-0 scale-95"
|
|
To: "transform opacity-100 scale-100"
|
|
Leaving: "transition ease-in duration-75"
|
|
From: "transform opacity-100 scale-100"
|
|
To: "transform opacity-0 scale-95"
|
|
-->
|
|
<.focus_wrap
|
|
id={"actions-#{track.scrobbled_at_uts}"}
|
|
class={[
|
|
"hidden pointer-events-auto absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white dark:bg-zinc-800 py-2 shadow-lg ring-1 ring-zinc-900/5 focus:outline-none"
|
|
]}
|
|
role="menu"
|
|
aria-orientation="vertical"
|
|
aria-labelledby="options-menu-0-button"
|
|
tabindex="-1"
|
|
>
|
|
<.link
|
|
:for={format <- Records.Record.formats()}
|
|
class="block px-3 py-1 text-sm leading-6 text-zinc-900 dark:text-zinc-400 hover:bg-zinc-50 dark:hover:text-zinc-300 dark:hover:bg-zinc-700"
|
|
role="menuitem"
|
|
tabindex="-1"
|
|
id={"actions-#{track.scrobbled_at_uts}-#{format}-import"}
|
|
phx-click={
|
|
JS.push("import",
|
|
value: %{id: track.album.musicbrainz_id, format: format},
|
|
page_loading: true
|
|
)
|
|
}
|
|
>
|
|
{Records.Record.format_long_label(format)}
|
|
</.link>
|
|
</.focus_wrap>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|