Collaborative-pixel-art/frontend/src/components/ui/UsernameModal.tsx
2025-08-22 20:14:48 +02:00

130 lines
No EOL
5.2 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
interface UsernameModalProps {
isOpen: boolean;
currentUsername: string;
onUsernameChange: (username: string) => void;
onClose: () => void;
}
export function UsernameModal({
isOpen,
currentUsername,
onUsernameChange,
onClose
}: UsernameModalProps) {
const [username, setUsername] = useState(currentUsername);
useEffect(() => {
setUsername(currentUsername);
}, [currentUsername]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (username.trim()) {
onUsernameChange(username.trim());
onClose();
}
};
return (
<AnimatePresence>
{isOpen && (
<>
{/* Backdrop */}
<motion.div
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
/>
{/* Modal */}
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6">
<motion.div
className="w-full max-w-[320px] sm:max-w-[350px]"
initial={{ opacity: 0, scale: 0.7, y: 30 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.7, y: 30 }}
transition={{ type: "spring", stiffness: 300, damping: 25 }}
>
<form onSubmit={handleSubmit}>
<div className="bg-white/5 backdrop-blur-2xl rounded-2xl sm:rounded-3xl p-4 sm:p-6 lg:p-8 border border-white/20 shadow-2xl ring-1 ring-white/10 mx-auto">
<div className="text-center">
<motion.h3
className="text-white text-lg sm:text-xl font-bold mb-2"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
>
Choose Username
</motion.h3>
<motion.p
className="text-white/70 text-xs sm:text-sm mb-4 sm:mb-6"
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.15 }}
>
Your username will be shown when you place pixels
</motion.p>
<motion.div
className="mb-6 sm:mb-8"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Enter your username..."
className="w-full px-3 sm:px-4 py-3 sm:py-3 bg-white/5 backdrop-blur-xl border border-white/20 rounded-xl text-white text-sm sm:text-base placeholder-white/50 focus:outline-none focus:border-blue-400/60 focus:bg-white/10 transition-all duration-200 ring-1 ring-white/10 touch-manipulation"
maxLength={20}
autoFocus
/>
</motion.div>
<motion.div
className="flex gap-3 sm:gap-4"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.25 }}
>
<motion.button
type="button"
className="flex-1 px-4 sm:px-6 py-3 bg-white/5 backdrop-blur-xl text-white text-sm sm:text-base rounded-xl border border-white/20 hover:bg-white/10 active:bg-white/15 transition-all duration-200 font-medium ring-1 ring-white/10 touch-manipulation"
onClick={onClose}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
Cancel
</motion.button>
<motion.button
type="submit"
className="flex-1 px-4 sm:px-6 py-3 bg-gradient-to-r from-blue-500/80 to-purple-600/80 backdrop-blur-xl text-white text-sm sm:text-base rounded-xl hover:from-blue-600/90 hover:to-purple-700/90 active:from-blue-700/90 active:to-purple-800/90 transition-all duration-200 font-medium shadow-xl ring-1 ring-white/20 disabled:opacity-50 disabled:cursor-not-allowed touch-manipulation"
disabled={!username.trim()}
whileHover={{
scale: username.trim() ? 1.02 : 1,
boxShadow: username.trim() ? "0 10px 25px rgba(0,0,0,0.3)" : undefined
}}
whileTap={{ scale: username.trim() ? 0.98 : 1 }}
>
Save
</motion.button>
</motion.div>
</div>
</div>
</form>
</motion.div>
</div>
</>
)}
</AnimatePresence>
);
}