import { forwardRef, type HTMLAttributes, type ImgHTMLAttributes, type ReactNode, } from 'react'; import { ResolvedAssetImage } from '../ResolvedAssetImage'; type PlatformMediaFrameAspect = | 'auto' | 'square' | 'standard' | 'landscape' | 'wide' | 'portrait' | 'video'; type PlatformMediaFrameSurface = | 'warm' | 'editorDark' | 'plain' | 'soft' | 'bright' | 'none' | 'bare'; type PlatformMediaFrameProps = Omit< HTMLAttributes, 'children' | 'className' > & { src?: string | null; fallbackSrc?: string | null; alt: string; fallbackLabel: string; aspect?: PlatformMediaFrameAspect; surface?: PlatformMediaFrameSurface; loading?: 'eager' | 'lazy'; refreshKey?: string | number | null; imageClassName?: string; imageProps?: Omit< ImgHTMLAttributes, 'alt' | 'className' | 'loading' | 'src' >; className?: string; fallbackClassName?: string; fallbackShellClassName?: string; fallbackContent?: ReactNode; children?: ReactNode; previewOverlay?: ReactNode; overlayInteractive?: boolean; }; const PLATFORM_MEDIA_FRAME_ASPECT_CLASS: Record< PlatformMediaFrameAspect, string > = { auto: '', square: 'aspect-square', standard: 'aspect-[4/3]', landscape: 'aspect-[16/9]', wide: 'aspect-[9/5]', portrait: 'aspect-[9/16]', video: 'aspect-video', }; const PLATFORM_MEDIA_FRAME_SURFACE_CLASS: Record< PlatformMediaFrameSurface, string > = { warm: 'border border-[var(--platform-subpanel-border)] bg-[radial-gradient(circle_at_top,rgba(255,255,255,0.22),transparent_42%),linear-gradient(180deg,rgba(204,117,76,0.9),rgba(223,127,64,0.82))]', editorDark: 'border border-white/10 bg-[radial-gradient(circle_at_top,rgba(56,189,248,0.16),transparent_48%),linear-gradient(180deg,rgba(19,24,39,0.95),rgba(8,10,17,0.92))]', plain: 'border border-[var(--platform-subpanel-border)] bg-[var(--platform-subpanel-fill)]', soft: 'border border-[var(--platform-subpanel-border)] bg-white/68', bright: 'border border-[var(--platform-subpanel-border)] bg-white/82', none: '', bare: 'bg-[var(--platform-subpanel-fill)]', }; /** * 平台媒体预览框。 * 统一承接图片预览、固定比例、fallback 文案和可选 overlay。 */ export const PlatformMediaFrame = forwardRef< HTMLDivElement, PlatformMediaFrameProps >(function PlatformMediaFrame( { src, fallbackSrc, alt, fallbackLabel, aspect = 'square', surface = 'warm', loading, refreshKey, imageClassName = 'h-full w-full object-cover', imageProps, className, fallbackClassName, fallbackShellClassName, fallbackContent, children, previewOverlay, overlayInteractive = false, ...containerProps }, ref, ) { const imageSrc = src?.trim() || fallbackSrc?.trim() || ''; const hasOverlay = Boolean(children) || Boolean(previewOverlay); return ( {imageSrc ? ( ) : ( {fallbackContent ?? fallbackLabel} )} {hasOverlay ? ( {previewOverlay} {children} ) : null} ); });