diff --git a/lib/music_library_web.ex b/lib/music_library_web.ex index a51427f2..b475c88d 100644 --- a/lib/music_library_web.ex +++ b/lib/music_library_web.ex @@ -62,8 +62,7 @@ defmodule MusicLibraryWeb do def live_view do quote do - use Phoenix.LiveView, - layout: {MusicLibraryWeb.Layouts, :app} + use Phoenix.LiveView unquote(html_helpers()) end @@ -102,6 +101,7 @@ defmodule MusicLibraryWeb do # HTML escaping functionality import Phoenix.HTML + alias MusicLibraryWeb.Layouts # Shortcut for generating JS commands alias Phoenix.LiveView.JS diff --git a/lib/music_library_web/components/layouts/app.html.heex b/lib/music_library_web/components/layouts/app.html.heex index b0c62bdc..3f3242b7 100644 --- a/lib/music_library_web/components/layouts/app.html.heex +++ b/lib/music_library_web/components/layouts/app.html.heex @@ -126,7 +126,7 @@ toasts_sync={assigns[:toasts_sync]} toast_class_fn={&toast_class_fn/1} /> - {@inner_content} + {render_slot(@inner_block)} diff --git a/lib/music_library_web/live/artist_live/show.html.heex b/lib/music_library_web/live/artist_live/show.html.heex index 967884a2..b492bff3 100644 --- a/lib/music_library_web/live/artist_live/show.html.heex +++ b/lib/music_library_web/live/artist_live/show.html.heex @@ -1,270 +1,272 @@ -
-
-
-

- {@artist.name} - <.country_flag country={@country} /> -

+ +
+
+
+

+ {@artist.name} + <.country_flag country={@country} /> +

-
- - <.dropdown id={"actions-#{@artist.musicbrainz_id}"} placement="bottom-end"> - <:toggle> - {gettext("Actions")} +
+
-
- -
- <.async_result :let={lastfm_artist_info} assign={@lastfm_artist_info}> - <:loading> - {gettext("Loading play count")} - <.loading /> - - <:failed :let={_failure}> -
- <.icon - name="hero-exclamation-triangle" - class="-mt-1 mr-1 ml-2 h-5 w-5" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Error loading play count")} -
- - <.on_tour_link lastfm_artist_info={lastfm_artist_info} /> - <.play_count play_count={lastfm_artist_info.play_count} /> - - <.button variant="solid" patch={~p"/artists/#{@artist.musicbrainz_id}/import"}> - <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("Add more")} - -
-
- -
-
-

- {gettext("Meta")} -

- <.artist_image - class="w-full rounded-md shadow-sm mt-4" - artist={@artist} - image_hash={@artist_info.image_data_hash} - /> -
-
- {gettext("MusicBrainz ID")} -
-
- - - {@artist.musicbrainz_id} - - - -
-
- <.async_result :let={lastfm_artist_info} assign={@lastfm_artist_info}> - <:loading> -
- {gettext("Loading biography")} -
- - <:failed :let={_failure}> -
- <.icon - name="hero-exclamation-triangle" - class="-mt-1 mr-1 h-5 w-5" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Error loading biography")} -
- -
- {gettext("Biography")} -
-
- {remove_read_more_link(lastfm_artist_info.summary)} - <.link - class="block mt-2 text-sm font-medium text-zinc-900 dark:text-zinc-400" - phx-click={Fluxon.open_dialog("bio")} - > - <.icon - name="hero-arrow-right-end-on-rectangle" - class="-mt-1 mr-1 h-5 w-5" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Read more")} - -
- <.sheet id="bio" class="max-w-2xl text-zinc-700 dark:text-zinc-300" placement="left"> - {render_bio(lastfm_artist_info.bio)} - - -
-
- <.record_grid - :if={@collection_records_count > 0} - title={gettext("Collection")} - id="collection" - records={@streams.collection_records} - records_count={@collection_records_count} - record_show_path={fn record -> ~p"/collection/#{record}" end} - record_edit_path={fn record -> ~p"/collection/#{record}/show/edit" end} - /> - <.separator :if={@wishlist_records_count > 0} class="mt-8 mb-8" /> - <.record_grid - :if={@wishlist_records_count > 0} - title={gettext("Wishlist")} - id="wishlist" - records={@streams.wishlist_records} - records_count={@wishlist_records_count} - record_show_path={fn record -> ~p"/wishlist/#{record}" end} - record_edit_path={fn record -> ~p"/wishlist/#{record}/show/edit" end} - /> + <.dropdown id={"actions-#{@artist.musicbrainz_id}"} placement="bottom-end"> + <:toggle> + {gettext("Actions")} + <.icon + name="hero-ellipsis-vertical" + class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" + aria-hidden="true" + data-slot="icon" + /> + + <.focus_wrap id={"actions-#{@artist.musicbrainz_id}-focus-wrap"}> + <.dropdown_link + id={"actions-#{@artist.musicbrainz_id}-edit"} + patch={~p"/artists/#{@artist.musicbrainz_id}/edit"} + > + <.icon + name="hero-pencil-square" + class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Edit")} + + <.dropdown_link + id={"actions-#{@artist.musicbrainz_id}-refresh-image"} + phx-click={JS.push("refresh_artist_image", value: %{id: @artist.musicbrainz_id})} + > + <.icon + name="hero-photo" + class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Refresh image")} + - <.async_result :let={similar_artists} assign={@similar_artists}> - <:loading> -
- {gettext("Loading similar artists")} -
- - <:failed :let={_failure}> -
- <.icon - name="hero-exclamation-triangle" - class="-mt-1 mr-1 h-5 w-5" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Error loading similar artists")} -
- - <.separator class="mt-8 mb-8" /> - <.artist_grid title={gettext("Similar artists")} artists={similar_artists} /> - + <.dropdown_link + id={"actions-#{@artist.musicbrainz_id}-refresh-artist-info"} + phx-click={JS.push("refresh_artist_info", value: %{id: @artist.musicbrainz_id})} + > + <.icon + name="hero-arrow-path" + class="h-4 w-4 mr-1 phx-click-loading:animate-spin" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Refresh info")} + + + +
+
+ +
+ <.async_result :let={lastfm_artist_info} assign={@lastfm_artist_info}> + <:loading> + {gettext("Loading play count")} + <.loading /> + + <:failed :let={_failure}> +
+ <.icon + name="hero-exclamation-triangle" + class="-mt-1 mr-1 ml-2 h-5 w-5" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Error loading play count")} +
+ + <.on_tour_link lastfm_artist_info={lastfm_artist_info} /> + <.play_count play_count={lastfm_artist_info.play_count} /> + + <.button variant="solid" patch={~p"/artists/#{@artist.musicbrainz_id}/import"}> + <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Add more")} + +
+
+ +
+
+

+ {gettext("Meta")} +

