Files
AboutMe/components/hero.tsx
T
2026-08-19 18:05:20 +08:00

145 lines
3.4 KiB
TypeScript

"use client";
import { useEffect, useRef } from "react";
import gsap from "gsap";
export function Hero() {
const rootRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const ctx = gsap.context(() => {
// 细线缓慢绘制
gsap.fromTo(
".hero-line",
{ strokeDashoffset: 600 },
{
strokeDashoffset: 0,
duration: 2.4,
ease: "power2.inOut",
stagger: 0.3
}
);
gsap.fromTo(
".hero-shape",
{ opacity: 0, scale: 0.96 },
{
opacity: 1,
scale: 1,
duration: 1.8,
ease: "power2.out",
stagger: 0.2
}
);
// 缓慢呼吸浮动
gsap.to(".hero-float", {
y: -10,
duration: 4,
ease: "sine.inOut",
yoyo: true,
repeat: -1
});
gsap.to(".hero-breathe", {
opacity: 0.35,
duration: 3.2,
ease: "sine.inOut",
yoyo: true,
repeat: -1
});
gsap.fromTo(
".hero-hint",
{ opacity: 0 },
{ opacity: 1, duration: 1.5, delay: 2, ease: "power2.out" }
);
}, rootRef);
return () => ctx.revert();
}, []);
return (
<section
ref={rootRef}
aria-label="首屏"
className="relative flex h-svh w-full items-center justify-center overflow-hidden"
>
<div className="hero-float relative -translate-x-4">
<svg
width="320"
height="320"
viewBox="0 0 320 320"
fill="none"
aria-hidden="true"
className="h-56 w-56 md:h-80 md:w-80"
>
{/* 外圈细线圆 */}
<circle
className="hero-line"
cx="160"
cy="160"
r="120"
stroke="oklch(0.98 0.004 90 / 0.16)"
strokeWidth="1"
strokeDasharray="600"
strokeDashoffset="600"
/>
{/* 内部偏移圆 */}
<circle
className="hero-line"
cx="176"
cy="144"
r="72"
stroke="oklch(0.62 0.05 155 / 0.45)"
strokeWidth="1"
strokeDasharray="600"
strokeDashoffset="600"
/>
{/* 对角细线 */}
<line
className="hero-line"
x1="48"
y1="272"
x2="272"
y2="48"
stroke="oklch(0.98 0.004 90 / 0.12)"
strokeWidth="1"
strokeDasharray="600"
strokeDashoffset="600"
/>
{/* 小方形节点 */}
<rect
className="hero-shape"
x="156"
y="156"
width="8"
height="8"
fill="oklch(0.72 0.07 75 / 0.7)"
/>
<circle
className="hero-shape hero-breathe"
cx="232"
cy="88"
r="3"
fill="oklch(0.62 0.05 155 / 0.8)"
/>
<circle
className="hero-shape hero-breathe"
cx="88"
cy="232"
r="2"
fill="oklch(0.98 0.004 90 / 0.4)"
/>
</svg>
</div>
<div className="hero-hint absolute bottom-10 left-1/2 -translate-x-1/2 opacity-0">
<span className="text-[11px] uppercase tracking-[0.3em] text-muted-foreground/60">
Scroll
</span>
</div>
</section>
);
}