import type { JellyItem } from './shared';
import { Link, useLocation, useSearchParams } from 'react-router';
import { Check, Play } from 'lucide-react';
import { useClient } from 'hooks/useClient';
import { episodeLabel, itemHref, posterUrl, progressPercent, subtitleFor, thumbUrl } from './shared';
// One tile in a shelf or a grid.
//
// It is a real to `?item=` — cmd-click opens the detail in a new tab, the URL says what is open,
// and the back button closes it. The play button is a SIBLING anchor rather than nested inside, because an
// anchor inside an anchor is not valid HTML and browsers resolve it by dropping one of them.
type MediaCardProps = { item: JellyItem; wide?: boolean };
export const MediaCard = ({ item, wide = false }: MediaCardProps) => {
const { token } = useClient();
const { pathname } = useLocation();
const [params] = useSearchParams();
const src = wide ? thumbUrl(item, token) : posterUrl(item, token);
const progress = progressPercent(item);
const watched = item.UserData?.Played === true;
const unplayed = item.UserData?.UnplayedItemCount ?? 0;
const subtitle = subtitleFor(item);
return (
);
};
/** A horizontal shelf. Overflow scrolls rather than wrapping — a shelf that wraps is a grid with a title. */
export const MediaShelf = ({ title, items, wide }: { title: string; items: JellyItem[]; wide?: boolean }) => {
if (!items.length) return null;
return (
{title}
{items.map((item) => (
))}
);
};
/** A wrapping grid. Column count comes from a min tile width, so it works in a panel of any size. */
export const MediaGrid = ({ items, wide }: { items: JellyItem[]; wide?: boolean }) => (