init: init repo with existing code
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { CheckCircle, Send, X } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
interface ContactModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function ContactModal({ isOpen, onClose }: ContactModalProps) {
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
message: "",
|
||||
});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [isSuccess, setIsSuccess] = useState(false);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
// Simulate form submission
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
|
||||
setIsSubmitting(false);
|
||||
setIsSuccess(true);
|
||||
|
||||
// Reset after showing success
|
||||
setTimeout(() => {
|
||||
setIsSuccess(false);
|
||||
setFormData({ name: "", email: "", message: "" });
|
||||
onClose();
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[e.target.name]: e.target.value,
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="fixed inset-0 z-[100] flex items-center justify-center p-4"
|
||||
>
|
||||
{/* Backdrop */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="absolute inset-0 bg-background/80 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
/>
|
||||
|
||||
{/* Modal */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.9, y: 20 }}
|
||||
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||
exit={{ opacity: 0, scale: 0.9, y: 20 }}
|
||||
transition={{ type: "spring", damping: 25, stiffness: 300 }}
|
||||
className="relative w-full max-w-md rounded-3xl p-8 border-gradient overflow-hidden"
|
||||
>
|
||||
{/* Close button */}
|
||||
<motion.button
|
||||
onClick={onClose}
|
||||
className="absolute top-4 right-4 p-2 rounded-full glass hover:bg-primary/20 transition-colors"
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</motion.button>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10">
|
||||
<AnimatePresence mode="wait">
|
||||
{isSuccess ? (
|
||||
<motion.div
|
||||
key="success"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.8 }}
|
||||
className="text-center py-8"
|
||||
>
|
||||
<motion.div
|
||||
initial={{ scale: 0 }}
|
||||
animate={{ scale: 1 }}
|
||||
transition={{
|
||||
type: "spring",
|
||||
damping: 15,
|
||||
stiffness: 300,
|
||||
delay: 0.2,
|
||||
}}
|
||||
>
|
||||
<CheckCircle className="w-20 h-20 text-primary mx-auto mb-4 neon-text-glow" />
|
||||
</motion.div>
|
||||
<h3 className="text-2xl font-bold mb-2">Message Sent!</h3>
|
||||
<p className="text-muted-foreground">
|
||||
We'll get back to you soon.
|
||||
</p>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.div
|
||||
key="form"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
>
|
||||
<h2 className="text-2xl font-bold mb-2">Let's Talk</h2>
|
||||
<p className="text-muted-foreground mb-6">
|
||||
Ready to start your project? Tell us about it.
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.1 }}
|
||||
>
|
||||
<Input
|
||||
name="name"
|
||||
placeholder="Your Name"
|
||||
value={formData.name}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className=" border focus:border-primary focus:neon-glow transition-all"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
>
|
||||
<Input
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="Your Email"
|
||||
value={formData.email}
|
||||
onChange={handleChange}
|
||||
required
|
||||
className=" border focus:border-primary focus:neon-glow transition-all"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
>
|
||||
<Textarea
|
||||
name="message"
|
||||
placeholder="Tell us about your project..."
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
required
|
||||
rows={4}
|
||||
className=" border focus:border-primary focus:neon-glow transition-all resize-none"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
className="w-full bg-primary text-primary-foreground font-semibold py-3 rounded-full neon-glow hover:neon-glow-strong transition-all group"
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{
|
||||
duration: 1,
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
}}
|
||||
className="w-5 h-5 border-2 border-primary-foreground/30 border-t-primary-foreground rounded-full"
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
Send Message
|
||||
<Send className="w-4 h-4 ml-2 group-hover:translate-x-1 transition-transform" />
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</motion.div>
|
||||
</form>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user