Convert universal search into a live component

This commit is contained in:
Claudio Ortolina
2025-09-21 21:21:16 +03:00
parent 64cb917a4e
commit a1b9994837
3 changed files with 107 additions and 104 deletions
@@ -130,4 +130,4 @@
</div> </div>
</main> </main>
{MusicLibraryWeb.UniversalSearchLive.Index.live(@socket)} <.live_component module={MusicLibraryWeb.UniversalSearchLive.Index} id="universal-search" />
@@ -1,15 +1,11 @@
defmodule MusicLibraryWeb.UniversalSearchLive.Index do defmodule MusicLibraryWeb.UniversalSearchLive.Index do
use MusicLibraryWeb, :live_view use MusicLibraryWeb, :live_component
import MusicLibraryWeb.SearchComponents import MusicLibraryWeb.SearchComponents
alias MusicLibrary.Search alias MusicLibrary.Search
alias Phoenix.LiveView.ColocatedHook alias Phoenix.LiveView.ColocatedHook
def live(socket) do
live_render(socket, __MODULE__, id: "universal-search", session: %{})
end
def universal_search_trigger(assigns) do def universal_search_trigger(assigns) do
~H""" ~H"""
<script :type={ColocatedHook} name=".SearchGlobalShortcut"> <script :type={ColocatedHook} name=".SearchGlobalShortcut">
@@ -47,7 +43,7 @@ defmodule MusicLibraryWeb.UniversalSearchLive.Index do
end end
@impl true @impl true
def mount(_params, _session, socket) do def mount(socket) do
{:ok, {:ok,
socket socket
|> assign(:show_modal, false) |> assign(:show_modal, false)
@@ -1,105 +1,112 @@
<.structured_modal <div id={@id}>
:if={@show_modal} <.structured_modal
id="universal-search-root" :if={@show_modal}
open={@show_modal} id="universal-search-root"
on_close={JS.push("close_modal", value: %{})} open={@show_modal}
> on_close={JS.push("close_modal", value: %{}, target: "#universal-search")}
<form class="mt-4 text-sm" phx-change="search" phx-submit="search"> >
<div class="relative"> <form class="mt-4 text-sm" phx-change="search" phx-submit="search" phx-target={@myself}>
<.icon <div class="relative">
name="hero-magnifying-glass" <.icon
class="absolute left-3 top-1/2 transform -translate-y-1/2 h-5 w-5 text-zinc-400" name="hero-magnifying-glass"
/> class="absolute left-3 top-1/2 transform -translate-y-1/2 h-5 w-5 text-zinc-400"
<.input />
name="query" <.input
id="universal-search-input" name="query"
placeholder="Search records and artists..." id="universal-search-input"
value={@search_query} placeholder="Search records and artists..."
phx-debounce="300" value={@search_query}
autofocus phx-debounce="300"
/> autofocus
</div> />
</form> </div>
</form>
<!-- Empty state --> <!-- Empty state -->
<.empty_state :if={@search_query == ""} /> <.empty_state :if={@search_query == ""} />
<!-- No results --> <!-- No results -->
<.no_results :if={@search_query != "" and @total_results == 0} query={@search_query} /> <.no_results :if={@search_query != "" and @total_results == 0} query={@search_query} />
<!-- Search results --> <!-- Search results -->
<div :if={@total_results > 0} class="max-h-148 md:max-h-164 overflow-y-auto"> <div :if={@total_results > 0} class="max-h-148 md:max-h-164 overflow-y-auto">
<!-- Collection results --> <!-- Collection results -->
<.search_result_group <.search_result_group
:if={length(@search_results.collection) > 0} :if={length(@search_results.collection) > 0}
title="Collection" title="Collection"
count={length(@search_results.collection)} count={length(@search_results.collection)}
total_count={@search_counts.collection_count} total_count={@search_counts.collection_count}
> >
<.search_result_record <.search_result_record
:for={record <- @search_results.collection} :for={record <- @search_results.collection}
record={record} record={record}
type={:collection} type={:collection}
phx-click="navigate_to_record" phx-click="navigate_to_record"
phx-value-id={record.id} phx-value-id={record.id}
phx-value-type="collection" phx-value-type="collection"
/> phx-target={@myself}
<:actions>
<.view_all_button
:if={@search_counts.collection_count > length(@search_results.collection)}
count={@search_counts.collection_count}
target="collection"
phx-click="navigate_to_collection"
phx-value-query={@search_query}
/> />
</:actions> <:actions>
</.search_result_group> <.view_all_button
:if={@search_counts.collection_count > length(@search_results.collection)}
count={@search_counts.collection_count}
target="collection"
phx-click="navigate_to_collection"
phx-value-query={@search_query}
phx-target={@myself}
/>
</:actions>
</.search_result_group>
<!-- Wishlist results --> <!-- Wishlist results -->
<.search_result_group <.search_result_group
:if={length(@search_results.wishlist) > 0} :if={length(@search_results.wishlist) > 0}
title="Wishlist" title="Wishlist"
count={length(@search_results.wishlist)} count={length(@search_results.wishlist)}
total_count={@search_counts.wishlist_count} total_count={@search_counts.wishlist_count}
class="border-t border-zinc-200 dark:border-zinc-700" class="border-t border-zinc-200 dark:border-zinc-700"
> >
<.search_result_record <.search_result_record
:for={record <- @search_results.wishlist} :for={record <- @search_results.wishlist}
record={record} record={record}
type={:wishlist} type={:wishlist}
phx-click="navigate_to_record" phx-click="navigate_to_record"
phx-value-id={record.id} phx-value-id={record.id}
phx-value-type="wishlist" phx-value-type="wishlist"
/> phx-target={@myself}
<:actions>
<.view_all_button
:if={@search_counts.wishlist_count > length(@search_results.wishlist)}
count={@search_counts.wishlist_count}
target="wishlist"
phx-click="navigate_to_wishlist"
phx-value-query={@search_query}
/> />
</:actions> <:actions>
</.search_result_group> <.view_all_button
:if={@search_counts.wishlist_count > length(@search_results.wishlist)}
count={@search_counts.wishlist_count}
target="wishlist"
phx-click="navigate_to_wishlist"
phx-value-query={@search_query}
phx-target={@myself}
/>
</:actions>
</.search_result_group>
<!-- Artists results --> <!-- Artists results -->
<.search_result_group <.search_result_group
:if={length(@search_results.artists) > 0} :if={length(@search_results.artists) > 0}
title="Artists" title="Artists"
count={length(@search_results.artists)} count={length(@search_results.artists)}
total_count={@search_counts.artists_count} total_count={@search_counts.artists_count}
class="border-t border-zinc-200 dark:border-zinc-700" class="border-t border-zinc-200 dark:border-zinc-700"
> >
<.search_result_artist <.search_result_artist
:for={%{artist: artist, image_data_hash: image_data_hash} <- @search_results.artists} :for={%{artist: artist, image_data_hash: image_data_hash} <- @search_results.artists}
artist={artist} artist={artist}
image_data_hash={image_data_hash} image_data_hash={image_data_hash}
phx-click="navigate_to_artist" phx-click="navigate_to_artist"
phx-value-id={artist.musicbrainz_id} phx-value-id={artist.musicbrainz_id}
/> phx-target={@myself}
</.search_result_group> />
</div> </.search_result_group>
</div>
<!-- Footer with keyboard shortcuts --> <!-- Footer with keyboard shortcuts -->
<.results_footer total_results={@total_results} /> <.results_footer total_results={@total_results} />
</.structured_modal> </.structured_modal>
</div>