2022-05-08 11:34:14 +02:00

199 lines
6.2 KiB
TypeScript

import { useAppLayout } from "contexts/AppLayoutContext";
import {
DatePickerFragment,
PricePickerFragment,
UploadImageFragment,
} from "graphql/generated";
import Link from "next/link";
import { AppStaticProps } from "helpers/getAppStaticProps";
import {
prettyDate,
prettyDuration,
prettyPrice,
prettyShortenNumber,
} from "helpers/helpers";
import Chip from "./Chip";
import Img, { ImageQuality } from "./Img";
interface Props {
thumbnail?: UploadImageFragment | string | null | undefined;
thumbnailAspectRatio?: string;
href: string;
pre_title?: string | null | undefined;
title: string | null | undefined;
subtitle?: string | null | undefined;
description?: string | null | undefined;
topChips?: string[];
bottomChips?: string[];
keepInfoVisible?: boolean;
metadata?: {
currencies?: AppStaticProps["currencies"];
release_date?: DatePickerFragment | null;
price?: PricePickerFragment | null;
views?: number;
author?: string;
position: "Bottom" | "Top";
};
hoverlay?:
| {
__typename: "Video";
duration: number;
}
| { __typename: "anotherHoverlayName" };
}
export default function ThumbnailPreview(props: Props): JSX.Element {
const {
href,
thumbnail,
pre_title,
title,
subtitle,
description,
topChips,
bottomChips,
keepInfoVisible,
thumbnailAspectRatio,
metadata,
hoverlay,
} = props;
const appLayout = useAppLayout();
const metadataJSX =
metadata && (metadata.release_date || metadata.price) ? (
<div className="flex flex-row flex-wrap gap-x-3 w-full">
{metadata.release_date && (
<p className="mobile:text-xs text-sm">
<span className="material-icons !text-base translate-y-[.15em] mr-1">
event
</span>
{prettyDate(metadata.release_date)}
</p>
)}
{metadata.price && metadata.currencies && (
<p className="mobile:text-xs text-sm justify-self-end">
<span className="material-icons !text-base translate-y-[.15em] mr-1">
shopping_cart
</span>
{prettyPrice(
metadata.price,
metadata.currencies,
appLayout.currency
)}
</p>
)}
{metadata.views && (
<p className="mobile:text-xs text-sm">
<span className="material-icons !text-base translate-y-[.15em] mr-1">
visibility
</span>
{prettyShortenNumber(metadata.views)}
</p>
)}
{metadata.author && (
<p className="mobile:text-xs text-sm">
<span className="material-icons !text-base translate-y-[.15em] mr-1">
person
</span>
{metadata.author}
</p>
)}
</div>
) : (
<></>
);
return (
<Link href={href} passHref>
<div
className="drop-shadow-shade-xl cursor-pointer grid items-end
fine:[--cover-opacity:0] hover:[--cover-opacity:1] hover:scale-[1.02]
[--bg-opacity:0] hover:[--bg-opacity:0.5] [--play-opacity:0]
hover:[--play-opacity:100] transition-transform"
>
{thumbnail ? (
<div className="relative">
<Img
className={
keepInfoVisible
? "rounded-t-md"
: "rounded-md coarse:rounded-b-none"
}
image={thumbnail}
quality={ImageQuality.Medium}
/>
{hoverlay && hoverlay.__typename === "Video" && (
<>
<div
className="absolute inset-0 text-light grid
place-content-center drop-shadow-shade-lg bg-shade
bg-opacity-[var(--bg-opacity)] transition-colors"
>
<span
className="material-icons text-6xl
opacity-[var(--play-opacity)] transition-opacity"
>
play_circle_outline
</span>
</div>
<div
className="absolute right-2 bottom-2 text-light bg-black
bg-opacity-60 px-2 rounded-full"
>
{prettyDuration(hoverlay.duration)}
</div>
</>
)}
</div>
) : (
<div
style={{ aspectRatio: thumbnailAspectRatio }}
className={`w-full bg-light ${
keepInfoVisible
? "rounded-t-md"
: "rounded-md coarse:rounded-b-none"
}`}
></div>
)}
<div
className={`linearbg-obi ${
keepInfoVisible
? "-mt-[0.3333em]"
: `fine:drop-shadow-shade-lg fine:absolute coarse:rounded-b-md
bottom-2 -inset-x-0.5 opacity-[var(--cover-opacity)]`
} transition-opacity z-20 grid p-4 gap-2`}
>
{metadata?.position === "Top" && metadataJSX}
{topChips && topChips.length > 0 && (
<div className="grid grid-flow-col gap-1 overflow-hidden place-content-start">
{topChips.map((text, index) => (
<Chip key={index}>{text}</Chip>
))}
</div>
)}
<div className="my-1">
{pre_title && <p className="leading-none mb-1">{pre_title}</p>}
{title && (
<p className="font-headers text-lg leading-none">{title}</p>
)}
{subtitle && <p className="leading-none">{subtitle}</p>}
</div>
{description && <p>{description}</p>}
{bottomChips && bottomChips.length > 0 && (
<div className="grid grid-flow-col gap-1 overflow-hidden place-content-start">
{bottomChips.map((text, index) => (
<Chip key={index} className="text-sm">
{text}
</Chip>
))}
</div>
)}
{metadata?.position === "Bottom" && metadataJSX}
</div>
</div>
</Link>
);
}