+ <.artist_image + class="w-full rounded-md shadow-sm mt-4" + artist={@artist} + image_hash={@artist_info.image_data_hash} + /> +
+
+ {gettext("MusicBrainz ID")} +
+
+ + + {@artist.musicbrainz_id} + + + +
+
+ <.async_result :let={lastfm_artist_info} assign={@lastfm_artist_info}> + <:loading> +
+ {gettext("Loading biography")} +
+ + <:failed :let={_failure}> +
+ <.icon + name="hero-exclamation-triangle" + class="-mt-1 mr-1 h-5 w-5" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Error loading biography")} +
+ +
+ {gettext("Biography")} +
+
+ {remove_read_more_link(lastfm_artist_info.summary)} + <.link + class="block mt-2 text-sm font-medium text-zinc-900 dark:text-zinc-400" + phx-click={Fluxon.open_dialog("bio")} + > + <.icon + name="hero-arrow-right-end-on-rectangle" + class="-mt-1 mr-1 h-5 w-5" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Read more")} + +
+ <.sheet id="bio" class="max-w-2xl text-zinc-700 dark:text-zinc-300" placement="left"> + {render_bio(lastfm_artist_info.bio)} + + +
+
+ <.record_grid + :if={@collection_records_count > 0} + title={gettext("Collection")} + id="collection" + records={@streams.collection_records} + records_count={@collection_records_count} + record_show_path={fn record -> ~p"/collection/#{record}" end} + record_edit_path={fn record -> ~p"/collection/#{record}/show/edit" end} + /> + <.separator :if={@wishlist_records_count > 0} class="mt-8 mb-8" /> + <.record_grid + :if={@wishlist_records_count > 0} + title={gettext("Wishlist")} + id="wishlist" + records={@streams.wishlist_records} + records_count={@wishlist_records_count} + record_show_path={fn record -> ~p"/wishlist/#{record}" end} + record_edit_path={fn record -> ~p"/wishlist/#{record}/show/edit" end} + /> + + <.async_result :let={similar_artists} assign={@similar_artists}> + <:loading> +
+ {gettext("Loading similar artists")} +
+ + <:failed :let={_failure}> +
+ <.icon + name="hero-exclamation-triangle" + class="-mt-1 mr-1 h-5 w-5" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Error loading similar artists")} +
+ + <.separator class="mt-8 mb-8" /> + <.artist_grid title={gettext("Similar artists")} artists={similar_artists} /> + +
+ + <.json_viewer + :if={@artist_info.musicbrainz_data} + title={gettext("MusicBrainz data")} + data={@artist_info.musicbrainz_data} + /> + + <.json_viewer + :if={@artist_info.discogs_data} + title={gettext("Discogs data")} + data={@artist_info.discogs_data} + />
- <.json_viewer - :if={@artist_info.musicbrainz_data} - title={gettext("MusicBrainz data")} - data={@artist_info.musicbrainz_data} - /> + <.structured_modal + :if={@live_action == :import} + id="record-modal" + on_close={JS.patch(~p"/artists/#{@artist.musicbrainz_id}")} + > + <.live_component + module={MusicLibraryWeb.AddRecordComponent} + id={:search} + title={@page_title} + action={@live_action} + patch={~p"/artists/#{@artist.musicbrainz_id}"} + initial_query={"arid:#{@artist.musicbrainz_id}"} + icon_name="hero-plus" + /> + - <.json_viewer - :if={@artist_info.discogs_data} - title={gettext("Discogs data")} - data={@artist_info.discogs_data} - /> - - -<.structured_modal - :if={@live_action == :import} - id="record-modal" - on_close={JS.patch(~p"/artists/#{@artist.musicbrainz_id}")} -> <.live_component - module={MusicLibraryWeb.AddRecordComponent} - id={:search} - title={@page_title} - action={@live_action} - patch={~p"/artists/#{@artist.musicbrainz_id}"} - initial_query={"arid:#{@artist.musicbrainz_id}"} - icon_name="hero-plus" + id="artist-notes" + sheet_id="artist-notes-sheet" + module={MusicLibraryWeb.NotesComponent} + entity={:artist} + musicbrainz_id={@artist.musicbrainz_id} /> - -<.live_component - id="artist-notes" - sheet_id="artist-notes-sheet" - module={MusicLibraryWeb.NotesComponent} - entity={:artist} - musicbrainz_id={@artist.musicbrainz_id} -/> - -<.structured_modal - :if={@live_action == :edit} - id="artist-info-modal" - on_close={JS.patch(~p"/artists/#{@artist.musicbrainz_id}")} -> - <.live_component - module={MusicLibraryWeb.ArtistLive.FormComponent} - id={@artist_info.id} - action={@live_action} - artist_info={@artist_info} - artist={@artist} - patch={~p"/artists/#{@artist.musicbrainz_id}"} - /> - + <.structured_modal + :if={@live_action == :edit} + id="artist-info-modal" + on_close={JS.patch(~p"/artists/#{@artist.musicbrainz_id}")} + > + <.live_component + module={MusicLibraryWeb.ArtistLive.FormComponent} + id={@artist_info.id} + action={@live_action} + artist_info={@artist_info} + artist={@artist} + patch={~p"/artists/#{@artist.musicbrainz_id}"} + /> + + diff --git a/lib/music_library_web/live/collection_live/index.html.heex b/lib/music_library_web/live/collection_live/index.html.heex index 3e29cbb1..c8ad8c70 100644 --- a/lib/music_library_web/live/collection_live/index.html.heex +++ b/lib/music_library_web/live/collection_live/index.html.heex @@ -1,109 +1,111 @@ -
-
-
- <.search_form query={@record_list_params.query} /> + +
+
+
+ <.search_form query={@record_list_params.query} /> + <.button_group> + <.button + variant="solid" + size="sm" + patch={~p"/collection/import"} + > + <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Add")} + + <.button + variant="solid" + size="sm" + patch={~p"/collection/scan"} + > + <.barcode_icon class="icon fill-current" /> + {gettext("Scan")} + + +
+
+ +
<.button_group> <.button - variant="solid" + patch={order_path(@record_list_params, :purchase)} size="sm" - patch={~p"/collection/import"} + class={[ + @record_list_params.order == :purchase && "!bg-zinc-100 dark:!bg-zinc-700" + ]} > - <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("Add")} + <.icon + name="hero-banknotes-solid" + class="icon" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Purchase")} <.button - variant="solid" + patch={order_path(@record_list_params, :alphabetical)} size="sm" - patch={~p"/collection/scan"} + class={[ + @record_list_params.order == :alphabetical && "!bg-zinc-100 dark:!bg-zinc-700" + ]} > - <.barcode_icon class="icon fill-current" /> - {gettext("Scan")} + <.icon name="hero-user-solid" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("A->Z")}
-
- -
- <.button_group> - <.button - patch={order_path(@record_list_params, :purchase)} - size="sm" - class={[ - @record_list_params.order == :purchase && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon - name="hero-banknotes-solid" - class="icon" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Purchase")} - - <.button - patch={order_path(@record_list_params, :alphabetical)} - size="sm" - class={[ - @record_list_params.order == :alphabetical && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon name="hero-user-solid" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("A->Z")} - -
-
-<.record_list - records={@streams.records} - record_show_path={fn record -> ~p"/collection/#{record}" end} - record_edit_path={fn record -> ~p"/collection/#{record}/edit" end} -/> - -<.structured_modal - :if={@live_action == :edit} - id="record-modal" - on_close={JS.patch(back_path(@record_list_params))} -> - <.live_component - module={MusicLibraryWeb.RecordFormComponent} - id={@record.id} - action={@live_action} - show_purchased_at={true} - record={@record} - patch={back_path(@record_list_params)} + <.record_list + records={@streams.records} + record_show_path={fn record -> ~p"/collection/#{record}" end} + record_edit_path={fn record -> ~p"/collection/#{record}/edit" end} /> - -<.structured_modal - :if={@live_action == :import} - id="record-modal" - on_close={JS.patch(back_path(@record_list_params))} -> - <.live_component - module={MusicLibraryWeb.AddRecordComponent} - id={:search} - title={@page_title} - action={@live_action} - record={@record} - patch={back_path(@record_list_params)} - initial_query="" - icon_name="hero-plus" - /> - + <.structured_modal + :if={@live_action == :edit} + id="record-modal" + on_close={JS.patch(back_path(@record_list_params))} + > + <.live_component + module={MusicLibraryWeb.RecordFormComponent} + id={@record.id} + action={@live_action} + show_purchased_at={true} + record={@record} + patch={back_path(@record_list_params)} + /> + -<.structured_modal - :if={@live_action == :barcode_scan} - id="barcode-scanner-modal" - on_close={JS.patch(back_path(@record_list_params))} -> - <.live_component - module={MusicLibraryWeb.BarcodeScannerComponent} - id={:barcode_scanner} - title={@page_title} - action={@live_action} - patch={back_path(@record_list_params)} - /> - + <.structured_modal + :if={@live_action == :import} + id="record-modal" + on_close={JS.patch(back_path(@record_list_params))} + > + <.live_component + module={MusicLibraryWeb.AddRecordComponent} + id={:search} + title={@page_title} + action={@live_action} + record={@record} + patch={back_path(@record_list_params)} + initial_query="" + icon_name="hero-plus" + /> + -<.pagination id={:bottom_pagination} pagination_params={@record_list_params} /> + <.structured_modal + :if={@live_action == :barcode_scan} + id="barcode-scanner-modal" + on_close={JS.patch(back_path(@record_list_params))} + > + <.live_component + module={MusicLibraryWeb.BarcodeScannerComponent} + id={:barcode_scanner} + title={@page_title} + action={@live_action} + patch={back_path(@record_list_params)} + /> + + + <.pagination id={:bottom_pagination} pagination_params={@record_list_params} /> + diff --git a/lib/music_library_web/live/collection_live/show.html.heex b/lib/music_library_web/live/collection_live/show.html.heex index 6c497e0b..80d5c1cf 100644 --- a/lib/music_library_web/live/collection_live/show.html.heex +++ b/lib/music_library_web/live/collection_live/show.html.heex @@ -1,356 +1,360 @@ -
-
- <.record_cover - record={@record} - class="w-full rounded-lg drop-shadow-sm" - /> -
+ +
+
+ <.record_cover + record={@record} + class="w-full rounded-lg drop-shadow-sm" + /> +
-
-
-
-

- <.artist_links joinphrase_class="text-sm" artists={@record.artists} /> -

-

- {@record.title} -

-

- <.record_colors record={@record} /> - - {Records.Record.format_release_date(@record.release_date)} · {format_label( - @record.format - )} · {type_label(@record.type)} - -

-
-
- - - <.dropdown id={"actions-#{@record.id}"} placement="bottom-end"> - <:toggle class="h-5 block"> - {gettext("Actions")} +
+
+
+

+ <.artist_links joinphrase_class="text-sm" artists={@record.artists} /> +

+

+ {@record.title} +

+

+ <.record_colors record={@record} /> + + {Records.Record.format_release_date(@record.release_date)} · {format_label( + @record.format + )} · {type_label(@record.type)} + +

+
+
+ + + <.dropdown id={"actions-#{@record.id}"} placement="bottom-end"> + <:toggle class="h-5 block"> + {gettext("Actions")} <.icon - name="hero-pencil-square" - class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" + name="hero-ellipsis-vertical" + class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" aria-hidden="true" data-slot="icon" /> - {gettext("Edit")} - + + <.focus_wrap id={"actions-#{@record.id}-focus-wrap"}> + <.dropdown_link + id={"actions-#{@record.id}-edit"} + patch={~p"/collection/#{@record}/show/edit"} + > + <.icon + name="hero-pencil-square" + class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Edit")} + - <.dropdown_link - id={"actions-#{@record.id}-refresh-cover"} - phx-click={JS.push("refresh_cover", value: %{id: @record.id})} - > - <.icon - name="hero-photo" - class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Refresh cover")} - + <.dropdown_link + id={"actions-#{@record.id}-refresh-cover"} + phx-click={JS.push("refresh_cover", value: %{id: @record.id})} + > + <.icon + name="hero-photo" + class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Refresh cover")} + - <.dropdown_link - id={"actions-#{@record.id}-refresh-mb-data"} - phx-click={JS.push("refresh_musicbrainz_data", value: %{id: @record.id})} - > - <.icon - name="hero-arrow-path" - class="h-4 w-4 mr-1 phx-click-loading:animate-spin" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Refresh MB data")} - + <.dropdown_link + id={"actions-#{@record.id}-refresh-mb-data"} + phx-click={JS.push("refresh_musicbrainz_data", value: %{id: @record.id})} + > + <.icon + name="hero-arrow-path" + class="h-4 w-4 mr-1 phx-click-loading:animate-spin" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Refresh MB data")} + - <.dropdown_link - id={"actions-#{@record.id}-populate-genres"} - phx-click={JS.push("populate_genres", value: %{id: @record.id})} - > - <.icon - name="hero-sparkles" - class="h-4 w-4 mr-1 phx-click-loading:animate-shake" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Populate genres")} - + <.dropdown_link + id={"actions-#{@record.id}-populate-genres"} + phx-click={JS.push("populate_genres", value: %{id: @record.id})} + > + <.icon + name="hero-sparkles" + class="h-4 w-4 mr-1 phx-click-loading:animate-shake" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Populate genres")} + - <.dropdown_link - id={"actions-#{@record.id}-extract-colors-fast"} - phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :fast})} - > - <.icon - name="hero-paint-brush" - class="h-4 w-4 mr-1 phx-click-loading:animate-shake" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Extract colors (fast)")} - + <.dropdown_link + id={"actions-#{@record.id}-extract-colors-fast"} + phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :fast})} + > + <.icon + name="hero-paint-brush" + class="h-4 w-4 mr-1 phx-click-loading:animate-shake" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Extract colors (fast)")} + - <.dropdown_link - id={"actions-#{@record.id}-extract-colors-slow"} - phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :slow})} - > - <.icon - name="hero-paint-brush" - class="h-4 w-4 mr-1 phx-click-loading:animate-shake" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Extract colors (slow)")} - + <.dropdown_link + id={"actions-#{@record.id}-extract-colors-slow"} + phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :slow})} + > + <.icon + name="hero-paint-brush" + class="h-4 w-4 mr-1 phx-click-loading:animate-shake" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Extract colors (slow)")} + - <.dropdown_separator /> - <.dropdown_link - id={"actions-#{@record.id}-delete"} - phx-click={JS.push("delete", value: %{id: @record.id})} - data-confirm={gettext("Are you sure?")} - class="text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" - > - <.icon - name="hero-trash" - class="h-4 w-4 mr-1 phx-click-loading:animate-spin" - aria-hidden="true" - data-slot="icon" + <.dropdown_separator /> + <.dropdown_link + id={"actions-#{@record.id}-delete"} + phx-click={JS.push("delete", value: %{id: @record.id})} + data-confirm={gettext("Are you sure?")} + class="text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" + > + <.icon + name="hero-trash" + class="h-4 w-4 mr-1 phx-click-loading:animate-spin" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Delete")} + + + +
+
+
+ <%!-- TODO: replace with OSS version --%> +
+
+
+ {gettext("ID")} +
+
+ {@record.id} + +
+
+
+
+ {gettext("Genres")} +
+
+ <.link + :for={genre <- @record.genres} + class="mr-2 text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" + patch={~p"/collection?#{%{query: ~s(genre:"#{genre}")}}"} + > + {genre} + +
+
+
+
+ {gettext("MusicBrainz ID")} +
+
+ + {@record.musicbrainz_id} + + +
+
+
+
+ {gettext("Purchased on")} +
+
+ {Records.Record.format_as_date(@record.purchased_at)} +
+
+
+
+ {gettext("Published releases")} +
+
+ {Records.Record.release_count(@record)} +
+
+
+
+ {gettext("Collected release")} +
+
+ + {gettext("No release selected")} + + + <.release_summary + :if={@record.selected_release_id} + release={Records.Record.selected_release(@record)} /> - {gettext("Delete")} - - - + @record.id} + class="hidden" + > + {@record.selected_release_id} + + + +
+
+
0} + class="py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" + > +
+ {gettext("Includes")} +
+
+
    +
  • + {included_release_group.artists} - {included_release_group.title} +
  • +
+
+
+
+
+ {gettext("Inserted at")} +
+
+ {Records.Record.format_as_date(@record.inserted_at)} +
+
+
+
+ {gettext("Updated at")} +
+
+ {Records.Record.format_as_date(@record.updated_at)} +
+
+
+
+ {gettext("Last listened at")} +
+
+ {@last_listened_track && + localize_scrobbled_at(@last_listened_track.scrobbled_at_uts, @timezone)} +
+
+
-
- <%!-- TODO: replace with OSS version --%> -
-
-
- {gettext("ID")} -
-
- {@record.id} - -
-
-
-
- {gettext("Genres")} -
-
- <.link - :for={genre <- @record.genres} - class="mr-2 text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" - patch={~p"/collection?#{%{query: ~s(genre:"#{genre}")}}"} - > - {genre} - -
-
-
-
- {gettext("MusicBrainz ID")} -
-
- - {@record.musicbrainz_id} - - -
-
-
-
- {gettext("Purchased on")} -
-
- {Records.Record.format_as_date(@record.purchased_at)} -
-
-
-
- {gettext("Published releases")} -
-
- {Records.Record.release_count(@record)} -
-
-
-
- {gettext("Collected release")} -
-
- - {gettext("No release selected")} - - - <.release_summary - :if={@record.selected_release_id} - release={Records.Record.selected_release(@record)} - /> - @record.id} - class="hidden" - > - {@record.selected_release_id} - - - -
-
-
0} - class="py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" - > -
- {gettext("Includes")} -
-
-
    -
  • - {included_release_group.artists} - {included_release_group.title} -
  • -
