summaryrefslogtreecommitdiff
path: root/apps/web/src/components/ui/image-timeline-treatment.tsx
blob: 97a401b6201a7193fa1c79eb8518962aa44a7701 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"use client";

import { useState } from "react";
import { cn } from "@/lib/utils";
import type { BackgroundType } from "@/types/editor";

interface ImageTimelineTreatmentProps {
	src: string;
	alt: string;
	targetAspectRatio?: number; // Default to 16:9 for video
	className?: string;
	backgroundType?: BackgroundType;
	backgroundColor?: string;
}

export function ImageTimelineTreatment({
	src,
	alt,
	targetAspectRatio = 16 / 9,
	className,
	backgroundType = "blur",
	backgroundColor = "#000000",
}: ImageTimelineTreatmentProps) {
	const [imageLoaded, setImageLoaded] = useState(false);
	const [imageDimensions, setImageDimensions] = useState<{
		width: number;
		height: number;
	} | null>(null);

	const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {
		const img = e.currentTarget;
		setImageDimensions({
			width: img.naturalWidth,
			height: img.naturalHeight,
		});
		setImageLoaded(true);
	};

	const imageAspectRatio = imageDimensions
		? imageDimensions.width / imageDimensions.height
		: 1;

	const needsAspectRatioTreatment = imageAspectRatio !== targetAspectRatio;

	return (
		<div
			className={cn("relative overflow-hidden", className)}
			style={{ aspectRatio: targetAspectRatio }}
		>
			{/* Background Layer */}
			{needsAspectRatioTreatment && imageLoaded && (
				<>
					{backgroundType === "blur" && (
						<div className="absolute inset-0">
							<img
								src={src}
								alt=""
								className="w-full h-full object-cover filter blur-xl scale-110 opacity-60"
								aria-hidden="true"
							/>
							<div className="absolute inset-0 bg-black/20" />
						</div>
					)}

					{backgroundType === "mirror" && (
						<div className="absolute inset-0">
							<img
								src={src}
								alt=""
								className="w-full h-full object-cover opacity-30"
								aria-hidden="true"
							/>
						</div>
					)}

					{backgroundType === "color" && (
						<div className="absolute inset-0" style={{ backgroundColor }} />
					)}
				</>
			)}

			{/* Main Image Layer */}
			<div className="absolute inset-0">
				<img
					src={src}
					alt={alt}
					className="w-full h-full object-cover"
					onLoad={handleImageLoad}
				/>
			</div>

			{/* Loading state */}
			{!imageLoaded && (
				<div className="absolute inset-0 flex items-center justify-center bg-muted/30">
					<div className="animate-pulse text-xs text-muted-foreground">
						Loading...
					</div>
				</div>
			)}
		</div>
	);
}