63 lines
1.3 KiB
TypeScript
63 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
|
|
interface SafeImageProps {
|
|
src: string;
|
|
alt: string;
|
|
width?: number;
|
|
height?: number;
|
|
style?: React.CSSProperties;
|
|
fallbackLabel?: string; // initials or short label shown when image fails
|
|
containerStyle?: React.CSSProperties;
|
|
}
|
|
|
|
export default function SafeImage({
|
|
src,
|
|
alt,
|
|
width,
|
|
height,
|
|
style,
|
|
fallbackLabel,
|
|
containerStyle,
|
|
}: SafeImageProps) {
|
|
const [errored, setErrored] = useState(false);
|
|
|
|
if (errored) {
|
|
if (!fallbackLabel) return null;
|
|
return (
|
|
<div
|
|
style={{
|
|
width: width ?? 40,
|
|
height: height ?? 40,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
background: "#131720",
|
|
border: "1px solid #1c1f26",
|
|
fontFamily: "var(--font-bebas), sans-serif",
|
|
fontSize: `${Math.min((width ?? 40) * 0.38, 18)}px`,
|
|
color: "#c8a96e",
|
|
letterSpacing: "0.04em",
|
|
flexShrink: 0,
|
|
...containerStyle,
|
|
}}
|
|
>
|
|
{fallbackLabel}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img
|
|
src={src}
|
|
alt={alt}
|
|
width={width}
|
|
height={height}
|
|
style={style}
|
|
onError={() => setErrored(true)}
|
|
/>
|
|
);
|
|
}
|