import type { HTMLAttributes, ReactNode } from "react"; import clsx from "clsx"; import { Play } from "lucide-react"; import { iconButtonClass } from "./buttonStyles"; import { MoreButton } from "./MoreButton"; import { SURFACE } from "./surfaces"; // The ONE media card (docs/DESIGN.md "Media card"): a YouTube video, a Plex movie, show, // season or episode — in the feed, the Plex library, Home's shelves and the media pages' strips — is // the same object: one glass frame holding the picture, then the title, then a meta line PINNED to the // frame's bottom edge. Cards in a grid row stretch to the row's height, so pinning the meta puts every // card's meta on one line whatever its title's length; a one-line title leaves room between the title // and the meta, never an empty line under it (the owner's pick, option C, 2026-09-26). The length is // a badge ON the picture, as YouTube draws it. // // The callers keep what differs (a YouTube picture is a link, a Plex picture is the card's play // button) and build it from the pieces here and in ./mediaCardStyles, so the look cannot drift // apart again. /** The Play drawn on a picture whose whole box is the play button: the `media` IconButton's look * (so it matches the YouTube card's real one), but only a picture of it — the box around it is the * control, and a button inside a button is not allowed. Only where a click PLAYS: a show or a season * opens a page, and a Play there would be a promise the click does not keep. */ export function MediaPlayGlyph({ small = false }: { small?: boolean }) { return ( ); } /** How far into it the viewer is: a bar along the picture's bottom edge. */ export function MediaProgress({ pct }: { pct: number }) { if (pct <= 0) return null; return (
); } export function MediaCard({ rootProps, dense = false, dim = false, picture, leading, title, meta, more, moreLabel = "", className, }: { /** The card's own attributes: its right-click menu, its keyboard-walk position, a test id. */ rootProps?: HTMLAttributes & Record; /** A narrow column (a small card, a rail, a poster grid): tighter padding and a smaller title. */ dense?: boolean; /** Fades the whole card (a watched video in the feed). */ dim?: boolean; picture: ReactNode; /** Beside the text, before the title (the YouTube channel's avatar). */ leading?: ReactNode; title: ReactNode; /** The line pinned to the frame's bottom edge; omit for a card with none. */ meta?: ReactNode; /** The card's "…": on touch it sits beside the title as a 44px target (the hover row's twin). */ more?: { props: Record; open: boolean }; /** The "…"'s name (the caller's words: this platform file speaks no feature namespace). */ moreLabel?: string; className?: string; }) { return (
{picture}
{leading}
{title} {meta &&
{meta}
}
{more && ( )}
); }