-
-
-
-
- {gettext("Inserted at")} -
-
- {Records.Record.format_as_date(@record.inserted_at)} -
-
-
-
- {gettext("Updated at")} -
-
- {Records.Record.format_as_date(@record.updated_at)} -
-
-
-
- {gettext("Last listened at")} -
-
- {@last_listened_track && - localize_scrobbled_at(@last_listened_track.scrobbled_at_uts, @timezone)} -
-
-
-
-
-<.json_viewer title={gettext("MusicBrainz data")} data={@record.musicbrainz_data} /> + <.json_viewer title={gettext("MusicBrainz data")} data={@record.musicbrainz_data} /> -<.live_component - id="release-with-tracks" - sheet_id="release-with-tracks-sheet" - module={MusicLibraryWeb.ReleaseComponent} - record={@record} -/> - -<.live_component - id="record-notes" - sheet_id="record-notes-sheet" - module={MusicLibraryWeb.NotesComponent} - entity={:record} - musicbrainz_id={@record.musicbrainz_id} -/> - -<.structured_modal - :if={@live_action == :edit} - id="record-modal" - on_close={JS.patch(~p"/collection/#{@record}")} -> <.live_component - module={MusicLibraryWeb.RecordFormComponent} - id={@record.id} - action={@live_action} - show_purchased_at={true} + id="release-with-tracks" + sheet_id="release-with-tracks-sheet" + module={MusicLibraryWeb.ReleaseComponent} record={@record} - patch={~p"/collection/#{@record}"} /> - + + <.live_component + id="record-notes" + sheet_id="record-notes-sheet" + module={MusicLibraryWeb.NotesComponent} + entity={:record} + musicbrainz_id={@record.musicbrainz_id} + /> + + <.structured_modal + :if={@live_action == :edit} + id="record-modal" + on_close={JS.patch(~p"/collection/#{@record}")} + > + <.live_component + module={MusicLibraryWeb.RecordFormComponent} + id={@record.id} + action={@live_action} + show_purchased_at={true} + record={@record} + patch={~p"/collection/#{@record}"} + /> + + diff --git a/lib/music_library_web/live/online_store_template_live/index.html.heex b/lib/music_library_web/live/online_store_template_live/index.html.heex index 7bce0557..1417a6f5 100644 --- a/lib/music_library_web/live/online_store_template_live/index.html.heex +++ b/lib/music_library_web/live/online_store_template_live/index.html.heex @@ -1,106 +1,108 @@ -
-
-
-

