Static path, search dropdown, async follow
This commit is contained in:
@@ -29,8 +29,10 @@ public class AppSetting extends PanacheEntity {
|
||||
if (s == null) {
|
||||
s = new AppSetting();
|
||||
s.key = key;
|
||||
s.value = value;
|
||||
s.persist();
|
||||
} else {
|
||||
s.value = value;
|
||||
}
|
||||
s.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Path("/artists")
|
||||
public class ArtistResource {
|
||||
@@ -36,6 +37,10 @@ public class ArtistResource {
|
||||
@Location("fragments/feed-list.html")
|
||||
Template fragments_feed_list;
|
||||
|
||||
@Inject
|
||||
@Location("fragments/feed-row.html")
|
||||
Template fragments_feed_row;
|
||||
|
||||
@Inject
|
||||
@Location("fragments/artist-row.html")
|
||||
Template fragments_artist_row;
|
||||
@@ -61,16 +66,16 @@ public class ArtistResource {
|
||||
dto.area = new ArtistSearchResult.ArtistDto.Area();
|
||||
dto.area.name = area;
|
||||
}
|
||||
FollowedArtist artist = artistService.follow(dto);
|
||||
syncService.syncArtist(artist.mbid);
|
||||
return feedFragment(0);
|
||||
artistService.follow(dto);
|
||||
CompletableFuture.runAsync(() -> syncService.syncArtist(mbid));
|
||||
return feedFragment(0, true);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{mbid}")
|
||||
public TemplateInstance unfollow(@PathParam("mbid") String mbid) {
|
||||
artistService.unfollow(mbid);
|
||||
return feedFragment(0);
|
||||
return feedFragment(0, false);
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -96,12 +101,12 @@ public class ArtistResource {
|
||||
FollowedArtist artist = artistService.findArtist(mbid);
|
||||
if (artist != null) {
|
||||
artistService.setTypeEnabled(artist, primaryType, enabled);
|
||||
syncService.resyncArtist(mbid);
|
||||
CompletableFuture.runAsync(() -> syncService.resyncArtist(mbid));
|
||||
}
|
||||
return feedFragment(0);
|
||||
return feedFragment(0, true);
|
||||
}
|
||||
|
||||
private TemplateInstance feedFragment(int offset) {
|
||||
private TemplateInstance feedFragment(int offset, boolean autoRefresh) {
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
@@ -111,6 +116,7 @@ public class ArtistResource {
|
||||
return fragments_feed_list.data("rows", rows)
|
||||
.data("nextOffset", nextOffset)
|
||||
.data("hasMore", hasMore)
|
||||
.data("pageSize", feedService.pageSize());
|
||||
.data("pageSize", feedService.pageSize())
|
||||
.data("autoRefresh", autoRefresh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ public class PageResource {
|
||||
return fragments_feed_list.data("rows", rows)
|
||||
.data("nextOffset", nextOffset)
|
||||
.data("hasMore", hasMore)
|
||||
.data("pageSize", feedService.pageSize());
|
||||
.data("pageSize", feedService.pageSize())
|
||||
.data("autoRefresh", false);
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -52,6 +53,7 @@ public class PageResource {
|
||||
.data("nextOffset", rows.size())
|
||||
.data("hasMore", hasMore)
|
||||
.data("pageSize", feedService.pageSize())
|
||||
.data("autoRefresh", false)
|
||||
.data("followedCount", FollowedArtist.count())
|
||||
.data("feedCount", ReleaseGroupEntity.count());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.discdrop.service;
|
||||
|
||||
import io.discdrop.persistence.AppSetting;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -22,6 +23,7 @@ public class SettingsService {
|
||||
return parseTypes(raw);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void setDefaultPrimaryTypes(Set<String> types) {
|
||||
AppSetting.set(KEY_DEFAULT_PRIMARY_TYPES, String.join(",", types));
|
||||
}
|
||||
@@ -35,6 +37,7 @@ public class SettingsService {
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void setSyncScheduleHours(int hours) {
|
||||
AppSetting.set(KEY_SYNC_SCHEDULE_HOURS, String.valueOf(hours));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/* DiscDrop custom styles */
|
||||
html { scroll-behavior: smooth; }
|
||||
|
||||
/* Hide empty search dropdown */
|
||||
#search-dropdown:empty { display: none; }
|
||||
|
||||
/* Remove native search input artifacts */
|
||||
input[type="text"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 469 B After Width: | Height: | Size: 469 B |
|
Before Width: | Height: | Size: 676 B After Width: | Height: | Size: 676 B |
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
@@ -1,3 +0,0 @@
|
||||
/* DiscDrop custom styles */
|
||||
html { scroll-behavior: smooth; }
|
||||
#search-dropdown:empty { display: none; }
|
||||
@@ -4,18 +4,18 @@
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>DiscDrop – Artists</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/img/favicon.svg"/>
|
||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg"/>
|
||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.min.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/[email protected]"></script>
|
||||
<link rel="stylesheet" href="/static/css/app.css"/>
|
||||
<script src="/static/js/app.js" defer></script>
|
||||
<link rel="stylesheet" href="/css/app.css"/>
|
||||
<script src="/js/app.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="sticky top-0 z-30 bg-base-100/90 backdrop-blur border-b border-base-300">
|
||||
<div class="navbar flex flex-wrap justify-center gap-4 px-4 py-3 max-w-5xl mx-auto">
|
||||
<div class="flex items-center gap-2">
|
||||
<img src="/static/img/logo.svg" alt="DiscDrop logo" class="h-9 w-9"/>
|
||||
<img src="/img/logo.svg" alt="DiscDrop logo" class="h-9 w-9"/>
|
||||
<span class="text-xl font-bold">DiscDrop</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
@@ -16,3 +16,10 @@
|
||||
<p class="text-sm">Search for an artist above and click <strong>Follow</strong> to start tracking their release groups.</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if autoRefresh?? && autoRefresh}
|
||||
<div hx-get="/feed?offset=0"
|
||||
hx-target="#feed-list"
|
||||
hx-swap="innerHTML"
|
||||
hx-trigger="load delay:3s"
|
||||
class="hidden"></div>
|
||||
{/if}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
alt="cover"
|
||||
loading="lazy"
|
||||
class="w-16 h-16 rounded object-cover bg-base-200"
|
||||
onerror="this.onerror=null;this.src='/static/img/no-cover.svg'"/>
|
||||
onerror="this.onerror=null;this.src='/img/no-cover.svg'"/>
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
|
||||
@@ -4,38 +4,37 @@
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>DiscDrop</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/img/favicon.svg"/>
|
||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg"/>
|
||||
<link rel="alternate" type="application/rss+xml" title="DiscDrop – New Releases" href="/rss"/>
|
||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.min.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/[email protected]"></script>
|
||||
<link rel="stylesheet" href="/static/css/app.css"/>
|
||||
<script src="/static/js/app.js" defer></script>
|
||||
<link rel="stylesheet" href="/css/app.css"/>
|
||||
<script src="/js/app.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="sticky top-0 z-30 bg-base-100/90 backdrop-blur border-b border-base-300">
|
||||
<div class="navbar flex flex-wrap justify-center gap-4 px-4 py-3 max-w-5xl mx-auto">
|
||||
<div class="flex items-center gap-2">
|
||||
<img src="/static/img/logo.svg" alt="DiscDrop logo" class="h-9 w-9"/>
|
||||
<img src="/img/logo.svg" alt="DiscDrop logo" class="h-9 w-9"/>
|
||||
<span class="text-xl font-bold">DiscDrop</span>
|
||||
</div>
|
||||
|
||||
<div id="search-wrap" class="relative flex-1 min-w-[220px] max-w-xl">
|
||||
<form id="search-form" class="join w-full" autocomplete="off">
|
||||
<input
|
||||
id="search-input"
|
||||
type="search"
|
||||
name="q"
|
||||
placeholder="Search MusicBrainz artists…"
|
||||
class="input input-bordered join-item w-full"
|
||||
hx-get="/search/artists"
|
||||
hx-trigger="input changed delay:300ms"
|
||||
hx-target="#search-dropdown"
|
||||
hx-swap="innerHTML"
|
||||
hx-include="this"/>
|
||||
</form>
|
||||
<input
|
||||
id="search-input"
|
||||
type="text"
|
||||
name="q"
|
||||
placeholder="Search MusicBrainz artists…"
|
||||
class="input input-bordered w-full"
|
||||
autocomplete="off"
|
||||
hx-get="/search/artists"
|
||||
hx-trigger="input changed delay:300ms"
|
||||
hx-target="#search-dropdown"
|
||||
hx-swap="innerHTML"
|
||||
hx-include="this"/>
|
||||
<div id="search-dropdown"
|
||||
class="absolute left-0 right-0 z-40 mt-1 bg-base-100 rounded-box shadow-lg border border-base-300 max-h-96 overflow-y-auto"></div>
|
||||
class="absolute left-0 right-0 top-full z-40 mt-1 bg-base-100 rounded-box shadow-lg border border-base-300 max-h-96 overflow-y-auto"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user