portfolio / src /components /AboutSection.tsx
jashdoshi77's picture
changed content form web developemetn to data sceince
251578d
"use client";
import { useRef, useLayoutEffect, useEffect, useState, useCallback } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
if (typeof window !== "undefined") {
gsap.registerPlugin(ScrollTrigger);
}
export default function AboutSection() {
const sectionRef = useRef<HTMLElement>(null);
const clippedContentRef = useRef<HTMLDivElement>(null);
const headerWrapperRef = useRef<HTMLDivElement>(null);
const heroLine1Ref = useRef<HTMLDivElement>(null);
const heroLine2Ref = useRef<HTMLDivElement>(null);
const storyBlock1Ref = useRef<HTMLDivElement>(null);
const storyBlock2Ref = useRef<HTMLDivElement>(null);
const stripsWrapperRef = useRef<HTMLDivElement>(null);
const [mounted, setMounted] = useState(false);
const [isMobile, setIsMobile] = useState(false);
// --- Hover reveal circle ---
const revealAreaRef = useRef<HTMLDivElement>(null);
const revealRef = useRef<HTMLDivElement>(null);
const circlePos = useRef({ x: -300, y: -300 });
const currentPos = useRef({ x: -300, y: -300 });
const isHovering = useRef(false);
const circleSize = 300;
const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
const rect = revealAreaRef.current?.getBoundingClientRect();
if (!rect) return;
circlePos.current = {
x: e.clientX - rect.left,
y: e.clientY - rect.top,
};
isHovering.current = true;
}, []);
const handleMouseLeave = useCallback(() => {
isHovering.current = false;
}, []);
// Smooth animation loop for the reveal circle
useEffect(() => {
let animId: number;
const animate = () => {
const reveal = revealRef.current;
if (!reveal) { animId = requestAnimationFrame(animate); return; }
currentPos.current.x += (circlePos.current.x - currentPos.current.x) * 0.12;
currentPos.current.y += (circlePos.current.y - currentPos.current.y) * 0.12;
const x = currentPos.current.x;
const y = currentPos.current.y;
const r = isHovering.current ? circleSize / 2 : 0;
reveal.style.clipPath = `circle(${r}px at ${x}px ${y}px)`;
animId = requestAnimationFrame(animate);
};
animId = requestAnimationFrame(animate);
return () => cancelAnimationFrame(animId);
}, []);
useEffect(() => {
setMounted(true);
const checkMobile = () => setIsMobile(window.innerWidth < 768);
checkMobile();
window.addEventListener('resize', checkMobile);
return () => window.removeEventListener('resize', checkMobile);
}, []);
useLayoutEffect(() => {
if (!mounted) return;
const isMobile = window.innerWidth < 768;
const insetX = isMobile ? "6%" : "14%";
const radius = isMobile ? "16px" : "28px";
const ctx = gsap.context(() => {
gsap.fromTo(
clippedContentRef.current,
{
clipPath: `inset(0 ${insetX} 0 ${insetX} round ${radius})`,
},
{
clipPath: "inset(0 0% 0 0% round 0px)",
ease: "power2.inOut",
scrollTrigger: {
trigger: sectionRef.current,
start: "top 85%",
end: "top 5%",
scrub: 0.6,
},
}
);
gsap.to(".about-header-marquee", {
xPercent: -50,
repeat: -1,
duration: 20,
ease: "linear",
});
gsap.to(".about-strip-1-marquee", {
xPercent: -50,
repeat: -1,
duration: 25,
ease: "linear",
});
gsap.fromTo(".about-strip-2-marquee",
{ xPercent: -50 },
{
xPercent: 0,
repeat: -1,
duration: 25,
ease: "linear",
}
);
gsap.set(headerWrapperRef.current, { opacity: 0, y: 30 });
gsap.set(heroLine1Ref.current, { opacity: 0, y: 100, filter: "blur(10px)" });
gsap.set(heroLine2Ref.current, { opacity: 0, y: 100, filter: "blur(10px)" });
gsap.set(storyBlock1Ref.current, { opacity: 0, x: -100, filter: "blur(8px)" });
gsap.set(storyBlock2Ref.current, { opacity: 0, x: 100, filter: "blur(8px)" });
gsap.set(stripsWrapperRef.current, { opacity: 0, y: 60 });
gsap.to(headerWrapperRef.current, {
opacity: 1,
y: 0,
ease: "power2.out",
scrollTrigger: {
trigger: sectionRef.current,
start: "top 90%",
end: "top 50%",
scrub: 0.3,
},
});
const tl = gsap.timeline({
scrollTrigger: {
trigger: sectionRef.current,
start: "top top",
end: isMobile ? "+=900" : "+=1500",
scrub: 1,
pin: true,
anticipatePin: 1,
pinSpacing: true,
},
});
tl.to(heroLine1Ref.current, { opacity: 1, y: 0, filter: "blur(0px)", duration: 0.25, ease: "power3.out" }, 0);
tl.to(heroLine2Ref.current, { opacity: 1, y: 0, filter: "blur(0px)", duration: 0.25, ease: "power3.out" }, 0.15);
tl.to(storyBlock1Ref.current, { opacity: 1, x: 0, filter: "blur(0px)", duration: 0.25, ease: "power3.out" }, 0.35);
tl.to(storyBlock2Ref.current, { opacity: 1, x: 0, filter: "blur(0px)", duration: 0.25, ease: "power3.out" }, 0.50);
tl.to(stripsWrapperRef.current, { opacity: 1, y: 0, duration: 0.25, ease: "power3.out" }, 0.70);
}, sectionRef);
return () => ctx.revert();
}, [mounted]);
const marqueeText = "DATA SCIENTIST ✦ PYTHON BACKEND DEVELOPER ✦ AI ENTHUSIAST ✦ PROBLEM SOLVER ✦ ";
const strip1Text = "★ Driven by Curiosity, Powered by Data ★ Machine Learning Solutions ★ Predictive Analytics ★ AI-Driven Insights ★ ";
const strip2Text = "★ Data Quality ★ Model Accuracy ★ Scalable Pipelines ★ Statistical Analysis ★ Deep Learning ★ Python Engineering ★ ";
return (
<section
id="about"
ref={sectionRef}
className="relative bg-[#050505] overflow-visible"
>
{/* Clipped content — clip-path creates the expanding box effect */}
<div
ref={clippedContentRef}
className="relative"
style={{
background: "linear-gradient(180deg, #0c0c0c 0%, #0a0a0a 50%, #080808 100%)",
}}
>
{/* Subtle top edge glow inside the clipped box */}
<div
className="absolute top-0 left-[10%] right-[10%] h-px pointer-events-none z-20"
style={{
background: "linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.12) 50%, transparent 100%)",
}}
/>
{/* Content */}
<div className="relative z-10 min-h-screen pt-16">
{/* Large Header Marquee Banner */}
<div ref={headerWrapperRef} className="py-3 md:py-4 overflow-hidden border-b border-white/5">
<div className="about-header-marquee flex whitespace-nowrap" style={{ width: "200%" }}>
<span className="text-2xl md:text-4xl lg:text-6xl font-black tracking-tight text-white/90 uppercase">
{marqueeText.repeat(6)}
</span>
</div>
</div>
{/* Hero + Story area — this is where the reveal mask lives */}
<div
ref={revealAreaRef}
className="relative"
onMouseMove={isMobile ? undefined : handleMouseMove}
onMouseLeave={isMobile ? undefined : handleMouseLeave}
>
{/* Normal layer (white text on dark bg) */}
<div className="px-6 md:px-12 lg:px-20 xl:px-32 py-8 md:py-12">
<div className="mb-16 md:mb-24">
<div ref={heroLine1Ref}>
<h2 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-extralight text-white tracking-tighter leading-[0.95]">
I extract insights that
</h2>
</div>
<div ref={heroLine2Ref}>
<h2 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl tracking-tighter leading-[0.95]">
<span className="font-black text-white">drive</span>
<span className="font-extralight text-white/50"> real </span>
<span className="font-black text-transparent bg-clip-text bg-gradient-to-r from-white via-neutral-300 to-white/70">decisions</span>
</h2>
</div>
</div>
<div className="grid md:grid-cols-2 gap-8 md:gap-16 mb-16 md:mb-24">
<div ref={storyBlock1Ref} className="space-y-4">
<p className="text-white/30 text-xs uppercase tracking-[0.3em] font-medium">My Journey</p>
<p className="text-lg md:text-xl lg:text-2xl text-white/80 font-light leading-relaxed">
Started as a <span className="text-white font-medium">curious teenager</span> exploring datasets,
I&apos;ve evolved into a data scientist who obsesses over every feature
and every decimal of model accuracy.
</p>
</div>
<div ref={storyBlock2Ref} className="space-y-4">
<p className="text-white/30 text-xs uppercase tracking-[0.3em] font-medium">My Approach</p>
<p className="text-lg md:text-xl lg:text-2xl text-white/80 font-light leading-relaxed">
I believe the best data solutions are the ones that
<span className="text-white font-medium"> speak for themselves</span>—clear insights,
actionable results, and decisions backed by evidence.
</p>
</div>
</div>
</div>
{/* Reveal layer (black text on white bg) — different alternate text */}
<div
ref={revealRef}
className="absolute inset-0 z-30 bg-white pointer-events-none"
style={{ clipPath: "circle(0px at -300px -300px)" }}
>
<div className="px-6 md:px-12 lg:px-20 xl:px-32 py-8 md:py-12">
<div className="mb-16 md:mb-24">
<div>
<h2 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-extralight text-black tracking-tighter leading-[0.95]">
I build models that
</h2>
</div>
<div>
<h2 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl tracking-tighter leading-[0.95]">
<span className="font-black text-black">transform</span>
<span className="font-extralight text-black/50"> raw </span>
<span className="font-black text-transparent bg-clip-text bg-gradient-to-r from-black via-neutral-600 to-black/70">data</span>
</h2>
</div>
</div>
<div className="grid md:grid-cols-2 gap-8 md:gap-16 mb-16 md:mb-24">
<div className="space-y-4">
<p className="text-black/30 text-xs uppercase tracking-[0.3em] font-medium">The Spark</p>
<p className="text-lg md:text-xl lg:text-2xl text-black/80 font-light leading-relaxed">
What started as <span className="text-black font-medium">late-night experiments</span> turned into a lifelong
obsession with uncovering patterns, building models, and
letting data tell its story.
</p>
</div>
<div className="space-y-4">
<p className="text-black/30 text-xs uppercase tracking-[0.3em] font-medium">The Philosophy</p>
<p className="text-lg md:text-xl lg:text-2xl text-black/80 font-light leading-relaxed">
Great analysis is <span className="text-black font-medium">invisible</span>—it removes noise,
reveals clarity, and makes complex data feel
wonderfully simple.
</p>
</div>
</div>
</div>
</div>
</div>
{/* Diagonal Crossing Strips */}
<div ref={stripsWrapperRef} className="relative h-20 md:h-32">
<div
className="absolute w-[300vw] left-[-100vw] bg-white py-5 md:py-6 shadow-2xl z-10"
style={{ transform: "rotate(-4deg)", top: "5%" }}
>
<div className="about-strip-1-marquee whitespace-nowrap" style={{ display: "inline-block", width: "200%" }}>
<span className="text-xl md:text-2xl lg:text-3xl font-black text-[#050505] tracking-wide inline-block uppercase">
{strip1Text.repeat(15)}
</span>
</div>
</div>
<div
className="absolute w-[300vw] left-[-100vw] bg-[#151515] py-5 md:py-6 shadow-2xl border-y border-white/5 z-20"
style={{ transform: "rotate(4deg)", top: "50%" }}
>
<div className="about-strip-2-marquee whitespace-nowrap" style={{ display: "inline-block", width: "200%" }}>
<span className="text-xl md:text-2xl lg:text-3xl font-black text-white/90 tracking-wide inline-block uppercase">
{strip2Text.repeat(15)}
</span>
</div>
</div>
</div>
</div>
</div>
</section>
);
}