145 lines
3.4 KiB
TypeScript
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>
|
|
);
|
|
}
|