Changes
This commit is contained in:
parent
7c3bc30e04
commit
a9b3a593e8
1 changed files with 64 additions and 73 deletions
|
|
@ -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) }}>
|
||||||
<div className="glass-card rounded-full p-1.5 ring-2 ring-primary/20">
|
{/* Center Avatar */}
|
||||||
<img
|
<div
|
||||||
src={avatar}
|
ref={avatarRef}
|
||||||
alt="Mohamad"
|
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center"
|
||||||
className="w-28 h-28 md:w-36 md:h-36 rounded-full"
|
>
|
||||||
/>
|
<div className="glass-card rounded-full p-1.5 ring-2 ring-primary/20">
|
||||||
|
<img
|
||||||
|
src={avatar}
|
||||||
|
alt="Mohamad"
|
||||||
|
className="w-24 h-24 md:w-32 md:h-32 rounded-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3 text-center whitespace-nowrap">
|
||||||
|
<h1 className="text-lg md:text-xl font-heading font-bold text-foreground">👋 Hey!</h1>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
I'm <span className="text-gradient font-semibold">Mohamad</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 text-center">
|
|
||||||
<h1 className="text-2xl md:text-3xl font-heading font-bold text-foreground">
|
|
||||||
👋 Hey There!
|
|
||||||
</h1>
|
|
||||||
<p className="text-muted-foreground text-sm mt-1">
|
|
||||||
I'm <span className="text-gradient font-semibold">Mohamad</span> — welcome to my space.
|
|
||||||
</p>
|
|
||||||
</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>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue