Initial commit from v0
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { ArrowRight, ChevronDown } 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-[0.9] mb-8">
|
||||
<AnimatedText text="Every Business" className="mb-2" />
|
||||
<AnimatedText text="Needs an" className="mb-2" />
|
||||
<span className="relative inline-block">
|
||||
<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">
|
||||
<Button
|
||||
asChild
|
||||
size="lg"
|
||||
className="group bg-primary text-primary-foreground hover:bg-primary/90 px-8 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="px-8 py-6 text-lg border-border hover:bg-card hover:border-primary/50 transition-all duration-300"
|
||||
>
|
||||
<Link href="#services">Our Services</Link>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="mt-20 grid grid-cols-2 md:grid-cols-4 gap-8 animate-fade-in animation-delay-1000">
|
||||
{[
|
||||
{ value: "100+", label: "Happy Clients" },
|
||||
{ value: "24/7", label: "Support" },
|
||||
{ value: "NZ", label: "Based Hosting" },
|
||||
{ value: "10+", label: "Years Experience" },
|
||||
].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>
|
||||
|
||||
{/* Scroll indicator */}
|
||||
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
|
||||
<Link href="#services" className="flex flex-col items-center gap-2 text-muted-foreground hover:text-foreground transition-colors">
|
||||
<span className="text-xs tracking-widest uppercase">Scroll</span>
|
||||
<ChevronDown className="w-5 h-5" />
|
||||
</Link>
|
||||
</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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user