From 79c749b9a7e613ec95c98014ce1bd342e03ad2a1 Mon Sep 17 00:00:00 2001 From: Quick <31828688+Quick104@users.noreply.github.com> Date: Tue, 9 Jun 2026 20:02:18 -0400 Subject: [PATCH] Feat/continue watching card affordance (#120) * feat(web): improve Continue Watching card affordances Add hover/active feedback to the play button (scale, brightness, shadow) and make the episode meta and time-left lines link to the item page like the heading. The blank time-left placeholder stays a plain div so card heights align without an invisible link. Co-Authored-By: Claude Fable 5 * test(web): cover audiobook-only continue sections using poster cards Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Claude Fable 5 --- web/src/components/ContinueWatchingCard.tsx | 23 +++++++++-- web/src/components/SectionRow.test.tsx | 44 +++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/web/src/components/ContinueWatchingCard.tsx b/web/src/components/ContinueWatchingCard.tsx index 2a91d0f8..977b3eb2 100644 --- a/web/src/components/ContinueWatchingCard.tsx +++ b/web/src/components/ContinueWatchingCard.tsx @@ -252,7 +252,7 @@ export default function ContinueWatchingCard(props: ContinueWatchingCardProps) { to={card.watchHref} onClick={handleWatchClick} aria-label={`Play ${heading}`} - className="bg-primary text-primary-foreground absolute top-1/2 left-1/2 flex h-11 w-11 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full opacity-100 shadow-lg transition-all duration-200 pointer-fine:pointer-events-none pointer-fine:opacity-0 pointer-fine:group-hover/media:pointer-events-auto pointer-fine:group-hover/media:opacity-100 pointer-fine:focus-visible:pointer-events-auto pointer-fine:focus-visible:opacity-100" + className="bg-primary text-primary-foreground absolute top-1/2 left-1/2 flex h-11 w-11 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full opacity-100 shadow-lg transition-all duration-200 hover:scale-110 hover:shadow-xl hover:brightness-110 active:scale-95 pointer-fine:pointer-events-none pointer-fine:opacity-0 pointer-fine:group-hover/media:pointer-events-auto pointer-fine:group-hover/media:opacity-100 pointer-fine:focus-visible:pointer-events-auto pointer-fine:focus-visible:opacity-100" > @@ -283,7 +283,14 @@ export default function ContinueWatchingCard(props: ContinueWatchingCardProps) { > {heading} - {episodeMeta &&
{episodeMeta}
} + {episodeMeta && ( + + {episodeMeta} + + )} {premiereBadge && (
)} - {timeLeftLabel &&
{timeLeftLabel}
} + {timeLeftLabel && + (timeLeftLabel === "\u00A0" ? ( +
{timeLeftLabel}
+ ) : ( + + {timeLeftLabel} + + ))} ); diff --git a/web/src/components/SectionRow.test.tsx b/web/src/components/SectionRow.test.tsx index 3380c4d3..18f61986 100644 --- a/web/src/components/SectionRow.test.tsx +++ b/web/src/components/SectionRow.test.tsx @@ -121,6 +121,50 @@ describe("SectionRow", () => { expect(markup).toContain("More actions"); }); + it("renders all-audiobook continue sections as square poster cards", () => { + const queryClient = new QueryClient(); + const section: ResolvedSection = { + id: "continue-listening", + section_type: "continue_watching", + title: "Continue Listening", + featured: false, + item_limit: 10, + total_count: 1, + is_custom: false, + customized: false, + items: [ + { + content_id: "book-001", + type: "audiobook", + title: "Project Hail Mary", + position_seconds: 600, + duration_seconds: 58000, + year: 2021, + genres: [], + status: "matched", + rating_imdb: null, + overview: "", + poster_url: "/book-cover.jpg", + poster_thumbhash: "", + backdrop_url: "", + backdrop_thumbhash: "", + logo_url: "", + }, + ], + }; + + const markup = renderToStaticMarkup( + + + + + , + ); + + expect(markup).toContain("aspect-square"); + expect(markup).not.toContain("aspect-video"); + }); + it("routes supported section view-all actions to browse destinations", () => { const queryClient = new QueryClient(); const section: ResolvedSection = {