Enable quick actions from universal search

This commit is contained in:
Claudio Ortolina
2026-03-29 23:07:53 +01:00
parent 0483d89fa7
commit 8f8eb0a656
9 changed files with 132 additions and 28 deletions
@@ -168,7 +168,7 @@ defmodule MusicLibraryWeb.SearchComponents do
"""
attr :label, :string, required: true
attr :icon, :string, required: true
attr :rest, :global, include: ~w(phx-click phx-value-path)
attr :rest, :global, include: ~w(phx-click phx-value-path phx-target)
def search_result_navigation(assigns) do
~H"""
@@ -273,18 +273,22 @@ defmodule MusicLibraryWeb.SearchComponents do
<.results_footer />
"""
attr :total_results, :integer, default: 0
attr :has_navigable_items, :boolean, default: false
def results_footer(assigns) do
assigns =
assign(assigns, :show_nav_hints, assigns.total_results > 0 or assigns.has_navigable_items)
~H"""
<div class="rounded-b-lg border-t border-zinc-200 bg-zinc-50 p-2 dark:border-zinc-700 dark:bg-zinc-900">
<div class="flex items-center justify-between text-xs text-zinc-500 dark:text-zinc-400">
<div class="flex items-center space-x-4">
<div :if={@total_results > 0} class="flex items-center gap-1">
<div :if={@show_nav_hints} class="flex items-center gap-1">
<kbd class="rounded bg-zinc-200 px-2 py-1 dark:bg-zinc-700">↑</kbd>
<kbd class="rounded bg-zinc-200 px-2 py-1 dark:bg-zinc-700">↓</kbd>
<span>{gettext("Navigate")}</span>
</div>
<div :if={@total_results > 0} class="flex items-center gap-1">
<div :if={@show_nav_hints} class="flex items-center gap-1">
<kbd class="rounded bg-zinc-200 px-2 py-1 dark:bg-zinc-700">Enter</kbd>
<span>{gettext("Select")}</span>
</div>
@@ -328,21 +332,39 @@ defmodule MusicLibraryWeb.SearchComponents do
<.no_results query="radiohead" />
"""
attr :query, :string, required: true
attr :target, :any, required: true
def no_results(assigns) do
~H"""
<div class="p-8 text-center">
<div class="p-4 text-center">
<.icon name="hero-face-frown" class="mx-auto mb-4 size-12 text-zinc-400" />
<p class="text-zinc-600 dark:text-zinc-400">
{gettext("No results found for '%{query}'", query: @query)}
</p>
<.link
class="truncate text-sm font-medium text-zinc-900 dark:text-zinc-100"
navigate={~p"/wishlist/import?#{[import_query: @query]}"}
>
{gettext("Add a record instead", query: @query)}
</.link>
</div>
<.search_result_group title={gettext("Quick actions")} count={3}>
<.search_result_navigation
label={gettext("Add to wishlist")}
icon="hero-star"
phx-click="navigate_to_link"
phx-value-path={~p"/wishlist/import?#{[import_query: @query]}"}
phx-target={@target}
/>
<.search_result_navigation
label={gettext("Add to collection")}
icon="hero-plus-circle"
phx-click="navigate_to_link"
phx-value-path={~p"/collection/import?#{[import_query: @query]}"}
phx-target={@target}
/>
<.search_result_navigation
label={gettext("Search to scrobble")}
icon="hero-play"
phx-click="navigate_to_link"
phx-value-path={~p"/scrobble?#{[query: @query]}"}
phx-target={@target}
/>
</.search_result_group>
"""
end
@@ -169,7 +169,7 @@ defmodule MusicLibraryWeb.CollectionLive.Index do
action={@live_action}
record={@record}
patch={back_path(@record_list_params)}
initial_query=""
initial_query={@import_query}
icon_name="hero-plus"
/>
</.structured_modal>
@@ -198,6 +198,7 @@ defmodule MusicLibraryWeb.CollectionLive.Index do
{:ok,
socket
|> assign(:current_section, :collection)
|> assign(:import_query, "")
|> assign(:display, :grid)}
end
@@ -207,9 +208,12 @@ defmodule MusicLibraryWeb.CollectionLive.Index do
end
defp apply_action(socket, :import, params) do
import_query = params["import_query"] || ""
socket
|> apply_fallback_index(params, :records, &apply_action/3)
|> assign(:page_title, gettext("Add new Record · Collection"))
|> assign(:import_query, import_query)
|> assign(:record, nil)
end
@@ -168,9 +168,20 @@ defmodule MusicLibraryWeb.ScrobbleLive.Index do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, gettext("Scrobble"))
defp apply_action(socket, :index, params) do
query = params["query"] || ""
socket =
socket
|> assign(:page_title, gettext("Scrobble"))
|> assign(:search_query, query)
if String.trim(query) != "" do
send(self(), {:perform_search, query})
assign(socket, :loading, true)
else
socket
end
end
@impl true
@@ -36,7 +36,11 @@ defmodule MusicLibraryWeb.UniversalSearchLive.Index do
<.empty_state :if={@search_query == ""} />
<.no_results :if={@search_query != "" and @total_results == 0} query={@search_query} />
<.no_results
:if={@search_query != "" and @total_results == 0}
query={@search_query}
target={@myself}
/>
<div :if={@total_results > 0} class="mt-4 max-h-148 overflow-y-auto md:max-h-164">
<.search_result_group
@@ -145,7 +149,10 @@ defmodule MusicLibraryWeb.UniversalSearchLive.Index do
/>
</:actions>
</.search_result_group>
<.results_footer total_results={@total_results} />
<.results_footer
total_results={@total_results}
has_navigable_items={@search_query != ""}
/>
</.structured_modal>
</div>
"""