259 lines
10 KiB
TypeScript
259 lines
10 KiB
TypeScript
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
import { motion, useInView } from "framer-motion";
|
|
import { CheckCircle, Mail, MapPin, Phone, Send } from "lucide-react";
|
|
import { useRef, useState } from "react";
|
|
|
|
const contactInfo = [
|
|
{ icon: Mail, label: "Email", value: "techzaa.alpha@gmail.com" },
|
|
{ icon: Phone, label: "Phone", value: "+880 19623-21487" },
|
|
{ icon: MapPin, label: "Location", value: "Rangpur, Bangladesh" },
|
|
];
|
|
|
|
export default function ContactSection() {
|
|
const ref = useRef<HTMLElement>(null);
|
|
const isInView = useInView(ref, { once: true, margin: "-100px" });
|
|
|
|
const [formData, setFormData] = useState({
|
|
name: "",
|
|
email: "",
|
|
subject: "",
|
|
message: "",
|
|
});
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
|
|
const [mousePositions, setMousePositions] = useState<
|
|
Record<number, { x: number; y: number }>
|
|
>({});
|
|
|
|
const handleMouseMove = (
|
|
index: number,
|
|
e: React.MouseEvent<HTMLDivElement>,
|
|
) => {
|
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
const x = ((e.clientX - rect.left) / rect.width) * 100;
|
|
const y = ((e.clientY - rect.top) / rect.height) * 100;
|
|
setMousePositions((prev) => ({ ...prev, [index]: { x, y } }));
|
|
};
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setIsSubmitting(true);
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
|
|
setIsSubmitting(false);
|
|
setIsSuccess(true);
|
|
|
|
setTimeout(() => {
|
|
setIsSuccess(false);
|
|
setFormData({ name: "", email: "", subject: "", message: "" });
|
|
}, 3000);
|
|
};
|
|
|
|
const handleChange = (
|
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
) => {
|
|
setFormData((prev) => ({
|
|
...prev,
|
|
[e.target.name]: e.target.value,
|
|
}));
|
|
};
|
|
|
|
return (
|
|
<section id="contact" ref={ref} className="relative overflow-hidden pb-20">
|
|
<div className="absolute inset-0 opacity-40 pointer-events-none">
|
|
<motion.div
|
|
animate={{
|
|
x: [0, 30, 0],
|
|
y: [0, -40, 0],
|
|
}}
|
|
transition={{ duration: 25, repeat: Infinity, ease: "linear" }}
|
|
className="absolute bottom-10 left-1/4 w-96 h-96 bg-primary/10 rounded-full blur-[140px]"
|
|
/>
|
|
<motion.div
|
|
animate={{
|
|
x: [0, -50, 0],
|
|
y: [0, 30, 0],
|
|
}}
|
|
transition={{ duration: 30, repeat: Infinity, ease: "linear" }}
|
|
className="absolute top-20 right-1/4 w-80 h-80 bg-neon-purple/10 rounded-full blur-[130px]"
|
|
/>
|
|
</div>
|
|
|
|
<div className="container mx-auto px-4 relative z-10">
|
|
{/* Section Header */}
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={isInView ? { opacity: 1, y: 0 } : {}}
|
|
transition={{ duration: 0.7 }}
|
|
className="text-center mb-20"
|
|
>
|
|
<span className="inline-block px-5 py-2 rounded-full glass text-sm font-medium text-primary mb-4 tracking-widest">
|
|
LET'S CONNECT
|
|
</span>
|
|
<h2 className="text-4xl md:text-5xl lg:text-6xl font-bold mb-6">
|
|
Get In <span className="text-primary neon-text-glow">Touch</span>
|
|
</h2>
|
|
<p className="text-muted-foreground max-w-2xl mx-auto text-lg">
|
|
Ready to bring your vision to life? Drop us a message.
|
|
</p>
|
|
</motion.div>
|
|
|
|
<div className="grid lg:grid-cols-2 gap-12 max-w-6xl mx-auto">
|
|
{/* Interactive Contact Info */}
|
|
<motion.div
|
|
initial={{ opacity: 0, x: -40 }}
|
|
animate={isInView ? { opacity: 1, x: 0 } : {}}
|
|
transition={{ duration: 0.7 }}
|
|
className="space-y-6"
|
|
>
|
|
<div className="mb-8">
|
|
<h3 className="text-3xl font-bold mb-3">Contact Information</h3>
|
|
<p className="text-muted-foreground text-lg">
|
|
Our team typically responds within 24 hours.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-6">
|
|
{contactInfo.map((item, index) => {
|
|
const pos = mousePositions[index] || { x: 50, y: 50 };
|
|
return (
|
|
<motion.div
|
|
key={item.label}
|
|
initial={{ opacity: 0, y: 30 }}
|
|
animate={isInView ? { opacity: 1, y: 0 } : {}}
|
|
transition={{ delay: 0.1 * index }}
|
|
onMouseMove={(e) => handleMouseMove(index, e)}
|
|
onMouseLeave={() => {
|
|
setMousePositions((prev) => ({
|
|
...prev,
|
|
[index]: { x: 50, y: 50 },
|
|
}));
|
|
}}
|
|
whileHover={{ scale: 1.02 }}
|
|
className="group relative rounded-xl overflow-hidden cursor-pointer h-full"
|
|
>
|
|
<div
|
|
className="relative p-4 rounded-xl border transition-all duration-300"
|
|
style={{
|
|
transform: `perspective(800px) rotateX(${(50 - pos.y) * 0.08}deg) rotateY(${(pos.x - 50) * 0.1}deg)`,
|
|
}}
|
|
>
|
|
<div className="flex items-start gap-6">
|
|
<div className="w-16 h-16 rounded-2xl bg-primary/10 flex items-center justify-center group-hover:bg-primary/20 transition-all group-hover:neon-glow">
|
|
<item.icon className="w-7 h-7 text-primary" />
|
|
</div>
|
|
<div className="pt-1">
|
|
<p className="text-sm text-muted-foreground mb-1">
|
|
{item.label}
|
|
</p>
|
|
<p className="text-xl font-medium group-hover:text-primary transition-colors">
|
|
{item.value}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Interactive Contact Form */}
|
|
<motion.div
|
|
initial={{ opacity: 0, x: 40 }}
|
|
animate={isInView ? { opacity: 1, x: 0 } : {}}
|
|
transition={{ duration: 0.7, delay: 0.1 }}
|
|
>
|
|
<div className="p-10 rounded-3xl border backdrop-blur-2xl relative overflow-hidden">
|
|
{/* Subtle moving gradient */}
|
|
<div className="absolute -top-32 -right-32 w-64 h-64 bg-primary/10 rounded-full blur-3xl" />
|
|
|
|
{isSuccess ? (
|
|
<motion.div
|
|
initial={{ opacity: 0, scale: 0.9 }}
|
|
animate={{ opacity: 1, scale: 1 }}
|
|
className="text-center py-16"
|
|
>
|
|
<CheckCircle className="w-24 h-24 text-primary mx-auto mb-6 neon-text-glow" />
|
|
<h3 className="text-3xl font-bold mb-3">
|
|
Message Sent Successfully!
|
|
</h3>
|
|
<p className="text-muted-foreground text-lg">
|
|
Thank you! We'll get back to you very soon.
|
|
</p>
|
|
</motion.div>
|
|
) : (
|
|
<form
|
|
onSubmit={handleSubmit}
|
|
className="space-y-6 relative z-10"
|
|
>
|
|
<div className="grid sm:grid-cols-2 gap-6">
|
|
<Input
|
|
name="name"
|
|
placeholder="Your Name"
|
|
value={formData.name}
|
|
onChange={handleChange}
|
|
required
|
|
className="h-14 focus:border-primary focus:ring-2 focus:ring-primary/30 transition-all text-base"
|
|
/>
|
|
<Input
|
|
name="email"
|
|
type="email"
|
|
placeholder="Your Email"
|
|
value={formData.email}
|
|
onChange={handleChange}
|
|
required
|
|
className="h-14 focus:border-primary focus:ring-2 focus:ring-primary/30 transition-all text-base"
|
|
/>
|
|
</div>
|
|
|
|
<Input
|
|
name="subject"
|
|
placeholder="Subject"
|
|
value={formData.subject}
|
|
onChange={handleChange}
|
|
required
|
|
className="h-14 focus:border-primary focus:ring-2 focus:ring-primary/30 transition-all text-base"
|
|
/>
|
|
|
|
<Textarea
|
|
name="message"
|
|
placeholder="Tell us about your project..."
|
|
value={formData.message}
|
|
onChange={handleChange}
|
|
required
|
|
rows={6}
|
|
className=" focus:border-primary focus:ring-2 focus:ring-primary/30 transition-all resize-none text-base"
|
|
/>
|
|
|
|
<Button
|
|
type="submit"
|
|
disabled={isSubmitting}
|
|
className="w-full h-14 bg-primary hover:bg-primary/90 text-lg font-semibold rounded-2xl neon-glow hover:neon-glow-strong transition-all group"
|
|
>
|
|
{isSubmitting ? (
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
|
Sending...
|
|
</div>
|
|
) : (
|
|
<div className="flex items-center justify-center gap-3">
|
|
Send Message
|
|
<Send className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
|
|
</div>
|
|
)}
|
|
</Button>
|
|
</form>
|
|
)}
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|