diff --git a/lib/music_library_web/live/stats_live/index.ex b/lib/music_library_web/live/stats_live/index.ex
index b60b3ca8..f5b39548 100644
--- a/lib/music_library_web/live/stats_live/index.ex
+++ b/lib/music_library_web/live/stats_live/index.ex
@@ -16,342 +16,31 @@ defmodule MusicLibraryWeb.StatsLive.Index do
def render(assigns) do
~H"""
-
-
- {gettext("Records")}
-
-
- <.album_preview
- record={@latest_record}
- title={gettext("Latest purchase")}
- class="col-span-3 sm:col-span-2"
- />
- <.counter
- title={gettext("Collection")}
- count={@collection_count}
- path={~p"/collection"}
- />
- <.counter title={gettext("Wishlist")} count={@wishlist_count} path={~p"/wishlist"} />
- <.counter
- title={gettext("Scrobbles")}
- count={to_compact(@scrobble_count)}
- tooltip={@scrobble_count}
- path={~p"/scrobbled-tracks"}
- />
-
-
-
+ <.record_stats
+ latest_record={@latest_record}
+ collection_count={@collection_count}
+ wishlist_count={@wishlist_count}
+ scrobble_count={@scrobble_count}
+ />
-
-
- {gettext("Formats")}
-
- <.counters_by_category
- categories_with_counts={@collection_count_by_format}
- category_format_fn={&format_label/1}
- category_path_fn={fn format -> ~p"/collection?query=format:#{format}" end}
- />
-
-
-
-
- {gettext("Types")}
-
- <.counters_by_category
- categories_with_counts={@collection_count_by_type}
- category_format_fn={&type_label/1}
- category_path_fn={fn type -> ~p"/collection?query=type:#{type}" end}
- />
-
+ <.formats_stats collection_count_by_format={@collection_count_by_format} />
+ <.types_stats collection_count_by_type={@collection_count_by_type} />
-
-
-
-
- {gettext("On This day")}
-
- <.form
- :let={f}
- for={to_form(%{"current_date" => @current_date})}
- phx-change="set_current_date"
- >
- <.date_picker size="xs" field={f[:current_date]}>
- <:outer_suffix>
- <.button
- size="xs"
- type="button"
- phx-click={
- JS.push("set_current_date", value: %{"current_date" => Date.utc_today()})
- }
- >
- Today
-
-
-
-
-
-
- <.records_on_this_day
- current_date={@current_date}
- records={@records_on_this_day}
- record_show_path={fn record -> ~p"/collection/#{record}" end}
- />
-
-
+ <.on_this_day current_date={@current_date} records_on_this_day={@records_on_this_day} />
-
-
-
- {gettext("Scrobble activity")}
-
- <.refresh_lastfm_feed_button />
-
- <.tabs id="scrobble-activity" class="mt-4">
- <.tabs_list active_tab={@scrobble_activity_mode} variant="segmented" class="w-48">
- <:tab
- name="albums"
- phx-click={JS.push("set_scrobble_activity_mode", value: %{mode: "albums"})}
- >
- {gettext("Albums")}
-
- <:tab
- name="tracks"
- phx-click={JS.push("set_scrobble_activity_mode", value: %{mode: "tracks"})}
- >
- {gettext("Tracks")}
-
-
-
- <.tabs_panel name="albums" active={@scrobble_activity_mode == "albums"}>
-
- -
-
-
-
-
-
-

-
-
- {album.artist.name}
-
- <.link
- :if={artist_id(album, artist_id)}
- class="block text-sm font-semibold text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300"
- navigate={~p"/artists/#{artist_id(album, artist_id)}"}
- >
- {album.artist.name}
-
-
- {album.metadata.title}
-
-
- <.album_metadata_tooltip album={album} />
-
-
-
- <.record_status_badges
- musicbrainz_id={album.metadata.musicbrainz_id}
- collected_record_id={collected_record_id}
- wishlisted_record_id={wishlisted_record_id}
- />
-
- <.import_format_dropdown
- :if={
- album.metadata.musicbrainz_id !== "" and !collected_record_id and
- !wishlisted_record_id
- }
- id={"actions-#{album.scrobbled_at_uts}-albums"}
- musicbrainz_id={album.metadata.musicbrainz_id}
- />
-
-
-
-
-
- <.tabs_panel name="tracks" active={@scrobble_activity_mode == "tracks"}>
-
- -
-
-
-
-
-
-

-
-
- {track.artist.name}
-
- <.link
- :if={artist_id(track, artist_id)}
- class="block text-sm font-semibold text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300"
- navigate={~p"/artists/#{artist_id(track, artist_id)}"}
- >
- {track.artist.name}
-
-
- {track.title}
-
-
- {track.album.title}
-
-
- <.track_metadata_tooltip track={track} />
-
-
-
- <.record_status_badges
- musicbrainz_id={track.album.musicbrainz_id}
- collected_record_id={collected_record_id}
- wishlisted_record_id={wishlisted_record_id}
- />
-
- <.import_format_dropdown
- :if={
- track.album.musicbrainz_id !== "" and !collected_record_id and
- !wishlisted_record_id
- }
- id={"actions-#{track.scrobbled_at_uts}-tracks"}
- musicbrainz_id={track.album.musicbrainz_id}
- />
-
-
-
-
-
-
-
+ <.scrobble_activity
+ scrobble_activity_mode={@scrobble_activity_mode}
+ streams={@streams}
+ />
-
-
- {gettext("Top %{n} Collection Artists", %{n: length(@records_by_artist)})}
-
-
- <.vertical_bar_chart
- data={@records_by_artist}
- color_class="bg-red-500"
- label_fn={fn datum -> datum.name end}
- value_fn={fn datum -> datum.count end}
- datum_click={
- fn datum ->
- JS.navigate(~p"/artists/#{datum.id}")
- end
- }
- class="w-full"
- />
-
-
-
-
-
- {gettext("Top %{n} Collection Genres", %{n: length(@records_by_genre)})}
-
-
- <.vertical_bar_chart
- data={@records_by_genre}
- color_class="bg-zinc-500"
- label_fn={fn {genre, _count} -> genre end}
- value_fn={fn {_genre, count} -> count end}
- datum_click={
- fn {genre, _count} ->
- JS.navigate(~p"/collection?#{%{query: ~s(genre:"#{genre}")}}")
- end
- }
- class="w-full"
- />
-
-
-
-
-
- {gettext("Top 20 Release Years")}
-
-
- <.vertical_bar_chart
- data={@records_by_release_year}
- color_class="bg-zinc-800 dark:bg-zinc-300"
- label_fn={fn {year, _count} -> year end}
- value_fn={fn {_year, count} -> count end}
- datum_click={
- fn {year, _count} ->
- JS.navigate(~p"/collection?#{%{query: "release_year:#{year}"}}")
- end
- }
- class="w-full"
- />
-
-
+ <.top_collection_artists records_by_artist={@records_by_artist} />
+ <.top_collection_genres records_by_genre={@records_by_genre} />
+ <.top_release_years records_by_release_year={@records_by_release_year} />
"""
@@ -459,6 +148,366 @@ defmodule MusicLibraryWeb.StatsLive.Index do
|> assign_scrobble_activity()}
end
+ defp top_release_years(assigns) do
+ ~H"""
+
+
+ {gettext("Top 20 Release Years")}
+
+
+ <.vertical_bar_chart
+ data={@records_by_release_year}
+ color_class="bg-zinc-800 dark:bg-zinc-300"
+ label_fn={fn {year, _count} -> year end}
+ value_fn={fn {_year, count} -> count end}
+ datum_click={
+ fn {year, _count} ->
+ JS.navigate(~p"/collection?#{%{query: "release_year:#{year}"}}")
+ end
+ }
+ class="w-full"
+ />
+
+
+ """
+ end
+
+ defp top_collection_genres(assigns) do
+ ~H"""
+
+
+ {gettext("Top %{n} Collection Genres", %{n: length(@records_by_genre)})}
+
+
+ <.vertical_bar_chart
+ data={@records_by_genre}
+ color_class="bg-zinc-500"
+ label_fn={fn {genre, _count} -> genre end}
+ value_fn={fn {_genre, count} -> count end}
+ datum_click={
+ fn {genre, _count} ->
+ JS.navigate(~p"/collection?#{%{query: ~s(genre:"#{genre}")}}")
+ end
+ }
+ class="w-full"
+ />
+
+
+ """
+ end
+
+ defp top_collection_artists(assigns) do
+ ~H"""
+
+
+ {gettext("Top %{n} Collection Artists", %{n: length(@records_by_artist)})}
+
+
+ <.vertical_bar_chart
+ data={@records_by_artist}
+ color_class="bg-red-500"
+ label_fn={fn datum -> datum.name end}
+ value_fn={fn datum -> datum.count end}
+ datum_click={
+ fn datum ->
+ JS.navigate(~p"/artists/#{datum.id}")
+ end
+ }
+ class="w-full"
+ />
+
+
+ """
+ end
+
+ defp scrobble_activity(assigns) do
+ ~H"""
+
+
+
+ {gettext("Scrobble activity")}
+
+ <.refresh_lastfm_feed_button />
+
+ <.tabs id="scrobble-activity" class="mt-4">
+ <.tabs_list active_tab={@scrobble_activity_mode} variant="segmented" class="w-48">
+ <:tab
+ name="albums"
+ phx-click={JS.push("set_scrobble_activity_mode", value: %{mode: "albums"})}
+ >
+ {gettext("Albums")}
+
+ <:tab
+ name="tracks"
+ phx-click={JS.push("set_scrobble_activity_mode", value: %{mode: "tracks"})}
+ >
+ {gettext("Tracks")}
+
+
+
+ <.tabs_panel name="albums" active={@scrobble_activity_mode == "albums"}>
+
+ -
+
+
+
+
+
+

+
+
+ {album.artist.name}
+
+ <.link
+ :if={artist_id(album, artist_id)}
+ class="block text-sm font-semibold text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300"
+ navigate={~p"/artists/#{artist_id(album, artist_id)}"}
+ >
+ {album.artist.name}
+
+
+ {album.metadata.title}
+
+
+ <.album_metadata_tooltip album={album} />
+
+
+
+ <.record_status_badges
+ musicbrainz_id={album.metadata.musicbrainz_id}
+ collected_record_id={collected_record_id}
+ wishlisted_record_id={wishlisted_record_id}
+ />
+
+ <.import_format_dropdown
+ :if={
+ album.metadata.musicbrainz_id !== "" and !collected_record_id and
+ !wishlisted_record_id
+ }
+ id={"actions-#{album.scrobbled_at_uts}-albums"}
+ musicbrainz_id={album.metadata.musicbrainz_id}
+ />
+
+
+
+
+
+ <.tabs_panel name="tracks" active={@scrobble_activity_mode == "tracks"}>
+
+ -
+
+
+
+
+
+

+
+
+ {track.artist.name}
+
+ <.link
+ :if={artist_id(track, artist_id)}
+ class="block text-sm font-semibold text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300"
+ navigate={~p"/artists/#{artist_id(track, artist_id)}"}
+ >
+ {track.artist.name}
+
+
+ {track.title}
+
+
+ {track.album.title}
+
+
+ <.track_metadata_tooltip track={track} />
+
+
+
+ <.record_status_badges
+ musicbrainz_id={track.album.musicbrainz_id}
+ collected_record_id={collected_record_id}
+ wishlisted_record_id={wishlisted_record_id}
+ />
+
+ <.import_format_dropdown
+ :if={
+ track.album.musicbrainz_id !== "" and !collected_record_id and
+ !wishlisted_record_id
+ }
+ id={"actions-#{track.scrobbled_at_uts}-tracks"}
+ musicbrainz_id={track.album.musicbrainz_id}
+ />
+
+
+
+
+
+
+
+ """
+ end
+
+ defp on_this_day(assigns) do
+ ~H"""
+
+
+
+ {gettext("On This day")}
+
+ <.form
+ :let={f}
+ for={to_form(%{"current_date" => @current_date})}
+ phx-change="set_current_date"
+ >
+ <.date_picker size="xs" field={f[:current_date]}>
+ <:outer_suffix>
+ <.button
+ size="xs"
+ type="button"
+ phx-click={JS.push("set_current_date", value: %{"current_date" => Date.utc_today()})}
+ >
+ Today
+
+
+
+
+
+
+ <.records_on_this_day
+ current_date={@current_date}
+ records={@records_on_this_day}
+ record_show_path={fn record -> ~p"/collection/#{record}" end}
+ />
+
+
+ """
+ end
+
+ defp types_stats(assigns) do
+ ~H"""
+
+
+ {gettext("Types")}
+
+ <.counters_by_category
+ categories_with_counts={@collection_count_by_type}
+ category_format_fn={&type_label/1}
+ category_path_fn={fn type -> ~p"/collection?query=type:#{type}" end}
+ />
+
+ """
+ end
+
+ defp formats_stats(assigns) do
+ ~H"""
+
+
+ {gettext("Formats")}
+
+ <.counters_by_category
+ categories_with_counts={@collection_count_by_format}
+ category_format_fn={&format_label/1}
+ category_path_fn={fn format -> ~p"/collection?query=format:#{format}" end}
+ />
+
+ """
+ end
+
+ defp record_stats(assigns) do
+ ~H"""
+
+
+ {gettext("Records")}
+
+
+ <.album_preview
+ record={@latest_record}
+ title={gettext("Latest purchase")}
+ class="col-span-3 sm:col-span-2"
+ />
+ <.counter
+ title={gettext("Collection")}
+ count={@collection_count}
+ path={~p"/collection"}
+ />
+ <.counter title={gettext("Wishlist")} count={@wishlist_count} path={~p"/wishlist"} />
+ <.counter
+ title={gettext("Scrobbles")}
+ count={to_compact(@scrobble_count)}
+ tooltip={@scrobble_count}
+ path={~p"/scrobbled-tracks"}
+ />
+
+
+ """
+ end
+
defp assign_counts(socket) do
collection_count_by_format = Collection.count_records_by_format()