feat(preview): link discovery feed + Find-similar to the artist preview

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan
2026-07-12 01:49:40 +02:00
parent e1033dab81
commit 3928662809
+32 -3
View File
@@ -26,6 +26,7 @@ export function DiscoverClient() {
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const [search, setSearch] = useState<SearchResult | null>(null); const [search, setSearch] = useState<SearchResult | null>(null);
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const [followedSimilar, setFollowedSimilar] = useState<Set<string>>(new Set());
const loadFeed = useCallback(async () => { const loadFeed = useCallback(async () => {
setFeed(await (await fetch("/api/discover")).json()); setFeed(await (await fetch("/api/discover")).json());
@@ -70,6 +71,17 @@ export function DiscoverClient() {
} }
} }
async function followSimilar(a: { mbid: string; name: string }) {
const res = await fetch("/api/artists", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ mbid: a.mbid, name: a.name }),
});
if (res.ok || res.status === 409) {
setFollowedSimilar((s) => new Set(s).add(a.mbid));
}
}
async function act(id: string, action: "follow" | "want" | "dismiss") { async function act(id: string, action: "follow" | "want" | "dismiss") {
await fetch(`/api/discover/${id}`, { await fetch(`/api/discover/${id}`, {
method: "POST", method: "POST",
@@ -104,7 +116,13 @@ export function DiscoverClient() {
<ul> <ul>
{search.similar.map((s) => ( {search.similar.map((s) => (
<li key={s.mbid}> <li key={s.mbid}>
{s.name} <small>({s.score.toFixed(1)})</small> <a href={`/discover/artist/${s.mbid}?name=${encodeURIComponent(s.name)}`}>{s.name}</a>{" "}
<small>({s.score.toFixed(1)})</small>{" "}
{followedSimilar.has(s.mbid) ? (
<span>Followed</span>
) : (
<button onClick={() => followSimilar(s)}>Follow</button>
)}
</li> </li>
))} ))}
</ul> </ul>
@@ -116,7 +134,11 @@ export function DiscoverClient() {
<ul> <ul>
{feed.artists.map((s) => ( {feed.artists.map((s) => (
<li key={s.id}> <li key={s.id}>
<strong>{s.artistName}</strong>{" "} <strong>
<a href={`/discover/artist/${s.artistMbid}?name=${encodeURIComponent(s.artistName)}`}>
{s.artistName}
</a>
</strong>{" "}
<small>score {s.score.toFixed(2)} · {s.seedCount} seed(s) · {s.sources.join(", ")}</small>{" "} <small>score {s.score.toFixed(2)} · {s.seedCount} seed(s) · {s.sources.join(", ")}</small>{" "}
<button onClick={() => act(s.id, "follow")}>Follow</button>{" "} <button onClick={() => act(s.id, "follow")}>Follow</button>{" "}
<button onClick={() => act(s.id, "dismiss")}>Dismiss</button> <button onClick={() => act(s.id, "dismiss")}>Dismiss</button>
@@ -130,7 +152,14 @@ export function DiscoverClient() {
<ul> <ul>
{feed.albums.map((s) => ( {feed.albums.map((s) => (
<li key={s.id}> <li key={s.id}>
<strong>{s.album}</strong> {s.artistName}{" "} <strong>
<a
href={`/discover/artist/${s.artistMbid}?name=${encodeURIComponent(s.artistName)}#rg-${s.rgMbid}`}
>
{s.album}
</a>
</strong>{" "}
{s.artistName}{" "}
<small>score {s.score.toFixed(2)}</small>{" "} <small>score {s.score.toFixed(2)}</small>{" "}
<button onClick={() => act(s.id, "want")}>Want</button>{" "} <button onClick={() => act(s.id, "want")}>Want</button>{" "}
<button onClick={() => act(s.id, "dismiss")}>Dismiss</button> <button onClick={() => act(s.id, "dismiss")}>Dismiss</button>