feat(player): a video's related videos, on demand beside it
The player shows what YouTube lists beside the video, without what the user has watched or hidden. Wide, a Related tab beside the description; stacked, a button beside the info opens them in a drawer. A row plays in the same player (Back returns) and the list stays the opened video's. A switch picks on-topic or Hungarian-trending lists, kept on the account. Each related row says whether the user follows its channel; the row is the video card's narrow form with its whole menu. VideoMenu moves to features/video, where the player can reach it.
This commit is contained in:
@@ -374,6 +374,8 @@ function VideoCard({
|
||||
menuOpen = false,
|
||||
navIndex,
|
||||
shelf = false,
|
||||
narrow = false,
|
||||
channelMark,
|
||||
}: {
|
||||
video: Video;
|
||||
view: FeedView;
|
||||
@@ -397,6 +399,12 @@ function VideoCard({
|
||||
navIndex?: number;
|
||||
/** On a shelf (a horizontal strip): a one-line title over the channel alone (ui/mediaCardStyles). */
|
||||
shelf?: boolean;
|
||||
/** The thumbnailed row in a side panel's ~20rem column: a smaller picture, and the "…" alone at the
|
||||
* row's end — the hover toggles leave no room for the title there, and every one of them is a row
|
||||
* of the menu. */
|
||||
narrow?: boolean;
|
||||
/** Something the list says about the channel (a "followed" mark), set before its name. */
|
||||
channelMark?: ReactNode;
|
||||
}) {
|
||||
const { t, i18n } = useTranslation();
|
||||
const lang = i18n.language;
|
||||
@@ -610,15 +618,46 @@ function VideoCard({
|
||||
const textBlock = (
|
||||
<>
|
||||
{title}
|
||||
<div className="mt-0.5">{channelLink}</div>
|
||||
<div className="mt-0.5">
|
||||
{channelMark ? (
|
||||
<div className="flex items-center gap-1 min-w-0">
|
||||
{channelMark}
|
||||
<div className="min-w-0">{channelLink}</div>
|
||||
</div>
|
||||
) : (
|
||||
channelLink
|
||||
)}
|
||||
</div>
|
||||
<div className="text-xs text-muted mt-0.5">
|
||||
{views}
|
||||
{views && " · "}
|
||||
{published}
|
||||
{/* The narrow row keeps the relative time and moves the date into its tooltip, as the small
|
||||
card does: in a 20rem panel the full pair wrapped to a line of its own. */}
|
||||
{narrow ? <RelativeTime at={video.published_at} /> : published}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
if (spec.family === "row" && narrow) {
|
||||
return (
|
||||
<div
|
||||
data-testid="video-card"
|
||||
data-video-id={video.id}
|
||||
{...menuProps?.(video)}
|
||||
{...(navIndex !== undefined && navItemAttrs(navIndex))}
|
||||
className={clsx(rowShell, "flex gap-2 p-1.5", watched && "opacity-55")}
|
||||
>
|
||||
<Thumb video={video} className="aspect-video shrink-0 w-24" onOpen={onOpen} small />
|
||||
<div className="min-w-0 flex-1 flex flex-col">{textBlock}</div>
|
||||
{more && (
|
||||
<div className="shrink-0 self-start">
|
||||
<MoreButton label={t("card.menu.more")} expanded={more.open} menuProps={more.props} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (spec.family === "row") {
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user