refactor(plex): one cast row for a show's page and a title's info

CastStrip (a show's page) and PlexInfo (a title's page and the player's overlay) each drew the
cast carousel by hand, and the copies had drifted: the gap, lazy pictures, the name's tooltip, the
initial's size. Both now render CastRow, which takes the overlay's white-on-art palette as a tone;
each caller keeps its own frame and heading. A DOM test holds the palette per variant (seen red
with the tone wired to "panel"). jscpd over the shipped code: 1 clone >= 10 lines -> 0.
This commit is contained in:
2026-10-03 19:12:17 +02:00
parent ca9ca85b18
commit c73761ae39
3 changed files with 100 additions and 121 deletions
@@ -300,6 +300,17 @@ describe("PlexInfo — the hero's second column (page)", () => {
expect(screen.getByTestId("detail-aside").textContent).toContain(`Person ${CREW_SHOWN + 1}`);
expect(screen.queryByRole("button", { name: "plex.info.crewMore" })).toBeNull();
});
// E32 S2: the cast row is the shared CastRow now; the page and the player's overlay hand it their
// own palette. Only the overlay sits on the dark art, so only it may carry the white text.
it.each([
["page", false],
["overlay", true],
] as const)("the %s variant's cast row takes its own palette", (variant, white) => {
wrap(<PlexInfo onPlayItem={noop} detail={full} variant={variant} />);
expect(screen.getByText("An Actor").className.includes("text-white/90")).toBe(white);
expect(screen.getByText("Hero").className.includes("text-muted")).toBe(!white);
});
});
// E28 review D1 + D2: a collection sibling is a Plex card like any other — its "…" menu, its watched