Implement achraf's portfolio

This commit is contained in:
achraf
2026-03-31 00:28:00 +02:00
parent fcd8d3d986
commit a4ee12732d
20 changed files with 2734 additions and 87 deletions

62
components/SafeImage.tsx Normal file
View File

@@ -0,0 +1,62 @@
"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)}
/>
);
}