Fix search dropdown, async artist add, OOB swaps
- Fix search results dropdown: absolute position relative to search wrapper - Make release group fetching async via Vert.x executeBlocking (avoid blocking add) - Add OOB swap for artist list so +Add works from any page - Simplify search-results template styling - Add Response type for combined OOB responses
This commit is contained in:
@@ -9,9 +9,11 @@ import com.discdrop.service.ReleaseGroupService;
|
||||
import io.quarkus.qute.Location;
|
||||
import io.quarkus.qute.Template;
|
||||
import io.quarkus.qute.TemplateInstance;
|
||||
import io.vertx.core.Vertx;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,6 +29,9 @@ public class ArtistController {
|
||||
@Inject
|
||||
FeedService feedService;
|
||||
|
||||
@Inject
|
||||
Vertx vertx;
|
||||
|
||||
@Inject
|
||||
@Location("fragments/search-results")
|
||||
Template searchResultsTemplate;
|
||||
@@ -55,12 +60,18 @@ public class ArtistController {
|
||||
@POST
|
||||
@Path("/{mbid}/track")
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
public TemplateInstance trackArtist(@PathParam("mbid") String mbid) {
|
||||
public Response trackArtist(@PathParam("mbid") String mbid) {
|
||||
var artist = artistService.addArtist(mbid);
|
||||
var types = getMonitoredTypes(artist);
|
||||
releaseGroupService.fetchAndCache(artist.mbid(), artist.name(), types);
|
||||
vertx.executeBlocking(promise -> {
|
||||
releaseGroupService.fetchAndCache(artist.mbid(), artist.name(), types);
|
||||
promise.complete();
|
||||
});
|
||||
var allArtists = artistService.findAll();
|
||||
return artistListTemplate.data("artists", allArtists);
|
||||
var listHtml = artistListTemplate.data("artists", allArtists).render();
|
||||
var emptySearch = searchResultsTemplate.data("artists", List.of()).render();
|
||||
var combined = emptySearch + listHtml;
|
||||
return Response.ok(combined).build();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<div id="artist-list" hx-swap-oob="true">
|
||||
{#if artists.isEmpty()}
|
||||
<div class="card bg-base-100 shadow-xl p-8 text-center">
|
||||
<p class="text-lg text-base-content/60">No artists tracked yet</p>
|
||||
@@ -30,35 +31,40 @@
|
||||
<input type="checkbox" class="checkbox checkbox-xs checkbox-primary"
|
||||
{#if artist.albumMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=album"
|
||||
hx-target="#artist-list" hx-swap="innerHTML">
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Album</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
{#if artist.singleMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=single"
|
||||
hx-target="#artist-list" hx-swap="innerHTML">
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Single</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
{#if artist.epMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=ep"
|
||||
hx-target="#artist-list" hx-swap="innerHTML">
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">EP</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
{#if artist.broadcastMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=broadcast"
|
||||
hx-target="#artist-list" hx-swap="innerHTML">
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Broadcast</span>
|
||||
</label>
|
||||
<label class="label cursor-pointer gap-1">
|
||||
<input type="checkbox" class="checkbox checkbox-xs"
|
||||
{#if artist.otherMonitored}checked{/if}
|
||||
hx-patch="/api/artists/{artist.mbid}/monitor?type=other"
|
||||
hx-target="#artist-list" hx-swap="innerHTML">
|
||||
hx-target="#artist-list"
|
||||
hx-swap="innerHTML">
|
||||
<span class="label-text text-xs">Other</span>
|
||||
</label>
|
||||
</div>
|
||||
@@ -78,3 +84,4 @@
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="card bg-base-100 shadow-xl mt-1 max-h-64 overflow-y-auto">
|
||||
<div class="bg-base-100 shadow-xl border border-base-300 rounded-box mt-1 max-h-64 overflow-y-auto">
|
||||
{#if artists.isEmpty()}
|
||||
<div class="p-3 text-sm text-base-content/60">No artists found</div>
|
||||
{#else}
|
||||
@@ -18,9 +18,9 @@
|
||||
{#else}
|
||||
<button class="btn btn-primary btn-xs"
|
||||
hx-post="/api/artists/{artist.mbid}/track"
|
||||
hx-target="#artist-list"
|
||||
hx-target="#search-results"
|
||||
hx-swap="innerHTML"
|
||||
onclick="this.closest('#search-results').innerHTML=''; document.querySelector('[name=q]').value=''">
|
||||
onclick="document.getElementById('search-input').value=''">
|
||||
+ Add
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
@@ -7,12 +7,16 @@
|
||||
<link href="https://cdn.jsdelivr.net/npm/daisyui@4.12.23/dist/full.min.css" rel="stylesheet">
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js"></script>
|
||||
<style>
|
||||
.search-dropdown {
|
||||
#search-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
#search-results {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 50;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
@@ -40,7 +44,7 @@
|
||||
</div>
|
||||
|
||||
<div class="navbar-center">
|
||||
<div class="relative">
|
||||
<div id="search-wrapper" class="w-48 md:w-64">
|
||||
<form hx-get="/api/artists/search"
|
||||
hx-target="#search-results"
|
||||
hx-swap="innerHTML"
|
||||
@@ -48,18 +52,18 @@
|
||||
<input id="search-input"
|
||||
type="text"
|
||||
placeholder="Search artists..."
|
||||
class="input input-bordered input-sm w-48 md:w-64"
|
||||
class="input input-bordered input-sm w-full"
|
||||
name="q"
|
||||
autocomplete="off">
|
||||
</form>
|
||||
<div id="search-results" class="search-dropdown"></div>
|
||||
<div id="search-results"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-end gap-2">
|
||||
<select class="select select-bordered select-sm w-full max-w-[8rem]"
|
||||
onchange="setTheme(this)">
|
||||
<option value="dark">Dark</option>
|
||||
<option value="dark" selected>Dark</option>
|
||||
<option value="light">Light</option>
|
||||
<option value="synthwave">Synthwave</option>
|
||||
<option value="retro">Retro</option>
|
||||
|
||||
Reference in New Issue
Block a user