origin/apps/web/src/components/presentation/nice-img.tsx

81 lines
2.3 KiB
TypeScript
Executable File

import React, { CSSProperties, useRef, useState } from 'react';
type NiceImgProps = React.HTMLAttributes<HTMLDivElement> & // Allow div props
React.ImgHTMLAttributes<HTMLImageElement> & {
fallbackSrc?: string;
shape?: 'circle' | 'square'; // Shape of the avatar
size?: 'small' | 'default' | 'large' | number; // Size of the avatar
className?: string;
};
const getSize = (size: 'small' | 'default' | 'large' | number) => {
switch (size) {
case 'small':
return 24;
case 'large':
return 64;
case 'default':
default:
return 30;
}
};
const NiceImg: React.FC<NiceImgProps> = ({
src,
alt,
fallbackSrc,
shape = 'square',
size = 'default',
style,
className,
...props
}) => {
const [isError, setIsError] = useState(false);
const imgRef = useRef<HTMLImageElement>(null);
const dimension = typeof size === 'number' ? size : getSize(size);
const combinedStyle: CSSProperties = {
width: dimension,
height: dimension,
borderRadius: shape === 'circle' ? '50%' : '4px',
objectFit: 'cover',
...style,
};
const handleError = () => {
setIsError(true);
};
return (
<>
{isError || !src ? (
<div
style={{
...combinedStyle,
backgroundColor: '#f0f0f0',
lineHeight: `${dimension}px`,
textAlign: 'center'
}}
className={`bg-gray-100 overflow-hidden ${shape === 'circle' ? 'rounded-full' : 'rounded'} ${className}`}
{...props}
>
{fallbackSrc && <img src={fallbackSrc} alt="fallback" style={{ width: '100%', height: '100%' }} />}
</div>
) : (
<img
ref={imgRef}
{...props}
className={`${className} ${shape === 'circle' ? 'rounded-full' : ''}`}
src={src}
alt={alt}
style={combinedStyle}
onError={handleError}
/>
)}
</>
);
};
export default NiceImg;