feat(web): artist detail — category tabs, cover thumbs, album modal

Discography now has category tabs (All/Albums/Singles/EPs/Live/Comps/Other
with counts, defaults to Albums), cover-art thumbnails, and clicking an album
opens the AlbumModal with its tracklist. Detail GET gains ?all=true so the
client filters by tab (studio-only default still governs the artists-list
counts). Replaces the old flat date-sorted list + show-all toggle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan
2026-07-12 15:20:06 +02:00
parent 34235a2355
commit d05d092d53
4 changed files with 116 additions and 36 deletions
@@ -45,6 +45,14 @@ describe("artist item API", () => {
expect(body.releases.map((r: { rgMbid: string }) => r.rgMbid).sort()).toEqual(["rg1", "rg2"]);
});
it("returns all release types with ?all=true regardless of showAllTypes", async () => {
const a = await seedArtist();
const res = await GET(new Request(`http://localhost/x?all=true`), ctx(a.id));
const body = await res.json();
expect(body.showAllTypes).toBe(false);
expect(body.releases).toHaveLength(2); // the Live secondary-type release is included
});
it("404s an unknown artist on GET", async () => {
expect((await GET(new Request("http://localhost/x"), ctx("nope"))).status).toBe(404);
});
+5 -2
View File
@@ -2,14 +2,17 @@ import { prisma } from "@/lib/db";
import { Prisma } from "@prisma/client";
import { isCoreRelease } from "@/lib/release-filter";
export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) {
export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
// ?all=true returns every release type (the detail page filters client-side via tabs);
// otherwise honour the artist's showAllTypes flag (studio-only default) as before.
const all = new URL(request.url).searchParams.get("all") === "true";
const artist = await prisma.watchedArtist.findUnique({
where: { id },
include: { releases: { orderBy: [{ firstReleaseDate: "desc" }, { album: "asc" }] } },
});
if (!artist) return Response.json({ error: "not found" }, { status: 404 });
const visibleReleases = artist.showAllTypes ? artist.releases : artist.releases.filter(isCoreRelease);
const visibleReleases = all || artist.showAllTypes ? artist.releases : artist.releases.filter(isCoreRelease);
return Response.json({
id: artist.id,
mbid: artist.mbid,