Files
timmypidashev.dev/src/components/about/intro.tsx
T

108 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useRef, useState } from "react";
import { ChevronDown } from "lucide-react";
export default function Intro() {
const [visible, setVisible] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const rect = el.getBoundingClientRect();
const inView = rect.top < window.innerHeight && rect.bottom > 0;
const isReload = performance.getEntriesByType?.("navigation")?.[0]?.type === "reload";
if (inView && isReload) {
setVisible(true);
return;
}
if (inView) {
// Fresh navigation — animate in
requestAnimationFrame(() => setVisible(true));
return;
}
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setVisible(true);
observer.disconnect();
}
},
{ threshold: 0.2 }
);
observer.observe(el);
return () => observer.disconnect();
}, []);
const scrollToNext = () => {
const nextSection = document.querySelector("section")?.nextElementSibling;
if (nextSection) {
const offset = (nextSection as HTMLElement).offsetTop - (window.innerHeight - (nextSection as HTMLElement).offsetHeight) / 2;
window.scrollTo({ top: offset, behavior: "smooth" });
}
};
const anim = (delay: number) =>
({
opacity: visible ? 1 : 0,
transform: visible ? "translateY(0)" : "translateY(20px)",
transition: `all 0.7s ease-out ${delay}ms`,
}) as React.CSSProperties;
return (
<div ref={ref} className="w-full max-w-4xl px-4">
<div className="space-y-8 md:space-y-12">
<div className="flex flex-col sm:flex-row items-center sm:items-center justify-center gap-8 sm:gap-16">
<div
className="w-32 h-32 sm:w-48 sm:h-48 shrink-0"
style={anim(0)}
>
<img
src="/me.jpeg"
alt="Timothy Pidashev"
className="rounded-lg object-cover w-full h-full ring-2 ring-yellow-bright hover:ring-orange-bright transition-all duration-300"
/>
</div>
<div className="text-center sm:text-left space-y-4 sm:space-y-6" style={anim(150)}>
<h2 className="text-xl sm:text-5xl font-bold text-yellow-bright">
Timothy Pidashev
</h2>
<div className="text-sm sm:text-xl text-foreground/70 space-y-2 sm:space-y-3">
<p className="flex items-center justify-center font-bold sm:justify-start gap-2" style={anim(300)}>
<span className="text-blue">Software Systems Engineer</span>
</p>
<p className="flex items-center justify-center font-bold sm:justify-start gap-2" style={anim(450)}>
<span className="text-green">Open Source Enthusiast</span>
</p>
<p className="flex items-center justify-center font-bold sm:justify-start gap-2" style={anim(600)}>
<span className="text-yellow">Coffee Connoisseur</span>
</p>
</div>
</div>
</div>
<div className="space-y-8" style={anim(750)}>
<p className="text-foreground/80 text-center text-base sm:text-2xl italic max-w-3xl mx-auto font-medium">
"Turning coffee into code" isn't just a clever phrase
<span className="text-aqua-bright"> it's how I approach each project:</span>
<span className="text-purple-bright"> methodically,</span>
<span className="text-blue-bright"> with attention to detail,</span>
<span className="text-green-bright"> and a refined process.</span>
</p>
<div className="flex justify-center" style={anim(900)}>
<button
onClick={scrollToNext}
className="text-foreground/50 hover:text-yellow-bright transition-colors duration-300"
aria-label="Scroll to next section"
>
<ChevronDown size={40} className="animate-bounce" />
</button>
</div>
</div>
</div>
</div>
);
}