184 lines
5.5 KiB
TypeScript
184 lines
5.5 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useRef } from "react"
|
|
import Image from "next/image"
|
|
import Link from "next/link"
|
|
import { Button } from "@/components/ui/button"
|
|
import { ChevronDown, History } from "lucide-react"
|
|
|
|
export default function HeroSection() {
|
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
|
|
|
useEffect(() => {
|
|
const canvas = canvasRef.current
|
|
if (!canvas) return
|
|
|
|
const ctx = canvas.getContext("2d")
|
|
if (!ctx) return
|
|
|
|
canvas.width = window.innerWidth
|
|
canvas.height = window.innerHeight
|
|
|
|
const particles: {
|
|
x: number
|
|
y: number
|
|
size: number
|
|
speedX: number
|
|
speedY: number
|
|
color: string
|
|
}[] = []
|
|
|
|
const createParticles = () => {
|
|
const particleCount = Math.floor(window.innerWidth / 20)
|
|
|
|
for (let i = 0; i < particleCount; i++) {
|
|
particles.push({
|
|
x: Math.random() * canvas.width,
|
|
y: Math.random() * canvas.height,
|
|
size: Math.random() * 1.5 + 0.1,
|
|
speedX: Math.random() * 0.3 - 0.15,
|
|
speedY: Math.random() * 0.3 - 0.15,
|
|
color: `rgba(255, 255, 255, ${Math.random() * 0.2})`,
|
|
})
|
|
}
|
|
}
|
|
|
|
const connectParticles = () => {
|
|
for (let i = 0; i < particles.length; i++) {
|
|
for (let j = i; j < particles.length; j++) {
|
|
const dx = particles[i].x - particles[j].x
|
|
const dy = particles[i].y - particles[j].y
|
|
const distance = Math.sqrt(dx * dx + dy * dy)
|
|
|
|
if (distance < 100) {
|
|
ctx.beginPath()
|
|
ctx.strokeStyle = `rgba(255, 255, 255, ${0.05 - distance / 2000})`
|
|
ctx.lineWidth = 0.2
|
|
ctx.moveTo(particles[i].x, particles[i].y)
|
|
ctx.lineTo(particles[j].x, particles[j].y)
|
|
ctx.stroke()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const animate = () => {
|
|
requestAnimationFrame(animate)
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
|
|
for (let i = 0; i < particles.length; i++) {
|
|
const p = particles[i]
|
|
ctx.fillStyle = p.color
|
|
ctx.beginPath()
|
|
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2)
|
|
ctx.fill()
|
|
|
|
p.x += p.speedX
|
|
p.y += p.speedY
|
|
|
|
if (p.x > canvas.width) p.x = 0
|
|
else if (p.x < 0) p.x = canvas.width
|
|
|
|
if (p.y > canvas.height) p.y = 0
|
|
else if (p.y < 0) p.y = canvas.height
|
|
}
|
|
|
|
connectParticles()
|
|
}
|
|
|
|
const handleResize = () => {
|
|
canvas.width = window.innerWidth
|
|
canvas.height = window.innerHeight
|
|
particles.length = 0
|
|
createParticles()
|
|
}
|
|
|
|
createParticles()
|
|
animate()
|
|
|
|
window.addEventListener("resize", handleResize)
|
|
|
|
return () => {
|
|
window.removeEventListener("resize", handleResize)
|
|
}
|
|
}, [])
|
|
|
|
const scrollToAbout = () => {
|
|
const aboutSection = document.getElementById("about")
|
|
if (aboutSection) {
|
|
aboutSection.scrollIntoView({ behavior: "smooth" })
|
|
}
|
|
}
|
|
|
|
return (
|
|
<section id="home" className="relative min-h-screen flex items-center justify-center overflow-hidden pt-16">
|
|
<canvas ref={canvasRef} className="absolute inset-0 z-0" />
|
|
|
|
<div className="absolute inset-0 grid-pattern opacity-20" />
|
|
|
|
<div className="absolute top-0 right-0 bottom-0 red-section z-0" />
|
|
|
|
<div className="container mx-auto px-4 z-20 flex flex-col items-center text-center relative">
|
|
<div className="mb-8 relative">
|
|
<div className="absolute inset-0 bg-primary/20 blur-3xl rounded-full" />
|
|
<Image src="/logo.svg" alt="Simba Robotics Logo" width={200} height={200} className="relative z-10" />
|
|
</div>
|
|
|
|
<div className="relative">
|
|
<h1 className="text-4xl md:text-6xl lg:text-7xl font-bold mb-4 uppercase font-mono">
|
|
SIMBA
|
|
<br />
|
|
ROBOTICS
|
|
</h1>
|
|
<div className="w-20 h-1 bg-primary mx-auto mb-6"></div>
|
|
</div>
|
|
|
|
<p className="text-xl md:text-2xl text-muted-foreground max-w-2xl mb-8 relative">
|
|
<span className="text-xs text-primary block mb-2 font-mono">// HLJU ROBOMASTER COMPETITION TEAM</span>
|
|
黑龙江大学 RoboMaster 战队
|
|
</p>
|
|
|
|
<div className="flex flex-col sm:flex-row gap-4 mb-16">
|
|
<Button
|
|
size="lg"
|
|
className="px-8 bg-primary text-primary-foreground hover:bg-primary/90 button-hover-effect"
|
|
onClick={() => {
|
|
const robotsSection = document.getElementById("robots")
|
|
if (robotsSection) {
|
|
robotsSection.scrollIntoView({ behavior: "smooth" })
|
|
}
|
|
}}
|
|
>
|
|
我们的机器人
|
|
</Button>
|
|
<Button
|
|
size="lg"
|
|
variant="outline"
|
|
className="px-8 border-white/20 hover:bg-white/5 button-hover-effect"
|
|
onClick={() => {
|
|
const contactSection = document.getElementById("contact")
|
|
if (contactSection) {
|
|
contactSection.scrollIntoView({ behavior: "smooth" })
|
|
}
|
|
}}
|
|
>
|
|
加入我们
|
|
</Button>
|
|
<Link href="/history">
|
|
<Button size="lg" variant="ghost" className="px-8 button-hover-effect">
|
|
<History className="mr-2 h-4 w-4" /> 英灵殿
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
className="absolute bottom-6 left-1/2 transform -translate-x-1/2 z-20 cursor-pointer animate-bounce"
|
|
onClick={scrollToAbout}
|
|
>
|
|
<ChevronDown className="h-10 w-10 text-primary" />
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|