200 lines
7.0 KiB
TypeScript
200 lines
7.0 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useRef, useState } from "react"
|
|
import { Button } from "@/components/ui/button"
|
|
import { ArrowRight } from "lucide-react"
|
|
import Link from "next/link"
|
|
|
|
function FloatingElement({ delay = 0, duration = 20, children, className = "" }: {
|
|
delay?: number
|
|
duration?: number
|
|
children: React.ReactNode
|
|
className?: string
|
|
}) {
|
|
return (
|
|
<div
|
|
className={`absolute pointer-events-none ${className}`}
|
|
style={{
|
|
animation: `float ${duration}s ease-in-out ${delay}s infinite`,
|
|
}}
|
|
>
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function GridPattern() {
|
|
return (
|
|
<div className="absolute inset-0 overflow-hidden opacity-20">
|
|
<div className="absolute inset-0" style={{
|
|
backgroundImage: `
|
|
linear-gradient(rgba(74, 222, 128, 0.1) 1px, transparent 1px),
|
|
linear-gradient(90deg, rgba(74, 222, 128, 0.1) 1px, transparent 1px)
|
|
`,
|
|
backgroundSize: '60px 60px'
|
|
}} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function AnimatedText({ text, className = "" }: { text: string; className?: string }) {
|
|
const [isVisible, setIsVisible] = useState(false)
|
|
const ref = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
const timer = setTimeout(() => setIsVisible(true), 300)
|
|
return () => clearTimeout(timer)
|
|
}, [])
|
|
|
|
return (
|
|
<div ref={ref} className={`overflow-hidden ${className}`}>
|
|
<div
|
|
className={`transition-all duration-1000 ease-out ${
|
|
isVisible ? "translate-y-0 opacity-100" : "translate-y-full opacity-0"
|
|
}`}
|
|
>
|
|
{text}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function Hero() {
|
|
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 })
|
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
const handleMouseMove = (e: MouseEvent) => {
|
|
if (containerRef.current) {
|
|
const rect = containerRef.current.getBoundingClientRect()
|
|
setMousePosition({
|
|
x: (e.clientX - rect.left - rect.width / 2) / 50,
|
|
y: (e.clientY - rect.top - rect.height / 2) / 50,
|
|
})
|
|
}
|
|
}
|
|
|
|
window.addEventListener("mousemove", handleMouseMove)
|
|
return () => window.removeEventListener("mousemove", handleMouseMove)
|
|
}, [])
|
|
|
|
return (
|
|
<section
|
|
ref={containerRef}
|
|
className="relative min-h-screen flex items-center justify-center overflow-hidden pt-20"
|
|
>
|
|
{/* Background Elements */}
|
|
<GridPattern />
|
|
|
|
{/* Floating decorative elements */}
|
|
<FloatingElement delay={0} duration={25} className="top-[15%] left-[10%]">
|
|
<div className="w-32 h-32 border border-primary/20 rounded-full" />
|
|
</FloatingElement>
|
|
<FloatingElement delay={5} duration={30} className="top-[60%] right-[15%]">
|
|
<div className="w-24 h-24 border border-primary/30 rotate-45" />
|
|
</FloatingElement>
|
|
<FloatingElement delay={10} duration={22} className="bottom-[20%] left-[20%]">
|
|
<div className="w-16 h-16 bg-primary/10 rounded-lg" />
|
|
</FloatingElement>
|
|
|
|
{/* Glow effect */}
|
|
<div
|
|
className="absolute w-[600px] h-[600px] rounded-full bg-primary/10 blur-[120px] transition-transform duration-500 ease-out"
|
|
style={{
|
|
transform: `translate(${mousePosition.x * 2}px, ${mousePosition.y * 2}px)`,
|
|
}}
|
|
/>
|
|
|
|
<div className="relative z-10 mx-auto max-w-7xl px-6 lg:px-8 text-center">
|
|
{/* Badge */}
|
|
<div className="inline-flex items-center gap-2 px-4 py-2 mb-8 border border-border rounded-full bg-card/50 backdrop-blur-sm animate-fade-in">
|
|
<span className="w-2 h-2 bg-primary rounded-full animate-pulse" />
|
|
<span className="text-sm text-muted-foreground">Auckland, New Zealand</span>
|
|
</div>
|
|
|
|
{/* Main Heading */}
|
|
<h1 className="text-5xl md:text-7xl lg:text-8xl font-bold tracking-tight leading-[1.05] mb-8">
|
|
<AnimatedText text="Every Business" className="mb-2 pb-1" />
|
|
<AnimatedText text="Needs an" className="mb-2 pb-1" />
|
|
<span className="relative inline-block pb-2">
|
|
<AnimatedText
|
|
text="I.T Guy"
|
|
className="text-primary"
|
|
/>
|
|
<div className="absolute -inset-2 bg-primary/20 blur-2xl -z-10 animate-pulse" />
|
|
</span>
|
|
</h1>
|
|
|
|
{/* Subtitle */}
|
|
<p className="max-w-2xl mx-auto text-lg md:text-xl text-muted-foreground mb-12 animate-fade-in animation-delay-500">
|
|
From websites and cloud infrastructure to computer repairs and I.T support —
|
|
we help small businesses thrive in the digital world.
|
|
</p>
|
|
|
|
{/* CTA Buttons */}
|
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 animate-fade-in animation-delay-700 max-w-36 mx-auto">
|
|
<Button
|
|
asChild
|
|
size="lg"
|
|
className="group bg-primary text-primary-foreground hover:bg-primary/90 w-full py-6 text-lg transition-all duration-300 hover:scale-105 hover:shadow-xl hover:shadow-primary/25"
|
|
>
|
|
<Link href="#contact">
|
|
Let's Talk
|
|
<ArrowRight className="ml-2 w-5 h-5 transition-transform duration-300 group-hover:translate-x-1" />
|
|
</Link>
|
|
</Button>
|
|
<Button
|
|
asChild
|
|
variant="outline"
|
|
size="lg"
|
|
className="w-full py-6 text-lg border-border hover:bg-card hover:border-primary/50 hover:text-primary-background transition-all duration-300"
|
|
>
|
|
<Link href="#services">Our Services</Link>
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Stats */}
|
|
<div className="mt-20 grid grid-cols-3 gap-8 max-w-lg mx-auto animate-fade-in animation-delay-1000">
|
|
{[
|
|
{ value: "24/7", label: "Support Available" },
|
|
{ value: "NZ", label: "Hosted Locally" },
|
|
{ value: "Auckland", label: "Based Business" },
|
|
].map((stat, index) => (
|
|
<div
|
|
key={stat.label}
|
|
className="group cursor-default"
|
|
style={{ animationDelay: `${1200 + index * 100}ms` }}
|
|
>
|
|
<div className="text-3xl md:text-4xl font-bold text-foreground transition-colors duration-300 group-hover:text-primary">
|
|
{stat.value}
|
|
</div>
|
|
<div className="text-sm text-muted-foreground mt-1">{stat.label}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<style jsx>{`
|
|
@keyframes float {
|
|
0%, 100% { transform: translateY(0px) rotate(0deg); }
|
|
50% { transform: translateY(-20px) rotate(5deg); }
|
|
}
|
|
|
|
.animate-fade-in {
|
|
animation: fadeIn 0.8s ease-out forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(20px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.animation-delay-500 { animation-delay: 500ms; }
|
|
.animation-delay-700 { animation-delay: 700ms; }
|
|
.animation-delay-1000 { animation-delay: 1000ms; }
|
|
`}</style>
|
|
</section>
|
|
)
|
|
}
|