Standardize all icon-based actions to buttons

Use a combination of ghost and soft, with button groups where
appropriate. Also remove unnecessary negative margins, and pad around
for ease of use on mobile.
This commit is contained in:
Claudio Ortolina
2025-10-17 20:02:04 +01:00
parent 8d01980c87
commit f4727bdcbd
14 changed files with 279 additions and 255 deletions
@@ -95,7 +95,7 @@ defmodule MusicLibraryWeb.Components.AddRecord do
<span class="sr-only">{gettext("Choose which format to import")}</span> <span class="sr-only">{gettext("Choose which format to import")}</span>
<.icon <.icon
name="hero-plus" name="hero-plus"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -46,17 +46,20 @@
</.nav_link> </.nav_link>
</div> </div>
</div> </div>
<div class="flex space-x-2 md:space-x-4 items-center"> <div class="flex items-center">
<.button_group>
<.universal_search_trigger /> <.universal_search_trigger />
<.dropdown placement="bottom-end"> <.dropdown placement="bottom-end">
<:toggle> <:toggle>
<.button variant="soft">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</.button>
</:toggle> </:toggle>
<.dropdown_link href={~p"/scrobbled-tracks"}> <.dropdown_link href={~p"/scrobbled-tracks"}>
<.icon <.icon
@@ -96,7 +99,12 @@
</.dropdown_link> </.dropdown_link>
<.dropdown_separator /> <.dropdown_separator />
<.dropdown_link href={~p"/dev/dashboard"}> <.dropdown_link href={~p"/dev/dashboard"}>
<.icon name="hero-chart-bar" class="h-4 w-4 mr-2" aria-hidden="true" data-slot="icon" /> <.icon
name="hero-chart-bar"
class="h-4 w-4 mr-2"
aria-hidden="true"
data-slot="icon"
/>
{gettext("Live Dashboard")} {gettext("Live Dashboard")}
</.dropdown_link> </.dropdown_link>
<.dropdown_link href={~p"/dev/oban"}> <.dropdown_link href={~p"/dev/oban"}>
@@ -114,6 +122,7 @@
{gettext("Logout")} {gettext("Logout")}
</.dropdown_link> </.dropdown_link>
</.dropdown> </.dropdown>
</.button_group>
</div> </div>
</div> </div>
</div> </div>
@@ -102,7 +102,7 @@ defmodule MusicLibraryWeb.RecordComponents do
</span> </span>
<.icon <.icon
name="hero-banknotes" name="hero-banknotes"
class="-mt-1 h-4 w-4" class="h-4 w-4"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -113,7 +113,7 @@ defmodule MusicLibraryWeb.RecordComponents do
<span class="sr-only"> <span class="sr-only">
{gettext("Wishlisted on")} {gettext("Wishlisted on")}
</span> </span>
<.icon name="hero-star" class="-mt-1 h-4 w-4" aria-hidden="true" data-slot="icon" /> <.icon name="hero-star" class="h-4 w-4" aria-hidden="true" data-slot="icon" />
{Records.Record.format_as_date(record.inserted_at)} {Records.Record.format_as_date(record.inserted_at)}
</span> </span>
</p> </p>
@@ -128,31 +128,32 @@ defmodule MusicLibraryWeb.RecordComponents do
<span class="sr-only"> <span class="sr-only">
{gettext("Purchased on")} {gettext("Purchased on")}
</span> </span>
<.icon name="hero-banknotes" class="-mt-1 h-4 w-4" aria-hidden="true" data-slot="icon" /> <.icon name="hero-banknotes" class="h-4 w-4" aria-hidden="true" data-slot="icon" />
{Records.Record.format_as_date(record.purchased_at)} {Records.Record.format_as_date(record.purchased_at)}
</p> </p>
<p :if={!record.purchased_at} class="text-xs leading-6 text-zinc-900 dark:text-zinc-300"> <p :if={!record.purchased_at} class="text-xs leading-6 text-zinc-900 dark:text-zinc-300">
<span class="sr-only"> <span class="sr-only">
{gettext("Wishlisted on")} {gettext("Wishlisted on")}
</span> </span>
<.icon name="hero-star" class="-mt-1 h-4 w-4" aria-hidden="true" data-slot="icon" /> <.icon name="hero-star" class="h-4 w-4" aria-hidden="true" data-slot="icon" />
{Records.Record.format_as_date(record.inserted_at)} {Records.Record.format_as_date(record.inserted_at)}
</p> </p>
</div> </div>
<.dropdown id={"actions-#{record.id}"} placement="bottom-end"> <.dropdown id={"actions-#{record.id}"} placement="bottom-end">
<:toggle> <:toggle>
<div <.button
variant="ghost"
phx-click={JS.toggle_class("pointer-events-none", to: "#records > li")} phx-click={JS.toggle_class("pointer-events-none", to: "#records > li")}
phx-click-away={JS.remove_class("pointer-events-none", to: "#records > li")} phx-click-away={JS.remove_class("pointer-events-none", to: "#records > li")}
> >
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</div> </.button>
</:toggle> </:toggle>
<.focus_wrap id={"actions-#{record.id}-focus-wrap"} class="pointer-events-auto"> <.focus_wrap id={"actions-#{record.id}-focus-wrap"} class="pointer-events-auto">
<.dropdown_link id={"actions-#{record.id}-edit"} patch={@record_edit_path.(record)}> <.dropdown_link id={"actions-#{record.id}-edit"} patch={@record_edit_path.(record)}>
@@ -246,15 +247,17 @@ defmodule MusicLibraryWeb.RecordComponents do
<p class="pointer-events-none mt-2 block truncate text-sm font-medium text-zinc-900 dark:text-zinc-300"> <p class="pointer-events-none mt-2 block truncate text-sm font-medium text-zinc-900 dark:text-zinc-300">
{record.title} {record.title}
</p> </p>
<.dropdown id={"actions-#{record.id}"} placement="bottom-end" class="mt-2"> <.dropdown id={"actions-#{record.id}"} placement="bottom-end">
<:toggle> <:toggle>
<.button variant="ghost" class="mt-2">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</.button>
</:toggle> </:toggle>
<.focus_wrap id={"actions-#{record.id}-focus-wrap"}> <.focus_wrap id={"actions-#{record.id}-focus-wrap"}>
<.dropdown_link id={"actions-#{record.id}-edit"} patch={@record_edit_path.(record)}> <.dropdown_link id={"actions-#{record.id}-edit"} patch={@record_edit_path.(record)}>
+1 -1
View File
@@ -69,7 +69,7 @@ defmodule MusicLibraryWeb.Components.Release do
<div class="mt-4 text-sm leading-5 text-zinc-500 dark:text-zinc-400"> <div class="mt-4 text-sm leading-5 text-zinc-500 dark:text-zinc-400">
<.icon <.icon
name="hero-exclamation-triangle" name="hero-exclamation-triangle"
class="-mt-1 mr-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -13,7 +13,7 @@ defmodule MusicLibraryWeb.ScrobbleComponents do
phx-click={JS.push("refresh_lastfm_feed")} phx-click={JS.push("refresh_lastfm_feed")}
> >
<span class="sr-only">{gettext("Refresh LastFm Feed")}</span> <span class="sr-only">{gettext("Refresh LastFm Feed")}</span>
<.icon name="hero-arrow-path" class="-mt-1 h-5 w-5" aria-hidden="true" data-slot="icon" /> <.icon name="hero-arrow-path" class="h-5 w-5" aria-hidden="true" data-slot="icon" />
</button> </button>
""" """
end end
@@ -186,7 +186,7 @@ defmodule MusicLibraryWeb.StatsComponents do
</span> </span>
<.icon <.icon
name="hero-banknotes" name="hero-banknotes"
class="-mt-1 h-4 w-4" class="h-4 w-4"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -22,13 +22,15 @@
</button> </button>
<.dropdown id={"actions-#{@artist.musicbrainz_id}"} placement="bottom-end"> <.dropdown id={"actions-#{@artist.musicbrainz_id}"} placement="bottom-end">
<:toggle> <:toggle>
<.button variant="ghost">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</.button>
</:toggle> </:toggle>
<.focus_wrap id={"actions-#{@artist.musicbrainz_id}-focus-wrap"}> <.focus_wrap id={"actions-#{@artist.musicbrainz_id}-focus-wrap"}>
<.dropdown_link <.dropdown_link
@@ -12,41 +12,44 @@
<h1 class="text-base font-medium leading-6 text-zinc-700"> <h1 class="text-base font-medium leading-6 text-zinc-700">
<.artist_links joinphrase_class="text-sm" artists={@record.artists} /> <.artist_links joinphrase_class="text-sm" artists={@record.artists} />
</h1> </h1>
<div class="min-w-12 border-0 space-x-2 md:space-x-0"> <div class="min-w-12">
<button <.button_group>
class="text-xs md:text-sm text-zinc-700 dark:text-zinc-300" <.button
variant="soft"
phx-click={MusicLibraryWeb.Components.Notes.open("record-notes-sheet")} phx-click={MusicLibraryWeb.Components.Notes.open("record-notes-sheet")}
> >
<span class="sr-only">{gettext("Open Notes")}</span> <span class="sr-only">{gettext("Open Notes")}</span>
<.icon <.icon
name="hero-pencil-square" name="hero-pencil-square"
class="-mt-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</button> </.button>
<button <.button
:if={@record.selected_release_id} :if={@record.selected_release_id}
class="text-xs md:text-sm text-zinc-700 dark:text-zinc-300" variant="soft"
phx-click={MusicLibraryWeb.Components.Release.open("release-with-tracks-sheet")} phx-click={MusicLibraryWeb.Components.Release.open("release-with-tracks-sheet")}
> >
<span class="sr-only">{gettext("Show Tracks")}</span> <span class="sr-only">{gettext("Show Tracks")}</span>
<.icon <.icon
name="hero-numbered-list" name="hero-numbered-list"
class="-mt-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</button> </.button>
<.dropdown id={"actions-#{@record.id}"} placement="bottom-end"> <.dropdown id={"actions-#{@record.id}"} placement="bottom-end">
<:toggle class="h-5 block"> <:toggle>
<.button variant="soft">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</.button>
</:toggle> </:toggle>
<.focus_wrap id={"actions-#{@record.id}-focus-wrap"}> <.focus_wrap id={"actions-#{@record.id}-focus-wrap"}>
<.dropdown_link <.dropdown_link
@@ -144,6 +147,7 @@
</.dropdown_link> </.dropdown_link>
</.focus_wrap> </.focus_wrap>
</.dropdown> </.dropdown>
</.button_group>
</div> </div>
</div> </div>
<div> <div>
@@ -53,15 +53,15 @@
<div class="flex items-center"> <div class="flex items-center">
<.dropdown id={"actions-#{template.id}"} placement="bottom-end"> <.dropdown id={"actions-#{template.id}"} placement="bottom-end">
<:toggle> <:toggle>
<div> <.button variant="ghost">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</div> </.button>
</:toggle> </:toggle>
<.dropdown_button phx-click="toggle-enabled" phx-value-id={template.id}> <.dropdown_button phx-click="toggle-enabled" phx-value-id={template.id}>
{if template.enabled, {if template.enabled,
@@ -58,18 +58,18 @@
{Calendar.strftime(scrobble_rule.inserted_at, "%Y-%m-%d")} {Calendar.strftime(scrobble_rule.inserted_at, "%Y-%m-%d")}
</span> </span>
</div> </div>
<div class="flex items-center"> <div class="flex items-center p-2">
<.dropdown id={"actions-#{scrobble_rule.id}"} placement="bottom-end"> <.dropdown id={"actions-#{scrobble_rule.id}"} placement="bottom-end">
<:toggle> <:toggle>
<div> <.button variant="ghost">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</div> </.button>
</:toggle> </:toggle>
<.dropdown_button phx-click="apply_rule" phx-value-id={scrobble_rule.id}> <.dropdown_button phx-click="apply_rule" phx-value-id={scrobble_rule.id}>
{gettext("Apply rule")} {gettext("Apply rule")}
@@ -168,15 +168,15 @@
</.dropdown> </.dropdown>
<.dropdown id={"actions-#{track.scrobbled_at_uts}"} placement="bottom-end"> <.dropdown id={"actions-#{track.scrobbled_at_uts}"} placement="bottom-end">
<:toggle> <:toggle>
<div> <.button variant="ghost">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</div> </.button>
</:toggle> </:toggle>
<.dropdown_link patch={~p"/scrobbled-tracks/#{track.scrobbled_at_uts}/edit"}> <.dropdown_link patch={~p"/scrobbled-tracks/#{track.scrobbled_at_uts}/edit"}>
{gettext("Edit")} {gettext("Edit")}
@@ -137,7 +137,7 @@
<.tooltip> <.tooltip>
<.icon <.icon
name="hero-information-circle" name="hero-information-circle"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -163,7 +163,7 @@
</span> </span>
<.icon <.icon
name="hero-clipboard-document" name="hero-clipboard-document"
class="-mt-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -190,7 +190,7 @@
</span> </span>
<.icon <.icon
name="hero-clipboard-document" name="hero-clipboard-document"
class="-mt-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -235,13 +235,15 @@
placement="bottom-end" placement="bottom-end"
> >
<:toggle> <:toggle>
<.button variant="ghost">
<span class="sr-only">{gettext("Choose which format to import")}</span> <span class="sr-only">{gettext("Choose which format to import")}</span>
<.icon <.icon
name="hero-star" name="hero-star"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</.button>
</:toggle> </:toggle>
<.focus_wrap id={"actions-#{album.scrobbled_at_uts}-albums-focus-wrap"}> <.focus_wrap id={"actions-#{album.scrobbled_at_uts}-albums-focus-wrap"}>
<.dropdown_link <.dropdown_link
@@ -326,7 +328,7 @@
<.tooltip> <.tooltip>
<.icon <.icon
name="hero-information-circle" name="hero-information-circle"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -352,7 +354,7 @@
</span> </span>
<.icon <.icon
name="hero-clipboard-document" name="hero-clipboard-document"
class="-mt-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -379,7 +381,7 @@
</span> </span>
<.icon <.icon
name="hero-clipboard-document" name="hero-clipboard-document"
class="-mt-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -406,7 +408,7 @@
</span> </span>
<.icon <.icon
name="hero-clipboard-document" name="hero-clipboard-document"
class="-mt-1 h-5 w-5" class="h-5 w-5"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
@@ -446,13 +448,15 @@
placement="bottom-end" placement="bottom-end"
> >
<:toggle> <:toggle>
<.button variant="ghost">
<span class="sr-only">{gettext("Choose which format to import")}</span> <span class="sr-only">{gettext("Choose which format to import")}</span>
<.icon <.icon
name="hero-star" name="hero-star"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</.button>
</:toggle> </:toggle>
<.focus_wrap id={"actions-#{track.scrobbled_at_uts}-tracks-focus-wrap"}> <.focus_wrap id={"actions-#{track.scrobbled_at_uts}-tracks-focus-wrap"}>
<.dropdown_link <.dropdown_link
@@ -30,7 +30,7 @@ defmodule MusicLibraryWeb.UniversalSearchLive.Index do
</script> </script>
<.button <.button
id="universal-search-button" id="universal-search-button"
variant="ghost" variant="soft"
title={gettext("Search (Cmd/Ctrl+K)")} title={gettext("Search (Cmd/Ctrl+K)")}
phx-click="open_modal" phx-click="open_modal"
phx-target="#universal-search" phx-target="#universal-search"
@@ -14,13 +14,15 @@
</h1> </h1>
<.dropdown id={"actions-#{@record.id}"} placement="bottom-end"> <.dropdown id={"actions-#{@record.id}"} placement="bottom-end">
<:toggle class="h-5 block"> <:toggle class="h-5 block">
<.button variant="ghost">
<span class="sr-only">{gettext("Actions")}</span> <span class="sr-only">{gettext("Actions")}</span>
<.icon <.icon
name="hero-ellipsis-vertical" name="hero-ellipsis-vertical"
class="-mt-1 h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer" class="h-5 w-5 text-zinc-500 dark:text-zinc-400 cursor-pointer"
aria-hidden="true" aria-hidden="true"
data-slot="icon" data-slot="icon"
/> />
</.button>
</:toggle> </:toggle>
<.focus_wrap id={"actions-#{@record.id}-focus-wrap"}> <.focus_wrap id={"actions-#{@record.id}-focus-wrap"}>
<.dropdown_link <.dropdown_link