- {gettext("Online Store Templates")} -

+ +
+
+
+

+ {gettext("Online Store Templates")} +

+
+
+ <.button variant="solid" size="sm" patch={~p"/online-store-templates/new"}> + <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("New Template")} + +
-
- <.button variant="solid" size="sm" patch={~p"/online-store-templates/new"}> - <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("New Template")} - -
-
-
+ -
-
    -
  • +
      -
      -
      - {template.name} -

      - {template.name} +

    • +
      +
      + {template.name} +

      + {template.name} +

      + <.badge :if={template.enabled} color="success"> + {gettext("Enabled")} + + <.badge :if={!template.enabled} color="warning"> + {gettext("Disabled")} + +
      +
      +

      {template.url_template}

      +
      +

      + {template.description}

      - <.badge :if={template.enabled} color="success"> - {gettext("Enabled")} - - <.badge :if={!template.enabled} color="warning"> - {gettext("Disabled")} -
      -
      -

      {template.url_template}

      +
      + <.dropdown id={"actions-#{template.id}"} placement="bottom-end"> + <:toggle> +
      + {gettext("Actions")} + <.icon + name="hero-ellipsis-vertical" + class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" + aria-hidden="true" + data-slot="icon" + /> +
      + + <.dropdown_button phx-click="toggle-enabled" phx-value-id={template.id}> + {if template.enabled, + do: gettext("Disable template"), + else: gettext("Enable template")} + + <.dropdown_link + id={"actions-#{template.id}-edit"} + patch={~p"/online-store-templates/#{template}/edit"} + > + {gettext("Edit")} + + <.separator /> + <.dropdown_button + phx-click="delete" + phx-value-id={template.id} + data-confirm={gettext("Are you sure?")} + class={[ + "text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" + ]} + > + {gettext("Delete")} + +
      -

      - {template.description} -

      -
      -
      - <.dropdown id={"actions-#{template.id}"} placement="bottom-end"> - <:toggle> -
      - {gettext("Actions")} - <.icon - name="hero-ellipsis-vertical" - class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" - aria-hidden="true" - data-slot="icon" - /> -
      - - <.dropdown_button phx-click="toggle-enabled" phx-value-id={template.id}> - {if template.enabled, - do: gettext("Disable template"), - else: gettext("Enable template")} - - <.dropdown_link - id={"actions-#{template.id}-edit"} - patch={~p"/online-store-templates/#{template}/edit"} - > - {gettext("Edit")} - - <.separator /> - <.dropdown_button - phx-click="delete" - phx-value-id={template.id} - data-confirm={gettext("Are you sure?")} - class={[ - "text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" - ]} - > - {gettext("Delete")} - - -
      -
    • -
    -
+ + +
-<.structured_modal - :if={@live_action in [:new, :edit]} - id="template-modal" - on_close={JS.patch(~p"/online-store-templates")} -> - <.live_component - module={MusicLibraryWeb.OnlineStoreTemplateLive.FormComponent} - id={@template.id || :new} - title={@page_title} - action={@live_action} - template={@template} - patch={~p"/online-store-templates"} - /> - + <.structured_modal + :if={@live_action in [:new, :edit]} + id="template-modal" + on_close={JS.patch(~p"/online-store-templates")} + > + <.live_component + module={MusicLibraryWeb.OnlineStoreTemplateLive.FormComponent} + id={@template.id || :new} + title={@page_title} + action={@live_action} + template={@template} + patch={~p"/online-store-templates"} + /> + + diff --git a/lib/music_library_web/live/scrobble_rules_live/index.html.heex b/lib/music_library_web/live/scrobble_rules_live/index.html.heex index b8ecfe0a..87f3cebd 100644 --- a/lib/music_library_web/live/scrobble_rules_live/index.html.heex +++ b/lib/music_library_web/live/scrobble_rules_live/index.html.heex @@ -1,115 +1,117 @@ -
-
-
-

- {gettext("Scrobble Rules")} -

-
-
- <.button_group> - <.button - variant="solid" - size="sm" - patch={~p"/scrobble-rules/new"} - > - <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("New Rule")} - - <.button - variant="solid" - size="sm" - phx-click="apply_all_rules" - > - <.icon name="hero-play" class="icon" /> - {gettext("Apply All")} - - + +
+
+
+

+ {gettext("Scrobble Rules")} +

+
+
+ <.button_group> + <.button + variant="solid" + size="sm" + patch={~p"/scrobble-rules/new"} + > + <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("New Rule")} + + <.button + variant="solid" + size="sm" + phx-click="apply_all_rules" + > + <.icon name="hero-play" class="icon" /> + {gettext("Apply All")} + + +
+
+ +
+
    +
  • +
    + <.type_badge type={scrobble_rule.type} /> +
    +
    +

    + {scrobble_rule.match_value} +

    +

    + {scrobble_rule.target_musicbrainz_id} +

    +

    + {scrobble_rule.description} +

    +
    +
    + + <.status_badge enabled={scrobble_rule.enabled} /> + + + {Calendar.strftime(scrobble_rule.inserted_at, "%Y-%m-%d")} + +
    +
    + <.dropdown id={"actions-#{scrobble_rule.id}"} placement="bottom-end"> + <:toggle> +
    + {gettext("Actions")} + <.icon + name="hero-ellipsis-vertical" + class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" + aria-hidden="true" + data-slot="icon" + /> +
    + + <.dropdown_button phx-click="apply_rule" phx-value-id={scrobble_rule.id}> + {gettext("Apply rule")} + + <.dropdown_button phx-click="toggle_enabled" phx-value-id={scrobble_rule.id}> + {if scrobble_rule.enabled, do: gettext("Disable rule"), else: gettext("Enable rule")} + + <.dropdown_link + id={"actions-#{scrobble_rule.id}-edit"} + patch={~p"/scrobble-rules/#{scrobble_rule}/edit"} + > + {gettext("Edit")} + + <.separator /> + <.dropdown_button + phx-click="delete" + phx-value-id={scrobble_rule.id} + data-confirm={gettext("Are you sure?")} + class={[ + "text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" + ]} + > + {gettext("Delete")} + + +
    +
  • +
-
-
-
    -
  • -
    - <.type_badge type={scrobble_rule.type} /> -
    -
    -

    - {scrobble_rule.match_value} -

    -

    - {scrobble_rule.target_musicbrainz_id} -

    -

    - {scrobble_rule.description} -

    -
    -
    - - <.status_badge enabled={scrobble_rule.enabled} /> - - - {Calendar.strftime(scrobble_rule.inserted_at, "%Y-%m-%d")} - -
    -
    - <.dropdown id={"actions-#{scrobble_rule.id}"} placement="bottom-end"> - <:toggle> -
    - {gettext("Actions")} - <.icon - name="hero-ellipsis-vertical" - class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" - aria-hidden="true" - data-slot="icon" - /> -
    - - <.dropdown_button phx-click="apply_rule" phx-value-id={scrobble_rule.id}> - {gettext("Apply rule")} - - <.dropdown_button phx-click="toggle_enabled" phx-value-id={scrobble_rule.id}> - {if scrobble_rule.enabled, do: gettext("Disable rule"), else: gettext("Enable rule")} - - <.dropdown_link - id={"actions-#{scrobble_rule.id}-edit"} - patch={~p"/scrobble-rules/#{scrobble_rule}/edit"} - > - {gettext("Edit")} - - <.separator /> - <.dropdown_button - phx-click="delete" - phx-value-id={scrobble_rule.id} - data-confirm={gettext("Are you sure?")} - class={[ - "text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" - ]} - > - {gettext("Delete")} - - -
    -
  • -
-
- -<.structured_modal - :if={@live_action in [:new, :edit]} - id="scrobble_rule-modal" - on_close={JS.patch(~p"/scrobble-rules")} -> - <.live_component - module={MusicLibraryWeb.ScrobbleRulesLive.FormComponent} - id={@scrobble_rule.id || :new} - title={@page_title} - action={@live_action} - scrobble_rule={@scrobble_rule} - patch={~p"/scrobble-rules"} - /> - + <.structured_modal + :if={@live_action in [:new, :edit]} + id="scrobble_rule-modal" + on_close={JS.patch(~p"/scrobble-rules")} + > + <.live_component + module={MusicLibraryWeb.ScrobbleRulesLive.FormComponent} + id={@scrobble_rule.id || :new} + title={@page_title} + action={@live_action} + scrobble_rule={@scrobble_rule} + patch={~p"/scrobble-rules"} + /> + + diff --git a/lib/music_library_web/live/scrobbled_tracks_live/index.html.heex b/lib/music_library_web/live/scrobbled_tracks_live/index.html.heex index a9b79c6e..32875223 100644 --- a/lib/music_library_web/live/scrobbled_tracks_live/index.html.heex +++ b/lib/music_library_web/live/scrobbled_tracks_live/index.html.heex @@ -1,160 +1,162 @@ -
-
-
- <.search_form query={@track_list_params.query} /> -
-
+ +
+
+
+ <.search_form query={@track_list_params.query} /> +
+
-
- <.button_group> - <.button - patch={order_path(@track_list_params, :scrobbled_at)} - size="xs" - class={[ - @track_list_params.order == :scrobbled_at && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon - name="hero-clock-solid" - class="icon" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Scrobbled")} - - <.button - patch={order_path(@track_list_params, :title)} - size="xs" - class={[ - @track_list_params.order == :title && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon name="hero-musical-note-solid" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("Title")} - - <.button - patch={order_path(@track_list_params, :artist)} - size="xs" - class={[ - @track_list_params.order == :artist && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon name="hero-user-solid" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("Artist")} - - <.button - patch={order_path(@track_list_params, :album)} - size="xs" - class={[ - @track_list_params.order == :album && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon name="hero-musical-note-solid" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("Album")} - - -
-
- -
-
    - - -
  • -
    -
    - {"Cover track.album.title} - onerror={"this.src = '" <> ~p"/images/cover-not-found.png" <> "';"} +
    + <.button_group> + <.button + patch={order_path(@track_list_params, :scrobbled_at)} + size="xs" + class={[ + @track_list_params.order == :scrobbled_at && "!bg-zinc-100 dark:!bg-zinc-700" + ]} + > + <.icon + name="hero-clock-solid" + class="icon" + aria-hidden="true" + data-slot="icon" /> -
    -
    -
    - <.icon name="hero-musical-note" class="h-6 w-6 text-zinc-400" /> + {gettext("Scrobbled")} + + <.button + patch={order_path(@track_list_params, :title)} + size="xs" + class={[ + @track_list_params.order == :title && "!bg-zinc-100 dark:!bg-zinc-700" + ]} + > + <.icon name="hero-musical-note-solid" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Title")} + + <.button + patch={order_path(@track_list_params, :artist)} + size="xs" + class={[ + @track_list_params.order == :artist && "!bg-zinc-100 dark:!bg-zinc-700" + ]} + > + <.icon name="hero-user-solid" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Artist")} + + <.button + patch={order_path(@track_list_params, :album)} + size="xs" + class={[ + @track_list_params.order == :album && "!bg-zinc-100 dark:!bg-zinc-700" + ]} + > + <.icon name="hero-musical-note-solid" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Album")} + + +
    +
    + +
    +
      + + +
    • +
      +
      + {"Cover track.album.title} + onerror={"this.src = '" <> ~p"/images/cover-not-found.png" <> "';"} + /> +
      +
      +
      + <.icon name="hero-musical-note" class="h-6 w-6 text-zinc-400" /> +
      +
      + +
      +

      + {track.title} +

      +

      + {track.artist.name} +

      +

      + {track.album.title} +

      +

      + {track.scrobbled_at_label} +

      -
      -

      - {track.title} -

      -

      - {track.artist.name} -

      -

      - {track.album.title} -

      -

      - {track.scrobbled_at_label} -

      +
      + <.dropdown id={"actions-#{track.scrobbled_at_uts}"} placement="bottom-end"> + <:toggle> +
      + {gettext("Actions")} + <.icon + name="hero-ellipsis-vertical" + class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" + aria-hidden="true" + data-slot="icon" + /> +
      + + <.dropdown_link patch={~p"/scrobbled-tracks/#{track.scrobbled_at_uts}/edit"}> + {gettext("Edit")} + + <.dropdown_button + phx-click={ + JS.push("delete", value: %{"scrobbled-at-uts": track.scrobbled_at_uts}) + |> JS.hide(to: "##{id}") + } + data-confirm={gettext("Are you sure?")} + class={[ + "text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" + ]} + > + {gettext("Delete")} + +
      -
      +
    • +
    -
    - <.dropdown id={"actions-#{track.scrobbled_at_uts}"} placement="bottom-end"> - <:toggle> -
    - {gettext("Actions")} - <.icon - name="hero-ellipsis-vertical" - class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" - aria-hidden="true" - data-slot="icon" - /> -
    - - <.dropdown_link patch={~p"/scrobbled-tracks/#{track.scrobbled_at_uts}/edit"}> - {gettext("Edit")} - - <.dropdown_button - phx-click={ - JS.push("delete", value: %{"scrobbled-at-uts": track.scrobbled_at_uts}) - |> JS.hide(to: "##{id}") - } - data-confirm={gettext("Are you sure?")} - class={[ - "text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" - ]} - > - {gettext("Delete")} - - -
    -
  • -
+ <.pagination id={:bottom_pagination} pagination_params={@track_list_params} /> +
- <.pagination id={:bottom_pagination} pagination_params={@track_list_params} /> -
- -<.structured_modal - :if={@live_action == :edit} - id="track-modal" - on_close={JS.patch(back_path(@track_list_params))} -> - <.live_component - module={MusicLibraryWeb.ScrobbledTracksLive.FormComponent} - id={@track.scrobbled_at_uts} - action={@live_action} - track={@track} - patch={back_path(@track_list_params)} - /> - + <.structured_modal + :if={@live_action == :edit} + id="track-modal" + on_close={JS.patch(back_path(@track_list_params))} + > + <.live_component + module={MusicLibraryWeb.ScrobbledTracksLive.FormComponent} + id={@track.scrobbled_at_uts} + action={@live_action} + track={@track} + patch={back_path(@track_list_params)} + /> + + diff --git a/lib/music_library_web/live/stats_live/index.html.heex b/lib/music_library_web/live/stats_live/index.html.heex index f7fb1558..e8988ded 100644 --- a/lib/music_library_web/live/stats_live/index.html.heex +++ b/lib/music_library_web/live/stats_live/index.html.heex @@ -1,125 +1,311 @@ -
-

- {gettext("Records")} -

- <%!-- TODO: replace with OSS version --%> -
- <.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} - /> -
-
- -
+

- {gettext("Formats")} + {gettext("Records")}

- <.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} - /> + <%!-- TODO: replace with OSS version --%> +
+ <.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} + /> +
+
+ +
+
+

+ {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} + /> +
-

- {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} - /> +
+ + +
-
-
-
- - -
-
+
+
+

