From 11143d0803ff5a29cb849ea5178e87dee4ec987b Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Thu, 5 Mar 2026 21:26:47 -0500 Subject: [PATCH] Declutter title page metadata row with cleaner visual hierarchy Replace mixed badge styles with a single icon type badge (with tooltip), CSS-based dot separators, collapsed genres with hover popover, status icons, and subtle TMDB link. Remove vote count for less noise. Co-Authored-By: Claude Opus 4.6 --- .../[id]/_components/genre-collapse.tsx | 41 ++++++++ .../[id]/_components/title-availability.tsx | 2 +- .../titles/[id]/_components/title-hero.tsx | 94 +++++++++++-------- .../titles/[id]/_components/type-badge.tsx | 25 +++++ 4 files changed, 120 insertions(+), 42 deletions(-) create mode 100644 app/(pages)/titles/[id]/_components/genre-collapse.tsx create mode 100644 app/(pages)/titles/[id]/_components/type-badge.tsx diff --git a/app/(pages)/titles/[id]/_components/genre-collapse.tsx b/app/(pages)/titles/[id]/_components/genre-collapse.tsx new file mode 100644 index 0000000..1804dcf --- /dev/null +++ b/app/(pages)/titles/[id]/_components/genre-collapse.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; + +export function GenreCollapse({ genres }: { genres: string[] }) { + if (genres.length === 0) return null; + if (genres.length === 1) return {genres[0]}; + + const remaining = genres.slice(1); + + return ( + + {genres[0]} + + 1 ? "s" : ""}`} + > + +{remaining.length} + + + {remaining.map((genre) => ( + + {genre} + + ))} + + + + ); +} diff --git a/app/(pages)/titles/[id]/_components/title-availability.tsx b/app/(pages)/titles/[id]/_components/title-availability.tsx index 526d8ab..4de422b 100644 --- a/app/(pages)/titles/[id]/_components/title-availability.tsx +++ b/app/(pages)/titles/[id]/_components/title-availability.tsx @@ -143,7 +143,7 @@ export function TitleAvailability({ if (Object.keys(availByType).length === 0) return null; return ( -
+

Where to Watch

diff --git a/app/(pages)/titles/[id]/_components/title-hero.tsx b/app/(pages)/titles/[id]/_components/title-hero.tsx index 8af1c55..1d073ac 100644 --- a/app/(pages)/titles/[id]/_components/title-hero.tsx +++ b/app/(pages)/titles/[id]/_components/title-hero.tsx @@ -1,9 +1,18 @@ +import { + IconCalendarEvent, + IconCircleCheck, + IconCircleX, + IconLoader, + IconRefresh, + IconStarFilled, +} from "@tabler/icons-react"; import Image from "next/image"; import type { ReactNode } from "react"; import { TmdbLogo } from "@/components/tmdb-logo"; -import { Badge } from "@/components/ui/badge"; import type { ColorPalette, ResolvedTitle } from "@/lib/types/title"; +import { GenreCollapse } from "./genre-collapse"; import { TrailerDialog } from "./trailer-dialog"; +import { TypeBadge } from "./type-badge"; export function TitleHero({ title, @@ -100,49 +109,37 @@ export function TitleHero({

{title.title}

-
- - {title.type} - - {title.contentRating && ( - - {title.contentRating} - - )} - {year && {year}} - {title.genres.length > 0 && ( - {title.genres.join(" · ")} - )} - {title.voteAverage != null && title.voteAverage > 0 && ( - - ★ {title.voteAverage.toFixed(1)} - {title.voteCount != null && ( - - ({title.voteCount.toLocaleString()}) +
+ +
+ {title.contentRating && {title.contentRating}} + {year && {year}} + {title.genres.length > 0 && ( + + )} + {title.voteAverage != null && title.voteAverage > 0 && ( + + + {title.voteAverage.toFixed(1)} + + )} + {title.status && + !(title.type === "movie" && title.status === "Released") && ( + + + {title.status} )} - - )} - {title.status && ( - - {title.status} - - )} - - - + + +
@@ -161,6 +158,21 @@ export function TitleHero({ ); } +const statusIcons: Record = { + Ended: , + Canceled: , + "Returning Series": , + "In Production": , + "Post Production": , + Planned: , + Pilot: , + Rumored: , +}; + +function StatusIcon({ status }: { status: string }) { + return statusIcons[status] ?? null; +} + function AmbientGlow({ palette }: { palette: ColorPalette | null }) { if (!palette) return null; diff --git a/app/(pages)/titles/[id]/_components/type-badge.tsx b/app/(pages)/titles/[id]/_components/type-badge.tsx new file mode 100644 index 0000000..becf0d6 --- /dev/null +++ b/app/(pages)/titles/[id]/_components/type-badge.tsx @@ -0,0 +1,25 @@ +"use client"; + +import { IconDeviceTv, IconMovie } from "@tabler/icons-react"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "@/components/ui/tooltip"; + +export function TypeBadge({ type }: { type: "movie" | "tv" }) { + const isMovie = type === "movie"; + + return ( + + + {isMovie ? ( + + ) : ( + + )} + + {isMovie ? "Movie" : "TV Series"} + + ); +}