Rewrite with modern stack
This commit is contained in:
parent
855c61c740
commit
1f1f20ffd6
69 changed files with 17771 additions and 1589 deletions
128
frontend/src/components/ui/UsernameModal.tsx
Normal file
128
frontend/src/components/ui/UsernameModal.tsx
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
'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 */}
|
||||
<motion.div
|
||||
className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50"
|
||||
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 w-[95vw] max-w-[320px] sm:max-w-[350px] shadow-2xl ring-1 ring-white/10">
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue