Fix UI inconsistencies across templates

- Replace .separator with .dropdown_separator in 4 dropdown menus
- Change gray-* to zinc-* color classes in online store templates
- Wrap hardcoded page titles in gettext() in online store templates
- Add consistent dark:text-zinc-200 to maintenance h3 subsections
- Add text-zinc-900 dark:text-zinc-200 to scrobble section headers
- Fix heading hierarchy (h1/h2 → h2/h3) in record set items
- Align artist form modal header to text-lg font-semibold
- Use size="xs" prop instead of class override on format badge
- Add external link icon to wishlist online store buttons
This commit is contained in:
Claudio Ortolina
2026-03-16 11:37:29 +00:00
parent 028f111300
commit 654b172ddb
13 changed files with 59 additions and 30 deletions
@@ -407,7 +407,7 @@ defmodule MusicLibraryWeb.RecordComponents do
defp format_badge(assigns) do defp format_badge(assigns) do
~H""" ~H"""
<.badge class="text-xs md:text-sm"> <.badge size="xs">
{@release |> ReleaseSearchResult.format() |> format_label()} {@release |> ReleaseSearchResult.format() |> format_label()}
</.badge> </.badge>
""" """
@@ -20,7 +20,7 @@ defmodule MusicLibraryWeb.ArtistLive.Form do
~H""" ~H"""
<div class="w-full"> <div class="w-full">
<header> <header>
<h1 class="text-base font-medium leading-6 text-zinc-700 dark:text-zinc-300"> <h1 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
{@artist.name} {@artist.name}
</h1> </h1>
</header> </header>
@@ -21,7 +21,7 @@ defmodule MusicLibraryWeb.MaintenanceLive.Index do
<h1 class="mt-2 text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold"> <h1 class="mt-2 text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
{gettext("Maintenance")} {gettext("Maintenance")}
</h1> </h1>
<h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-white"> <h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-zinc-200">
{gettext("Records")} {gettext("Records")}
</h3> </h3>
<p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400"> <p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400">
@@ -61,7 +61,7 @@ defmodule MusicLibraryWeb.MaintenanceLive.Index do
</.button_group> </.button_group>
</li> </li>
</ul> </ul>
<h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-white"> <h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-zinc-200">
{gettext("Artists")} {gettext("Artists")}
</h3> </h3>
<p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400"> <p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400">
@@ -127,7 +127,7 @@ defmodule MusicLibraryWeb.MaintenanceLive.Index do
</.button_group> </.button_group>
</li> </li>
</ul> </ul>
<h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-white"> <h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-zinc-200">
{gettext("Database")} {gettext("Database")}
</h3> </h3>
<p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400"> <p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400">
@@ -156,7 +156,7 @@ defmodule MusicLibraryWeb.MaintenanceLive.Index do
</.button_group> </.button_group>
</li> </li>
</ul> </ul>
<h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-white"> <h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-zinc-200">
{gettext("Assets")} {gettext("Assets")}
</h3> </h3>
<p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400"> <p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400">
@@ -187,7 +187,7 @@ defmodule MusicLibraryWeb.MaintenanceLive.Index do
</.button_group> </.button_group>
</li> </li>
</ul> </ul>
<h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-white"> <h3 class="mt-4 text-base font-semibold text-zinc-900 dark:text-zinc-200">
{gettext("Emails")} {gettext("Emails")}
</h3> </h3>
<p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400"> <p class="mt-2 max-w-4xl text-sm text-zinc-500 dark:text-zinc-400">
@@ -27,7 +27,7 @@ defmodule MusicLibraryWeb.OnlineStoreTemplateLive.Index do
<div class="mt-6 space-y-4"> <div class="mt-6 space-y-4">
<ul <ul
role="list" role="list"
class="divide-y divide-gray-200 dark:divide-gray-800" class="divide-y divide-zinc-100 dark:divide-zinc-300/20"
phx-update="stream" phx-update="stream"
id="templates" id="templates"
> >
@@ -42,7 +42,7 @@ defmodule MusicLibraryWeb.OnlineStoreTemplateLive.Index do
src={favicon_url(template.url_template)} src={favicon_url(template.url_template)}
alt={template.name} alt={template.name}
/> />
<p class="text-sm font-semibold text-gray-900 dark:text-white"> <p class="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
{template.name} {template.name}
</p> </p>
<.badge :if={template.enabled} color="success"> <.badge :if={template.enabled} color="success">
@@ -52,10 +52,10 @@ defmodule MusicLibraryWeb.OnlineStoreTemplateLive.Index do
{gettext("Disabled")} {gettext("Disabled")}
</.badge> </.badge>
</div> </div>
<div class="mt-1 flex items-center gap-x-2 text-xs text-gray-500 dark:text-gray-400"> <div class="mt-1 flex items-center gap-x-2 text-xs text-zinc-500 dark:text-zinc-400">
<p class="truncate font-mono">{template.url_template}</p> <p class="truncate font-mono">{template.url_template}</p>
</div> </div>
<p :if={template.description} class="mt-1 text-xs text-gray-500 dark:text-gray-400"> <p :if={template.description} class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">
{template.description} {template.description}
</p> </p>
</div> </div>
@@ -83,7 +83,7 @@ defmodule MusicLibraryWeb.OnlineStoreTemplateLive.Index do
> >
{gettext("Edit")} {gettext("Edit")}
</.dropdown_link> </.dropdown_link>
<.separator /> <.dropdown_separator />
<.dropdown_button <.dropdown_button
phx-click="delete" phx-click="delete"
phx-value-id={template.id} phx-value-id={template.id}
@@ -133,19 +133,19 @@ defmodule MusicLibraryWeb.OnlineStoreTemplateLive.Index do
defp apply_action(socket, :edit, %{"id" => id}) do defp apply_action(socket, :edit, %{"id" => id}) do
socket socket
|> assign(:page_title, "Edit Online Store Template") |> assign(:page_title, gettext("Edit Online Store Template"))
|> assign(:template, OnlineStoreTemplates.get_template!(id)) |> assign(:template, OnlineStoreTemplates.get_template!(id))
end end
defp apply_action(socket, :new, _params) do defp apply_action(socket, :new, _params) do
socket socket
|> assign(:page_title, "New Online Store Template") |> assign(:page_title, gettext("New Online Store Template"))
|> assign(:template, %OnlineStoreTemplate{}) |> assign(:template, %OnlineStoreTemplate{})
end end
defp apply_action(socket, :index, _params) do defp apply_action(socket, :index, _params) do
socket socket
|> assign(:page_title, "Online Store Templates") |> assign(:page_title, gettext("Online Store Templates"))
|> assign(:template, nil) |> assign(:template, nil)
end end
@@ -311,7 +311,7 @@ defmodule MusicLibraryWeb.RecordSetLive.Index do
> >
{gettext("Edit")} {gettext("Edit")}
</.dropdown_link> </.dropdown_link>
<.separator /> <.dropdown_separator />
<.dropdown_button <.dropdown_button
phx-click="delete_set" phx-click="delete_set"
phx-value-id={@record_set.id} phx-value-id={@record_set.id}
@@ -387,12 +387,12 @@ defmodule MusicLibraryWeb.RecordSetLive.Index do
aria-hidden="true" aria-hidden="true"
/> />
</button> </button>
<h1 class="mt-1 text-sm sm:text-sm leading-6 text-zinc-700"> <h2 class="mt-1 text-sm leading-6 text-zinc-700">
<.artist_links joinphrase_class="text-sm" artists={item.record.artists} /> <.artist_links joinphrase_class="text-sm" artists={item.record.artists} />
</h1>
<h2 class="flex font-semibold text-sm sm:text-sm leading-5 text-zinc-700 dark:text-zinc-300 text-wrap">
{item.record.title}
</h2> </h2>
<h3 class="flex font-semibold text-sm leading-5 text-zinc-700 dark:text-zinc-300 text-wrap">
{item.record.title}
</h3>
<p class="pointer-events-none block text-sm font-medium text-zinc-500"> <p class="pointer-events-none block text-sm font-medium text-zinc-500">
{format_label(item.record.format)} · {type_label(item.record.type)} {format_label(item.record.format)} · {type_label(item.record.type)}
</p> </p>
@@ -41,7 +41,7 @@ defmodule MusicLibraryWeb.RecordSetLive.Show do
> >
{gettext("Edit")} {gettext("Edit")}
</.dropdown_link> </.dropdown_link>
<.separator /> <.dropdown_separator />
<.dropdown_button <.dropdown_button
phx-click="delete_set" phx-click="delete_set"
data-confirm={gettext("Are you sure?")} data-confirm={gettext("Are you sure?")}
@@ -122,12 +122,12 @@ defmodule MusicLibraryWeb.RecordSetLive.Show do
aria-hidden="true" aria-hidden="true"
/> />
</button> </button>
<h1 class="mt-1 text-sm sm:text-sm leading-6 text-zinc-700"> <h2 class="mt-1 text-sm leading-6 text-zinc-700">
<.artist_links joinphrase_class="text-sm" artists={item.record.artists} /> <.artist_links joinphrase_class="text-sm" artists={item.record.artists} />
</h1>
<h2 class="flex font-semibold text-sm sm:text-sm leading-5 text-zinc-700 dark:text-zinc-300 text-wrap">
{item.record.title}
</h2> </h2>
<h3 class="flex font-semibold text-sm leading-5 text-zinc-700 dark:text-zinc-300 text-wrap">
{item.record.title}
</h3>
<p class="pointer-events-none block text-sm font-medium text-zinc-500"> <p class="pointer-events-none block text-sm font-medium text-zinc-500">
{format_label(item.record.format)} · {type_label(item.record.type)} {format_label(item.record.format)} · {type_label(item.record.type)}
</p> </p>
@@ -22,7 +22,9 @@ defmodule MusicLibraryWeb.ScrobbleLive.Index do
</header> </header>
<%= if @search_results != [] && @selected_release_group == nil do %> <%= if @search_results != [] && @selected_release_group == nil do %>
<div class="space-y-3"> <div class="space-y-3">
<h3 class="text-lg font-semibold">{gettext("Release Groups")}</h3> <h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-200">
{gettext("Release Groups")}
</h3>
<ul class={[ <ul class={[
"mt-5 divide-y divide-zinc-100 dark:divide-slate-300/30", "mt-5 divide-y divide-zinc-100 dark:divide-slate-300/30",
"max-h-125 overflow-y-auto" "max-h-125 overflow-y-auto"
@@ -74,7 +74,9 @@ defmodule MusicLibraryWeb.ScrobbleLive.Show do
<div :if={@release.media != []} class="mt-6 space-y-4"> <div :if={@release.media != []} class="mt-6 space-y-4">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<h3 class="text-lg font-semibold">{gettext("Tracks")}</h3> <h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-200">
{gettext("Tracks")}
</h3>
<.button <.button
:if={@can_scrobble} :if={@can_scrobble}
@@ -134,7 +134,7 @@ defmodule MusicLibraryWeb.ScrobbleRulesLive.Index do
> >
{gettext("Edit")} {gettext("Edit")}
</.dropdown_link> </.dropdown_link>
<.separator /> <.dropdown_separator />
<.dropdown_button <.dropdown_button
phx-click="delete" phx-click="delete"
phx-value-id={scrobble_rule.id} phx-value-id={scrobble_rule.id}
@@ -234,6 +234,11 @@ defmodule MusicLibraryWeb.WishlistLive.Show do
<span class="text-sm font-medium text-zinc-900 dark:text-white"> <span class="text-sm font-medium text-zinc-900 dark:text-white">
{template.name} {template.name}
</span> </span>
<.icon
name="hero-arrow-top-right-on-square"
class="h-3.5 w-3.5 text-zinc-400"
aria-hidden="true"
/>
</.button> </.button>
</div> </div>
</details> </details>
+10
View File
@@ -2293,3 +2293,13 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Timestamp" msgid "Timestamp"
msgstr "" msgstr ""
#: lib/music_library_web/live/online_store_template_live/index.ex
#, elixir-autogen, elixir-format
msgid "Edit Online Store Template"
msgstr ""
#: lib/music_library_web/live/online_store_template_live/index.ex
#, elixir-autogen, elixir-format
msgid "New Online Store Template"
msgstr ""
+10
View File
@@ -2293,3 +2293,13 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
msgid "Timestamp" msgid "Timestamp"
msgstr "" msgstr ""
#: lib/music_library_web/live/online_store_template_live/index.ex
#, elixir-autogen, elixir-format
msgid "Edit Online Store Template"
msgstr ""
#: lib/music_library_web/live/online_store_template_live/index.ex
#, elixir-autogen, elixir-format
msgid "New Online Store Template"
msgstr ""
@@ -28,8 +28,8 @@ defmodule MusicLibraryWeb.RecordSetLive.ShowTest do
conn conn
|> visit(~p"/record-sets/#{set}") |> visit(~p"/record-sets/#{set}")
|> assert_has("h2", escape(r1.title)) |> assert_has("h3", escape(r1.title))
|> assert_has("h2", escape(r2.title)) |> assert_has("h3", escape(r2.title))
end end
test "shows add record tile when set has no records", %{conn: conn} do test "shows add record tile when set has no records", %{conn: conn} do