+ {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")} + + -
-
-

- {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.metadata.title} +
    +

    + {album.artist.name} +

    + <.link + :if={album.artist.musicbrainz_id in @artist_ids} + class="font-semibold text-sm block text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" + navigate={~p"/artists/#{album.artist.musicbrainz_id}"} + > + {album.artist.name} + +

    + {album.metadata.title} +

    + +
    +
    - <.tabs_panel name="albums" active={@scrobble_activity_mode == "albums"}> -
      -
    • -
      - -
      -
      - {album.metadata.title} -
      -

      - {album.artist.name} -

      +
      + <.badge :if={album.metadata.musicbrainz_id == ""}> + {gettext("No MB ID")} + <.link - :if={album.artist.musicbrainz_id in @artist_ids} - class="font-semibold text-sm block text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" - navigate={~p"/artists/#{album.artist.musicbrainz_id}"} + :if={ + record_id = + tracked_record?(@collected_releases, album.metadata.musicbrainz_id) + } + navigate={~p"/collection/#{record_id}"} > - {album.artist.name} + <.badge color="success"> + {gettext("Collected")} + -

      - {album.metadata.title} -

      -
      + + <.dropdown + :if={ + album.metadata.musicbrainz_id !== "" and + !tracked_record?( + @collected_releases ++ @wishlisted_releases, + album.metadata.musicbrainz_id + ) + } + id={"actions-#{album.scrobbled_at_uts}-albums"} + placement="bottom-end" + > + <:toggle> + {gettext("Choose which format to import")} + <.icon + name="hero-star" + class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" + aria-hidden="true" + data-slot="icon" + /> + + <.focus_wrap id={"actions-#{album.scrobbled_at_uts}-albums-focus-wrap"}> + <.dropdown_link + :for={format <- Records.Record.formats()} + id={"actions-#{album.scrobbled_at_uts}-#{format}-import"} + phx-click={ + JS.push("import", + value: %{id: album.metadata.musicbrainz_id, format: format}, + page_loading: true + ) + } + > + {format_label(format)} + + + +
      +
      +
    • +
    + + <.tabs_panel name="tracks" active={@scrobble_activity_mode == "tracks"}> +
      +
    • +
      + +
      +
      + {track.title} +
      +

      + {track.artist.name} +

      + <.link + :if={track.artist.musicbrainz_id in @artist_ids} + class="font-semibold text-sm block text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" + navigate={~p"/artists/#{track.artist.musicbrainz_id}"} + > + {track.artist.name} + +

      + {track.title} +

      +

      + {track.album.title} +

      + <.tooltip> <.icon name="hero-information-circle" @@ -130,16 +316,43 @@ <:content>
      -
      {gettext("Album ID:")}
      +
      {gettext("Track ID:")}
      - - {album.metadata.musicbrainz_id || gettext("Unknown")} + + {track.musicbrainz_id || gettext("Unknown")} +
      +
      +
      +
      {gettext("Album ID:")}
      +
      + + {track.album.musicbrainz_id || gettext("Unknown")} + +
      - +
      -
      -
      - <.badge :if={album.metadata.musicbrainz_id == ""}> - {gettext("No MB ID")} - - <.link - :if={ - record_id = - tracked_record?(@collected_releases, album.metadata.musicbrainz_id) - } - navigate={~p"/collection/#{record_id}"} - > - <.badge color="success"> - {gettext("Collected")} +
      + <.badge :if={track.album.musicbrainz_id == ""}> + {gettext("No MB ID")} - - <.link - :if={ - record_id = - tracked_record?(@wishlisted_releases, album.metadata.musicbrainz_id) - } - navigate={~p"/wishlist/#{record_id}"} - > - <.badge color="warning"> - {gettext("Wishlisted")} - - -
      - - <.dropdown - :if={ - album.metadata.musicbrainz_id !== "" and - !tracked_record?( - @collected_releases ++ @wishlisted_releases, - album.metadata.musicbrainz_id - ) - } - id={"actions-#{album.scrobbled_at_uts}-albums"} - placement="bottom-end" - > - <:toggle> - {gettext("Choose which format to import")} - <.icon - name="hero-star" - class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" - aria-hidden="true" - data-slot="icon" - /> - - <.focus_wrap id={"actions-#{album.scrobbled_at_uts}-albums-focus-wrap"}> - <.dropdown_link - :for={format <- Records.Record.formats()} - id={"actions-#{album.scrobbled_at_uts}-#{format}-import"} - phx-click={ - JS.push("import", - value: %{id: album.metadata.musicbrainz_id, format: format}, - page_loading: true - ) - } - > - {format_label(format)} - - - -
      -
      -
    • -
    - - <.tabs_panel name="tracks" active={@scrobble_activity_mode == "tracks"}> -
      -
    • -
      - -
      -
      - {track.title} -
      -

      - {track.artist.name} -

      <.link - :if={track.artist.musicbrainz_id in @artist_ids} - class="font-semibold text-sm block text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" - navigate={~p"/artists/#{track.artist.musicbrainz_id}"} + :if={ + record_id = tracked_record?(@collected_releases, track.album.musicbrainz_id) + } + navigate={~p"/collection/#{record_id}"} > - {track.artist.name} + <.badge color="success">{gettext("Collected")} -

      - {track.title} -

      -

      - {track.album.title} -

      - - <.tooltip> + <.badge color="warning">{gettext("Wishlisted")} + +
      + + <.dropdown + :if={ + track.album.musicbrainz_id !== "" and + !tracked_record?( + @collected_releases ++ @wishlisted_releases, + track.album.musicbrainz_id + ) + } + id={"actions-#{track.scrobbled_at_uts}-tracks"} + placement="bottom-end" + > + <:toggle> + {gettext("Choose which format to import")} <.icon - name="hero-information-circle" + name="hero-star" class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" aria-hidden="true" data-slot="icon" /> - <:content> -
      -
      -
      {gettext("Track ID:")}
      -
      - - {track.musicbrainz_id || gettext("Unknown")} - - -
      -
      -
      -
      {gettext("Album ID:")}
      -
      - - {track.album.musicbrainz_id || gettext("Unknown")} - - -
      -
      -
      -
      {gettext("Artist ID:")}
      -
      - - {track.artist.musicbrainz_id || gettext("Unknown")} - - -
      -
      -
      - - -
      + + <.focus_wrap id={"actions-#{track.scrobbled_at_uts}-tracks-focus-wrap"}> + <.dropdown_link + :for={format <- Records.Record.formats()} + id={"actions-#{track.scrobbled_at_uts}-#{format}-import"} + phx-click={ + JS.push("import", + value: %{id: track.album.musicbrainz_id, format: format}, + page_loading: true + ) + } + > + {format_label(format)} + + +
      - -
      - <.badge :if={track.album.musicbrainz_id == ""}> - {gettext("No MB ID")} - - <.link - :if={ - record_id = tracked_record?(@collected_releases, track.album.musicbrainz_id) - } - navigate={~p"/collection/#{record_id}"} - > - <.badge color="success">{gettext("Collected")} - - <.link - :if={ - record_id = tracked_record?(@wishlisted_releases, track.album.musicbrainz_id) - } - navigate={~p"/wishlist/#{record_id}"} - > - <.badge color="warning">{gettext("Wishlisted")} - -
      - - <.dropdown - :if={ - track.album.musicbrainz_id !== "" and - !tracked_record?( - @collected_releases ++ @wishlisted_releases, - track.album.musicbrainz_id - ) - } - id={"actions-#{track.scrobbled_at_uts}-tracks"} - placement="bottom-end" - > - <:toggle> - {gettext("Choose which format to import")} - <.icon - name="hero-star" - class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" - aria-hidden="true" - data-slot="icon" - /> - - <.focus_wrap id={"actions-#{track.scrobbled_at_uts}-tracks-focus-wrap"}> - <.dropdown_link - :for={format <- Records.Record.formats()} - id={"actions-#{track.scrobbled_at_uts}-#{format}-import"} - phx-click={ - JS.push("import", - value: %{id: track.album.musicbrainz_id, format: format}, - page_loading: true - ) - } - > - {format_label(format)} - - -
      -
    -
  • -
- - -
+ + + + +
-
-
-
+
+
+
+

+ {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={@streams.records_on_this_day} + record_show_path={fn record -> ~p"/collection/#{record}" end} + /> +
+
+

- {gettext("On This day")} + {gettext("Top %{n} Artists", %{n: length(@records_by_artist)})}

- <.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 - - - - +
+ <.vertical_bar_chart + data={@records_by_artist} + width={600} + height={26 * length(@records_by_artist)} + color_class="fill-red-500" + label_fn={fn datum -> datum.name end} + value_fn={fn datum -> datum.count end} + label_click={ + fn datum -> + JS.navigate(~p"/artists/#{datum.id}") + end + } + class="w-full" + /> +
-
- <.records_on_this_day - current_date={@current_date} - records={@streams.records_on_this_day} - record_show_path={fn record -> ~p"/collection/#{record}" end} - /> -
-
-
-

- {gettext("Top %{n} Artists", %{n: length(@records_by_artist)})} -

-
- <.vertical_bar_chart - data={@records_by_artist} - width={600} - height={26 * length(@records_by_artist)} - color_class="fill-red-500" - label_fn={fn datum -> datum.name end} - value_fn={fn datum -> datum.count end} - label_click={ - fn datum -> - JS.navigate(~p"/artists/#{datum.id}") - end - } - class="w-full" - /> -
-
-
-

- {gettext("Top %{n} Genres", %{n: length(@records_by_genre)})} -

-
- <.vertical_bar_chart - data={@records_by_genre} - width={600} - height={26 * length(@records_by_genre)} - color_class="fill-zinc-500" - label_fn={fn {genre, _count} -> genre end} - value_fn={fn {_genre, count} -> count end} - label_click={ - fn {genre, _count} -> JS.navigate(~p"/collection?#{%{query: ~s(genre:"#{genre}")}}") end - } - class="w-full" - /> +
+

+ {gettext("Top %{n} Genres", %{n: length(@records_by_genre)})} +

+
+ <.vertical_bar_chart + data={@records_by_genre} + width={600} + height={26 * length(@records_by_genre)} + color_class="fill-zinc-500" + label_fn={fn {genre, _count} -> genre end} + value_fn={fn {_genre, count} -> count end} + label_click={ + fn {genre, _count} -> + JS.navigate(~p"/collection?#{%{query: ~s(genre:"#{genre}")}}") + end + } + class="w-full" + /> +
-
+ diff --git a/lib/music_library_web/live/wishlist_live/index.html.heex b/lib/music_library_web/live/wishlist_live/index.html.heex index e992d6f8..674fd941 100644 --- a/lib/music_library_web/live/wishlist_live/index.html.heex +++ b/lib/music_library_web/live/wishlist_live/index.html.heex @@ -1,83 +1,85 @@ -
-
-
- <.search_form query={@record_list_params.query} /> - <.button - variant="solid" - size="sm" - patch={~p"/wishlist/import"} - > - <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("Add")} - + +
+
+
+ <.search_form query={@record_list_params.query} /> + <.button + variant="solid" + size="sm" + patch={~p"/wishlist/import"} + > + <.icon name="hero-plus" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Add")} + +
+
+ +
+ <.button_group> + <.button + patch={order_path(@record_list_params, :insertion)} + size="sm" + class={[ + "rounded-l-md rounded-r-none", + @record_list_params.order == :insertion && "!bg-zinc-100 dark:!bg-zinc-700" + ]} + > + <.icon name="hero-star" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("Insertion")} + + <.button + patch={order_path(@record_list_params, :alphabetical)} + size="sm" + class={[ + "-ml-px rounded-r-md rounded-l-none", + @record_list_params.order == :alphabetical && "!bg-zinc-100 dark:!bg-zinc-700" + ]} + > + <.icon name="hero-user-solid" class="icon" aria-hidden="true" data-slot="icon" /> + {gettext("A->Z")} + +
-
- -
- <.button_group> - <.button - patch={order_path(@record_list_params, :insertion)} - size="sm" - class={[ - "rounded-l-md rounded-r-none", - @record_list_params.order == :insertion && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon name="hero-star" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("Insertion")} - - <.button - patch={order_path(@record_list_params, :alphabetical)} - size="sm" - class={[ - "-ml-px rounded-r-md rounded-l-none", - @record_list_params.order == :alphabetical && "!bg-zinc-100 dark:!bg-zinc-700" - ]} - > - <.icon name="hero-user-solid" class="icon" aria-hidden="true" data-slot="icon" /> - {gettext("A->Z")} - -
-
-<.record_list - current_date={@current_date} - records={@streams.records} - record_show_path={fn record -> ~p"/wishlist/#{record}" end} - record_edit_path={fn record -> ~p"/wishlist/#{record}/edit" end} -/> - -<.structured_modal - :if={@live_action == :edit} - id="record-modal" - on_close={JS.patch(back_path(@record_list_params))} -> - <.live_component - module={MusicLibraryWeb.RecordFormComponent} - id={@record.id} - action={@live_action} - show_purchased_at={false} - record={@record} - patch={back_path(@record_list_params)} + <.record_list + current_date={@current_date} + records={@streams.records} + record_show_path={fn record -> ~p"/wishlist/#{record}" end} + record_edit_path={fn record -> ~p"/wishlist/#{record}/edit" end} /> - -<.structured_modal - :if={@live_action == :import} - id="record-modal" - on_close={JS.patch(back_path(@record_list_params))} -> - <.live_component - module={MusicLibraryWeb.AddRecordComponent} - id={:search} - title={@page_title} - action={@live_action} - record={@record} - patch={back_path(@record_list_params)} - initial_query="" - icon_name="hero-plus" - /> - + <.structured_modal + :if={@live_action == :edit} + id="record-modal" + on_close={JS.patch(back_path(@record_list_params))} + > + <.live_component + module={MusicLibraryWeb.RecordFormComponent} + id={@record.id} + action={@live_action} + show_purchased_at={false} + record={@record} + patch={back_path(@record_list_params)} + /> + -<.pagination id={:bottom_pagination} pagination_params={@record_list_params} /> + <.structured_modal + :if={@live_action == :import} + id="record-modal" + on_close={JS.patch(back_path(@record_list_params))} + > + <.live_component + module={MusicLibraryWeb.AddRecordComponent} + id={:search} + title={@page_title} + action={@live_action} + record={@record} + patch={back_path(@record_list_params)} + initial_query="" + icon_name="hero-plus" + /> + + + <.pagination id={:bottom_pagination} pagination_params={@record_list_params} /> + diff --git a/lib/music_library_web/live/wishlist_live/show.html.heex b/lib/music_library_web/live/wishlist_live/show.html.heex index 25409bf7..792dea62 100644 --- a/lib/music_library_web/live/wishlist_live/show.html.heex +++ b/lib/music_library_web/live/wishlist_live/show.html.heex @@ -1,317 +1,321 @@ -
-
- <.record_cover - record={@record} - class="w-full rounded-lg drop-shadow-sm" - /> -
- -
-
-
-

- <.artist_links joinphrase_class="text-sm" artists={@record.artists} /> -

-

- {@record.title} -

-

- <.record_colors record={@record} /> - {Records.Record.format_release_date(@record.release_date)} - - ({gettext("Unreleased")}) - - · {format_label(@record.format)} · {type_label(@record.type)} -

-
- <.dropdown id={"actions-#{@record.id}"} placement="bottom-end"> - <:toggle class="h-5 block"> - {gettext("Actions")} - <.icon - name="hero-ellipsis-vertical" - class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" - aria-hidden="true" - data-slot="icon" - /> - - <.focus_wrap id={"actions-#{@record.id}-focus-wrap"}> - <.dropdown_link - id={"actions-#{@record.id}-edit"} - patch={~p"/wishlist/#{@record}/show/edit"} - > - <.icon - name="hero-pencil-square" - class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Edit")} - - - <.dropdown_link - id={"actions-#{@record.id}-refresh-cover"} - phx-click={JS.push("refresh_cover", value: %{id: @record.id})} - > - <.icon - name="hero-photo" - class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Refresh cover")} - - - <.dropdown_link - id={"actions-#{@record.id}-refresh-mb-data"} - phx-click={JS.push("refresh_musicbrainz_data", value: %{id: @record.id})} - > - <.icon - name="hero-arrow-path" - class="h-4 w-4 mr-1 phx-click-loading:animate-spin" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Refresh MB data")} - - - <.dropdown_link - id={"actions-#{@record.id}-populate-genres"} - phx-click={JS.push("populate_genres", value: %{id: @record.id})} - > - <.icon - name="hero-sparkles" - class="h-4 w-4 mr-1 phx-click-loading:animate-shake" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Populate genres")} - - - <.dropdown_link - :if={!@record.purchased_at} - id={"actions-#{@record.id}-purchase"} - phx-click={ - JS.dispatch("music_library:confetti") - |> JS.push("add-to-collection", value: %{id: @record.id}) - } - > - <.icon - name="hero-banknotes" - class="h-4 w-4 mr-1 phx-click-loading:animate-shake" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Purchased")} - - - <.dropdown_link - id={"actions-#{@record.id}-extract-colors-fast"} - phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :fast})} - > - <.icon - name="hero-paint-brush" - class="h-4 w-4 mr-1 phx-click-loading:animate-shake" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Extract colors (fast)")} - - - <.dropdown_link - id={"actions-#{@record.id}-extract-colors-slow"} - phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :slow})} - > - <.icon - name="hero-paint-brush" - class="h-4 w-4 mr-1 phx-click-loading:animate-shake" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Extract colors (slow)")} - - - <.dropdown_separator /> - <.dropdown_link - id={"actions-#{@record.id}-delete"} - phx-click={JS.push("delete", value: %{id: @record.id})} - data-confirm={gettext("Are you sure?")} - class="text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" - > - <.icon - name="hero-trash" - class="h-4 w-4 mr-1 phx-click-loading:animate-spin" - aria-hidden="true" - data-slot="icon" - /> - {gettext("Delete")} - - - + +
+
+ <.record_cover + record={@record} + class="w-full rounded-lg drop-shadow-sm" + />
-
- <%!-- TODO: replace with OSS version --%> -
-
-
- {gettext("ID")} -
-
- {@record.id} - -
-
-
-
- {gettext("Genres")} -
-
- <.link - :for={genre <- @record.genres} - class="mr-2 text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" - patch={~p"/wishlist?#{%{query: ~s(genre:"#{genre}")}}"} - > - {genre} - -
-
-
-
- {gettext("MusicBrainz ID")} -
-
- - {@record.musicbrainz_id} - - -
-
-
-
- {gettext("Published releases")} -
-
- {Records.Record.release_count(@record)} -
-
-
-
- {gettext("Wishlisted release")} -
-
- - {gettext("No release selected")} +
+
+
+

+ <.artist_links joinphrase_class="text-sm" artists={@record.artists} /> +

+

+ {@record.title} +

+

+ <.record_colors record={@record} /> + {Records.Record.format_release_date(@record.release_date)} + + ({gettext("Unreleased")}) - - <.release_summary - :if={@record.selected_release_id} - release={Records.Record.selected_release(@record)} + · {format_label(@record.format)} · {type_label(@record.type)} +

+
+ <.dropdown id={"actions-#{@record.id}"} placement="bottom-end"> + <:toggle class="h-5 block"> + {gettext("Actions")} + <.icon + name="hero-ellipsis-vertical" + class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" + aria-hidden="true" + data-slot="icon" /> -
-
-
0} - class="py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" - > -
- {gettext("Includes")} -
-
-
    -
  • - {included_release_group.artists} - {included_release_group.title} -
  • -
-
-
-
-
- {gettext("Inserted at")} -
-
- {Records.Record.format_as_date(@record.inserted_at)} -
-
-
-
- {gettext("Updated at")} -
-
- {Records.Record.format_as_date(@record.updated_at)} -
-
-
+ + <.focus_wrap id={"actions-#{@record.id}-focus-wrap"}> + <.dropdown_link + id={"actions-#{@record.id}-edit"} + patch={~p"/wishlist/#{@record}/show/edit"} + > + <.icon + name="hero-pencil-square" + class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Edit")} + + + <.dropdown_link + id={"actions-#{@record.id}-refresh-cover"} + phx-click={JS.push("refresh_cover", value: %{id: @record.id})} + > + <.icon + name="hero-photo" + class="h-4 w-4 mr-1 phx-click-loading:animate-bounce" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Refresh cover")} + + + <.dropdown_link + id={"actions-#{@record.id}-refresh-mb-data"} + phx-click={JS.push("refresh_musicbrainz_data", value: %{id: @record.id})} + > + <.icon + name="hero-arrow-path" + class="h-4 w-4 mr-1 phx-click-loading:animate-spin" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Refresh MB data")} + + + <.dropdown_link + id={"actions-#{@record.id}-populate-genres"} + phx-click={JS.push("populate_genres", value: %{id: @record.id})} + > + <.icon + name="hero-sparkles" + class="h-4 w-4 mr-1 phx-click-loading:animate-shake" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Populate genres")} + + + <.dropdown_link + :if={!@record.purchased_at} + id={"actions-#{@record.id}-purchase"} + phx-click={ + JS.dispatch("music_library:confetti") + |> JS.push("add-to-collection", value: %{id: @record.id}) + } + > + <.icon + name="hero-banknotes" + class="h-4 w-4 mr-1 phx-click-loading:animate-shake" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Purchased")} + + + <.dropdown_link + id={"actions-#{@record.id}-extract-colors-fast"} + phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :fast})} + > + <.icon + name="hero-paint-brush" + class="h-4 w-4 mr-1 phx-click-loading:animate-shake" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Extract colors (fast)")} + + + <.dropdown_link + id={"actions-#{@record.id}-extract-colors-slow"} + phx-click={JS.push("extract_colors", value: %{id: @record.id, method: :slow})} + > + <.icon + name="hero-paint-brush" + class="h-4 w-4 mr-1 phx-click-loading:animate-shake" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Extract colors (slow)")} + + + <.dropdown_separator /> + <.dropdown_link + id={"actions-#{@record.id}-delete"} + phx-click={JS.push("delete", value: %{id: @record.id})} + data-confirm={gettext("Are you sure?")} + class="text-red-900! hover:bg-red-50! dark:text-red-500! dark:hover:bg-red-900/30! dark:hover:text-red-600!" + > + <.icon + name="hero-trash" + class="h-4 w-4 mr-1 phx-click-loading:animate-spin" + aria-hidden="true" + data-slot="icon" + /> + {gettext("Delete")} + + + +
+ +
+ <%!-- TODO: replace with OSS version --%> +
+
+
+ {gettext("ID")} +
+
+ {@record.id} + +
+
+
+
+ {gettext("Genres")} +
+
+ <.link + :for={genre <- @record.genres} + class="mr-2 text-zinc-700 hover:text-zinc-500 dark:text-zinc-400 dark:hover:text-zinc-300" + patch={~p"/wishlist?#{%{query: ~s(genre:"#{genre}")}}"} + > + {genre} + +
+
+
+
+ {gettext("MusicBrainz ID")} +
+
+ + {@record.musicbrainz_id} + + +
+
+
+
+ {gettext("Published releases")} +
+
+ {Records.Record.release_count(@record)} +
+
+
+
+ {gettext("Wishlisted release")} +
+
+ + {gettext("No release selected")} + + + <.release_summary + :if={@record.selected_release_id} + release={Records.Record.selected_release(@record)} + /> +
+
+
0} + class="py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" + > +
+ {gettext("Includes")} +
+
+
    +
  • + {included_release_group.artists} - {included_release_group.title} +
  • +
+
+
+
+
+ {gettext("Inserted at")} +
+
+ {Records.Record.format_as_date(@record.inserted_at)} +
+
+
+
+ {gettext("Updated at")} +
+
+ {Records.Record.format_as_date(@record.updated_at)} +
+
+
+
-
-
-
- - {gettext("Check Online Stores")} - -
- <.button - :for={template <- @online_store_templates} - href={OnlineStoreTemplates.generate_url(template, @record)} - target="_blank" - rel="noopener noreferrer" - variant="ghost" - size="sm" - class="ml-2" - > - {template.name} - - {template.name} - - -
-
-
+
+
+ + {gettext("Check Online Stores")} + +
+ <.button + :for={template <- @online_store_templates} + href={OnlineStoreTemplates.generate_url(template, @record)} + target="_blank" + rel="noopener noreferrer" + variant="ghost" + size="sm" + class="ml-2" + > + {template.name} + + {template.name} + + +
+
+
-<.json_viewer title={gettext("MusicBrainz data")} data={@record.musicbrainz_data} /> + <.json_viewer title={gettext("MusicBrainz data")} data={@record.musicbrainz_data} /> -<.structured_modal - :if={@live_action == :edit} - id="record-modal" - on_close={JS.patch(~p"/wishlist/#{@record}")} -> - <.live_component - module={MusicLibraryWeb.RecordFormComponent} - id={@record.id} - action={@live_action} - show_purchased_at={false} - record={@record} - patch={~p"/wishlist/#{@record}"} - /> - + <.structured_modal + :if={@live_action == :edit} + id="record-modal" + on_close={JS.patch(~p"/wishlist/#{@record}")} + > + <.live_component + module={MusicLibraryWeb.RecordFormComponent} + id={@record.id} + action={@live_action} + show_purchased_at={false} + record={@record} + patch={~p"/wishlist/#{@record}"} + /> + +