Files
Genarrative/src/components/CustomWorldCoverArtwork.tsx

79 lines
2.8 KiB
TypeScript

import type { ReactNode } from 'react';
import { ResolvedAssetImage } from './ResolvedAssetImage';
import type { CustomWorldCoverRenderMode } from '../services/customWorldCover';
const COVER_PORTRAIT_CLASS_NAMES = [
'h-[54%] w-[24%] translate-y-[8%]',
'h-[68%] w-[30%]',
'h-[56%] w-[24%] translate-y-[10%]',
] as const;
type CustomWorldCoverArtworkProps = {
imageSrc?: string | null;
title: string;
fallbackLabel: string;
renderMode?: CustomWorldCoverRenderMode;
characterImageSrcs?: string[];
className?: string;
overlay?: ReactNode;
};
export function CustomWorldCoverArtwork({
imageSrc,
title,
fallbackLabel,
renderMode = 'image',
characterImageSrcs = [],
className = '',
overlay,
}: CustomWorldCoverArtworkProps) {
const coverCharacterImageSrcs = characterImageSrcs.slice(0, 3);
return (
<div
className={`relative overflow-hidden bg-[radial-gradient(circle_at_top,rgba(255,244,214,0.3),transparent_38%),linear-gradient(180deg,rgba(34,40,55,0.92),rgba(10,12,18,0.96))] ${className}`}
>
{imageSrc ? (
<ResolvedAssetImage
src={imageSrc}
alt={title}
loading="lazy"
className="absolute inset-0 h-full w-full object-cover"
/>
) : null}
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(8,10,14,0.04),rgba(8,10,14,0.26)_46%,rgba(8,10,14,0.82)_100%)]" />
{!imageSrc ? (
<div className="absolute inset-0 flex items-center justify-center px-4 text-center text-sm font-semibold tracking-[0.18em] text-zinc-300">
{fallbackLabel}
</div>
) : null}
{renderMode === 'scene_with_roles' && coverCharacterImageSrcs.length > 0 ? (
<>
<div className="absolute inset-x-0 bottom-0 h-[42%] bg-[linear-gradient(180deg,rgba(8,10,14,0)_0%,rgba(8,10,14,0.88)_100%)]" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 flex items-end justify-center gap-2 px-3 pb-2 sm:pb-3">
{coverCharacterImageSrcs.map((characterImageSrc, index) => (
<div
key={`${title}-cover-character-${index}-${characterImageSrc}`}
className={`overflow-hidden rounded-[1rem] border border-white/16 bg-[linear-gradient(180deg,rgba(255,255,255,0.14),rgba(255,255,255,0.04))] shadow-[0_12px_28px_rgba(0,0,0,0.4)] ${COVER_PORTRAIT_CLASS_NAMES[index] ?? COVER_PORTRAIT_CLASS_NAMES[1]}`}
>
<ResolvedAssetImage
src={characterImageSrc}
alt=""
loading="lazy"
className="h-full w-full object-cover object-top"
/>
</div>
))}
</div>
</>
) : null}
{overlay ? (
<div className="pointer-events-none absolute inset-0">{overlay}</div>
) : null}
</div>
);
}
export default CustomWorldCoverArtwork;