feat: so much stuff

This commit is contained in:
Maze Winther
2025-06-22 19:28:03 +02:00
parent e22aa6620c
commit 6ee16f9df8
9 changed files with 1229 additions and 83 deletions

View File

@ -0,0 +1,101 @@
"use client";
import { useState } from "react";
import { cn } from "@/lib/utils";
interface ImageTimelineTreatmentProps {
src: string;
alt: string;
targetAspectRatio?: number; // Default to 16:9 for video
className?: string;
backgroundType?: "blur" | "mirror" | "color";
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>
);
}