feat(29-02): create GearImage component for fit-within rendering

Renders images with object-contain by default (letterbox/pillarbox),
object-cover when cover prop is set, or CSS transform when crop
values are present. Parent container uses dominant color background.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 19:57:54 +02:00
parent 34804731a1
commit 06d3984161

View File

@@ -0,0 +1,65 @@
interface GearImageProps {
src: string;
alt: string;
dominantColor?: string | null;
cropZoom?: number | null;
cropX?: number | null;
cropY?: number | null;
className?: string;
cover?: boolean;
}
export function GearImage({
src,
alt,
dominantColor,
cropZoom,
cropX,
cropY,
className = "",
cover = false,
}: GearImageProps) {
const hasCrop = cropZoom != null && cropZoom > 1;
if (cover) {
return (
<img
src={src}
alt={alt}
className={`w-full h-full object-cover ${className}`}
/>
);
}
if (hasCrop) {
return (
<img
src={src}
alt={alt}
className={`w-full h-full object-cover ${className}`}
style={{
transform: `scale(${cropZoom}) translate(${cropX ?? 0}%, ${cropY ?? 0}%)`,
transformOrigin: "center center",
}}
/>
);
}
return (
<img
src={src}
alt={alt}
className={`w-full h-full object-contain ${className}`}
/>
);
}
/**
* Returns the background color for an image container.
* Uses the dominant color if available, otherwise a neutral fallback.
*/
export function imageContainerBg(
dominantColor?: string | null,
): string | undefined {
return dominantColor || "#f3f4f6";
}