From f7d5179d0fd311c47cf08d944ce7c81df5033d47 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Sun, 1 Mar 2026 11:32:17 -0500 Subject: [PATCH] Enhance dashboard: richer continue watching cards, color-coded stats, styled poster fallback - Continue Watching cards now show episode still images in 16:9 aspect with overlaid episode info, play button, and progress bar - Stats section uses per-stat color coding (primary/watching/watchlist/completed) with icon background pills and tabular-nums alignment - No-poster fallback replaced with textured gradient + title text overlay - Updated ContinueWatchingItem interface to include backdropPath, stillPath, overview Co-Authored-By: Claude Opus 4.6 --- app/(pages)/dashboard/page.tsx | 89 +++++++++++++++++++++------------- components/stats-summary.tsx | 16 +++++- components/title-card.tsx | 15 +++++- lib/services/discovery.ts | 6 +++ 4 files changed, 88 insertions(+), 38 deletions(-) diff --git a/app/(pages)/dashboard/page.tsx b/app/(pages)/dashboard/page.tsx index 69fff29..b152b73 100644 --- a/app/(pages)/dashboard/page.tsx +++ b/app/(pages)/dashboard/page.tsx @@ -20,6 +20,7 @@ interface ContinueWatchingItem { id: string; title: string; posterPath: string | null; + backdropPath: string | null; type: string; }; nextEpisode: { @@ -27,6 +28,8 @@ interface ContinueWatchingItem { seasonNumber: number; episodeNumber: number; name: string | null; + stillPath: string | null; + overview: string | null; } | null; totalEpisodes: number; watchedEpisodes: number; @@ -267,9 +270,11 @@ function FeedSection({ } function ContinueWatchingCard({ item }: { item: ContinueWatchingItem }) { - const posterUrl = item.title.posterPath - ? `https://image.tmdb.org/t/p/w300${item.title.posterPath}` - : null; + const stillUrl = item.nextEpisode?.stillPath + ? `https://image.tmdb.org/t/p/w500${item.nextEpisode.stillPath}` + : item.title.backdropPath + ? `https://image.tmdb.org/t/p/w500${item.title.backdropPath}` + : null; const progress = item.totalEpisodes > 0 ? (item.watchedEpisodes / item.totalEpisodes) * 100 @@ -278,46 +283,62 @@ function ContinueWatchingCard({ item }: { item: ContinueWatchingItem }) { return ( -
- {posterUrl ? ( + {/* Episode still / backdrop image */} +
+ {stillUrl ? ( {item.title.title} ) : ( -
- ? +
+
)} - {/* Progress bar at bottom of poster */} - {progress > 0 && ( -
-
-
- )} -
-
-

- {item.title.title} -

+
+ {/* Episode label overlay */} {item.nextEpisode && ( -

- S{item.nextEpisode.seasonNumber} E{item.nextEpisode.episodeNumber} -

+
+

+ + Up next +

+

+ + S{item.nextEpisode.seasonNumber} E + {item.nextEpisode.episodeNumber} + {" "} + {item.nextEpisode.name} +

+
)} -

- - Up next -

+ {/* Bottom bar with title + progress */} +
+
+

{item.title.title}

+

+ {item.watchedEpisodes}/{item.totalEpisodes} episodes +

+
+
+ +
+
+ {/* Progress bar */} + {progress > 0 && ( +
+
+
+ )} ); } diff --git a/components/stats-summary.tsx b/components/stats-summary.tsx index 0e4c7c8..0f46f07 100644 --- a/components/stats-summary.tsx +++ b/components/stats-summary.tsx @@ -21,21 +21,29 @@ const statDefs = [ key: "moviesThisMonth" as const, label: "Movies This Month", icon: IconMovie, + color: "text-primary", + bgColor: "bg-primary/10", }, { key: "episodesThisWeek" as const, label: "Episodes This Week", icon: IconPlayerPlay, + color: "text-status-watching", + bgColor: "bg-status-watching/10", }, { key: "librarySize" as const, label: "In Library", icon: IconLibrary, + color: "text-status-watchlist", + bgColor: "bg-status-watchlist/10", }, { key: "completed" as const, label: "Completed", icon: IconCheck, + color: "text-status-completed", + bgColor: "bg-status-completed/10", }, ]; @@ -70,13 +78,17 @@ export function StatsSummary() { className="rounded-xl border border-border/30 bg-card/50 p-4" >
- +
+ +
{def.label}
) : ( -
- No poster +
+
+
+
+

+ {title} +

+
)} {/* Hover gradient overlay with metadata */} diff --git a/lib/services/discovery.ts b/lib/services/discovery.ts index af4a05f..c80d18a 100644 --- a/lib/services/discovery.ts +++ b/lib/services/discovery.ts @@ -16,6 +16,7 @@ export interface ContinueWatchingItem { id: string; title: string; posterPath: string | null; + backdropPath: string | null; type: string; }; nextEpisode: { @@ -23,6 +24,8 @@ export interface ContinueWatchingItem { seasonNumber: number; episodeNumber: number; name: string | null; + stillPath: string | null; + overview: string | null; } | null; lastWatchedAt: Date | null; totalEpisodes: number; @@ -108,6 +111,8 @@ export function getContinueWatchingFeed( seasonNumber: s.seasonNumber, episodeNumber: ep.episodeNumber, name: ep.name, + stillPath: ep.stillPath, + overview: ep.overview, }; } } @@ -119,6 +124,7 @@ export function getContinueWatchingFeed( id: title.id, title: title.title, posterPath: title.posterPath, + backdropPath: title.backdropPath, type: title.type, }, nextEpisode,