2025-12-18 18:32:35 +08:00

176 lines
5.6 KiB
TypeScript

'use client';
import React, { useRef, useMemo } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { Float, Stars } from '@react-three/drei';
import * as THREE from 'three';
import { useTranslations } from 'next-intl';
// ------------------- Three.js Components -------------------
const GeometryArt = () => {
const meshRef = useRef<THREE.Mesh>(null);
useFrame((state) => {
if (meshRef.current) {
meshRef.current.rotation.x = state.clock.getElapsedTime() * 0.1;
meshRef.current.rotation.y = state.clock.getElapsedTime() * 0.15;
}
});
return (
<Float speed={1.5} rotationIntensity={0.5} floatIntensity={0.5}>
<mesh ref={meshRef} position={[2, 0, 0]} scale={1.8}>
<icosahedronGeometry args={[1, 1]} />
<meshStandardMaterial
color="#C5A059"
wireframe
transparent
opacity={0.3}
roughness={0}
metalness={1}
/>
</mesh>
<mesh position={[2, 0, 0]} scale={0.5}>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial
color="#C5A059"
emissive="#C5A059"
emissiveIntensity={0.5}
roughness={0.2}
metalness={1}
/>
</mesh>
</Float>
);
};
const ConnectingLines = () => {
// Create random connections mimicking a network
const count = 40;
const lines = useMemo(() => {
const points: [number, number, number][] = [];
// Use a fixed seed for consistent but pseudo-random positioning
const seed = 12345;
const seededRandom = (i: number) => {
const x = Math.sin(seed + i * 12.9898) * 43758.5453123;
return x - Math.floor(x);
};
for (let i = 0; i < count; i++) {
points.push([
(seededRandom(i * 3) - 0.5) * 10,
(seededRandom(i * 3 + 1) - 0.5) * 6,
(seededRandom(i * 3 + 2) - 0.5) * 5
]);
}
return points;
}, []);
const ref = useRef<THREE.Group>(null);
useFrame((state) => {
if (ref.current) {
ref.current.rotation.y = -state.clock.getElapsedTime() * 0.05;
}
});
return (
<group ref={ref}>
{lines.map((pos, i) => (
<mesh key={i} position={new THREE.Vector3(...pos)}>
<sphereGeometry args={[0.02, 8, 8]} />
<meshBasicMaterial color="#ffffff" opacity={0.4} transparent />
</mesh>
))}
</group>
)
}
const Scene = () => {
return (
<>
<ambientLight intensity={0.2} />
<pointLight position={[10, 10, 10]} intensity={1.5} color="#C5A059" />
<pointLight position={[-10, -10, -10]} intensity={0.5} color="#4c4c4c" />
<spotLight position={[0, 5, 0]} angle={0.3} penumbra={1} intensity={2} color="white" />
<GeometryArt />
<ConnectingLines />
<Stars radius={100} depth={50} count={5000} factor={4} saturation={0} fade speed={1} />
</>
);
};
// ------------------- Main Component -------------------
const Hero: React.FC = () => {
const t = useTranslations('Hero');
const tNav = useTranslations('Navbar');
return (
<section id="hero" className="relative w-full h-screen bg-feie-dark overflow-hidden">
{/* 3D Canvas Layer */}
<div className="absolute inset-0 z-0">
<Canvas camera={{ position: [0, 0, 6], fov: 45 }}>
<Scene />
</Canvas>
</div>
{/* Content Overlay */}
<div className="absolute inset-0 z-10 flex items-center">
<div className="container mx-auto px-6 grid grid-cols-1 md:grid-cols-2">
<div className="text-left space-y-6">
<div className="inline-block px-3 py-1 border border-feie-gold/50 rounded-full">
<span className="text-feie-gold text-xs font-serif tracking-widest uppercase">
Est. Nanjing Technology Leader
</span>
</div>
<h1 className="text-5xl md:text-7xl font-serif text-feie-white leading-tight">
{t('title')} <br />
<span className="text-feie-gold italic">{t('subtitle')}</span>
</h1>
<p className="text-feie-white/70 text-lg md:text-xl font-light max-w-md leading-relaxed">
{t('description')}
</p>
<div className="pt-8 flex gap-4">
<a
href="#services"
className="px-8 py-3 bg-feie-gold text-feie-white font-serif hover:bg-yellow-600 transition-colors duration-300 rounded-sm"
>
{t('cta')}
</a>
<a
href="#contact"
className="px-8 py-3 border border-feie-white text-feie-white font-serif hover:bg-feie-white hover:text-feie-dark transition-colors duration-300 rounded-sm"
>
{tNav('contact')}
</a>
</div>
</div>
{/* Right side is empty to allow the 3D visual to shine */}
<div className="hidden md:block"></div>
</div>
</div>
{/* Scroll indicator */}
<div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 z-10 animate-bounce">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="#FFFFFF"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="opacity-50"
>
<path d="M12 5v14M19 12l-7 7-7-7"/>
</svg>
</div>
</section>
);
};
export default Hero;