This commit is contained in:
gpt-engineer-app[bot] 2026-03-07 21:36:31 +00:00
parent 7c3bc30e04
commit a9b3a593e8

View file

@ -18,6 +18,7 @@ const Index = () => {
const [lines, setLines] = useState<{ x1: number; y1: number; x2: number; y2: number }[]>([]); const [lines, setLines] = useState<{ x1: number; y1: number; x2: number; y2: number }[]>([]);
const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
const [dims, setDims] = useState({ w: 0, h: 0 });
const updateLines = useCallback(() => { const updateLines = useCallback(() => {
if (!containerRef.current || !avatarRef.current) return; if (!containerRef.current || !avatarRef.current) return;
@ -25,13 +26,17 @@ const Index = () => {
const avatarRect = avatarRef.current.getBoundingClientRect(); const avatarRect = avatarRef.current.getBoundingClientRect();
const cx = avatarRect.left + avatarRect.width / 2 - containerRect.left; const cx = avatarRect.left + avatarRect.width / 2 - containerRect.left;
const cy = avatarRect.top + avatarRect.height / 2 - containerRect.top; const cy = avatarRect.top + avatarRect.height / 2 - containerRect.top;
setDims({ w: containerRect.width, h: containerRect.height });
const newLines = cardRefs.current.map((card) => { const newLines = cardRefs.current.map((card) => {
if (!card) return { x1: cx, y1: cy, x2: cx, y2: cy }; if (!card) return { x1: cx, y1: cy, x2: cx, y2: cy };
const cardRect = card.getBoundingClientRect(); const cardRect = card.getBoundingClientRect();
const cardCx = cardRect.left + cardRect.width / 2 - containerRect.left; return {
const cardCy = cardRect.top + cardRect.height / 2 - containerRect.top; x1: cx,
return { x1: cx, y1: cy, x2: cardCx, y2: cardCy }; y1: cy,
x2: cardRect.left + cardRect.width / 2 - containerRect.left,
y2: cardRect.top + cardRect.height / 2 - containerRect.top,
};
}); });
setLines(newLines); setLines(newLines);
}, []); }, []);
@ -40,29 +45,30 @@ const Index = () => {
updateLines(); updateLines();
const timer = setTimeout(() => setMounted(true), 100); const timer = setTimeout(() => setMounted(true), 100);
window.addEventListener('resize', updateLines); window.addEventListener('resize', updateLines);
return () => { return () => { window.removeEventListener('resize', updateLines); clearTimeout(timer); };
window.removeEventListener('resize', updateLines);
clearTimeout(timer);
};
}, [updateLines]); }, [updateLines]);
useEffect(() => { useEffect(() => {
// Re-calc after fonts/images load const t = setTimeout(updateLines, 500);
const timer = setTimeout(updateLines, 500); return () => clearTimeout(t);
return () => clearTimeout(timer);
}, [updateLines]); }, [updateLines]);
const handleMouseMove = useCallback((e: React.MouseEvent) => { const handleMouseMove = useCallback((e: React.MouseEvent) => {
if (!containerRef.current) return; setMousePos({ x: e.clientX, y: e.clientY });
const rect = containerRef.current.getBoundingClientRect();
setMousePos({ x: e.clientX - rect.left, y: e.clientY - rect.top });
}, []); }, []);
// On mobile, use a smaller radius
const isMobile = dims.w < 640;
const radius = isMobile ? 140 : 220;
const count = items.length;
// Start from top (-90deg) and spread evenly
const angleOffset = -90;
return ( return (
<div <div
ref={containerRef} ref={containerRef}
onMouseMove={handleMouseMove} onMouseMove={handleMouseMove}
className="min-h-screen bg-background relative overflow-hidden flex flex-col items-center justify-start py-10 md:py-16 px-4" className="min-h-screen bg-background relative overflow-hidden flex items-center justify-center"
> >
{/* Global mouse glow */} {/* Global mouse glow */}
<div <div
@ -97,100 +103,85 @@ const Index = () => {
</defs> </defs>
{lines.map((line, i) => ( {lines.map((line, i) => (
<g key={i}> <g key={i}>
{/* Glow line */}
<line <line
x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2} x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2}
stroke="hsl(25 95% 55% / 0.1)" stroke="hsl(25 95% 55% / 0.08)"
strokeWidth="4" strokeWidth="4"
filter="url(#glow)" filter="url(#glow)"
/> />
{/* Main line */}
<line <line
x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2} x1={line.x1} y1={line.y1} x2={line.x2} y2={line.y2}
stroke="url(#lineGrad)" stroke="url(#lineGrad)"
strokeWidth="1.5" strokeWidth="1.5"
strokeDasharray="6 4" strokeDasharray="6 4"
/> />
{/* End dot on card */}
<circle cx={line.x2} cy={line.y2} r="3" fill="hsl(25 95% 55% / 0.4)" /> <circle cx={line.x2} cy={line.y2} r="3" fill="hsl(25 95% 55% / 0.4)" />
</g> </g>
))} ))}
{/* Center dot */}
{lines.length > 0 && ( {lines.length > 0 && (
<circle cx={lines[0]?.x1} cy={lines[0]?.y1} r="5" fill="hsl(25 95% 55% / 0.6)" /> <circle cx={lines[0]?.x1} cy={lines[0]?.y1} r="5" fill="hsl(25 95% 55% / 0.6)" />
)} )}
</svg> </svg>
{/* Center Avatar Hub */} {/* Hub container - centered */}
<div ref={avatarRef} className="relative z-10 mb-8 md:mb-12 flex flex-col items-center"> <div className="relative z-10" style={{ width: radius * 2 + (isMobile ? 120 : 160), height: radius * 2 + (isMobile ? 120 : 160) }}>
{/* Center Avatar */}
<div
ref={avatarRef}
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center"
>
<div className="glass-card rounded-full p-1.5 ring-2 ring-primary/20"> <div className="glass-card rounded-full p-1.5 ring-2 ring-primary/20">
<img <img
src={avatar} src={avatar}
alt="Mohamad" alt="Mohamad"
className="w-28 h-28 md:w-36 md:h-36 rounded-full" className="w-24 h-24 md:w-32 md:h-32 rounded-full"
/> />
</div> </div>
<div className="mt-4 text-center"> <div className="mt-3 text-center whitespace-nowrap">
<h1 className="text-2xl md:text-3xl font-heading font-bold text-foreground"> <h1 className="text-lg md:text-xl font-heading font-bold text-foreground">👋 Hey!</h1>
👋 Hey There! <p className="text-xs text-muted-foreground">
</h1> I'm <span className="text-gradient font-semibold">Mohamad</span>
<p className="text-muted-foreground text-sm mt-1">
I'm <span className="text-gradient font-semibold">Mohamad</span> welcome to my space.
</p> </p>
</div> </div>
</div> </div>
{/* Cards arranged around */} {/* Orbiting cards */}
<div className="relative z-10 w-full max-w-3xl"> {items.map((item, i) => {
{/* Top row - 3 cards */} const angle = ((360 / count) * i + angleOffset) * (Math.PI / 180);
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3 md:gap-4 mb-3 md:mb-4"> const x = Math.cos(angle) * radius;
{items.slice(0, 3).map((item, i) => ( const y = Math.sin(angle) * radius;
const cardW = isMobile ? 110 : 130;
const cardH = isMobile ? 80 : 90;
return (
<a <a
key={item.label} key={item.label}
ref={(el) => { cardRefs.current[i] = el; }} ref={(el) => { cardRefs.current[i] = el; }}
href={item.href} href={item.href}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="block" className="absolute"
style={{
left: `calc(50% + ${x}px - ${cardW / 2}px)`,
top: `calc(50% + ${y}px - ${cardH / 2}px)`,
width: cardW,
}}
> >
<GlassCard className="p-4 md:p-5 h-full link-arrow-parent cursor-pointer"> <GlassCard className="p-3 md:p-4 link-arrow-parent cursor-pointer">
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<item.icon className="w-5 h-5 text-primary mb-2" /> <item.icon className="w-4 h-4 text-primary mb-1.5" />
<ExternalLink className="w-3.5 h-3.5 text-muted-foreground link-arrow" /> <ExternalLink className="w-3 h-3 text-muted-foreground link-arrow" />
</div> </div>
<p className="font-heading font-semibold text-foreground text-sm md:text-base">{item.label}</p> <p className="font-heading font-semibold text-foreground text-xs md:text-sm leading-tight">{item.label}</p>
<p className="text-xs text-muted-foreground mt-0.5">{item.desc}</p> <p className="text-[10px] text-muted-foreground mt-0.5 leading-tight">{item.desc}</p>
</GlassCard> </GlassCard>
</a> </a>
))} );
</div> })}
{/* Bottom row - 2 cards centered */}
<div className="grid grid-cols-2 gap-3 md:gap-4 max-w-md mx-auto">
{items.slice(3).map((item, i) => (
<a
key={item.label}
ref={(el) => { cardRefs.current[i + 3] = el; }}
href={item.href}
target="_blank"
rel="noopener noreferrer"
className="block"
>
<GlassCard className="p-4 md:p-5 h-full link-arrow-parent cursor-pointer">
<div className="flex items-start justify-between">
<item.icon className="w-5 h-5 text-primary mb-2" />
<ExternalLink className="w-3.5 h-3.5 text-muted-foreground link-arrow" />
</div>
<p className="font-heading font-semibold text-foreground text-sm md:text-base">{item.label}</p>
<p className="text-xs text-muted-foreground mt-0.5">{item.desc}</p>
</GlassCard>
</a>
))}
</div>
</div> </div>
{/* Footer */} {/* Footer */}
<p className="relative z-10 text-center text-xs text-muted-foreground font-mono mt-10"> <p className="absolute bottom-4 left-1/2 -translate-x-1/2 text-xs text-muted-foreground font-mono z-10">
damaj.tech damaj.tech
</p> </p>
</div> </div>