import { useState, useEffect, useRef } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Eye, EyeOff, Mail, Sparkles } from "lucide-react"; import { cn } from "@/lib/utils"; interface PupilProps { size?: number; maxDistance?: number; pupilColor?: string; forceLookX?: number; forceLookY?: number; } const Pupil = ({ size = 12, maxDistance = 5, pupilColor = "black", forceLookX, forceLookY }: PupilProps) => { const [mouseX, setMouseX] = useState(0); const [mouseY, setMouseY] = useState(0); const pupilRef = useRef(null); useEffect(() => { const handleMouseMove = (e: MouseEvent) => { setMouseX(e.clientX); setMouseY(e.clientY); }; window.addEventListener("mousemove", handleMouseMove); return () => { window.removeEventListener("mousemove", handleMouseMove); }; }, []); const calculatePupilPosition = () => { if (!pupilRef.current) return { x: 0, y: 0 }; // If forced look direction is provided, use that instead of mouse tracking if (forceLookX !== undefined && forceLookY !== undefined) { return { x: forceLookX, y: forceLookY }; } const pupil = pupilRef.current.getBoundingClientRect(); const pupilCenterX = pupil.left + pupil.width / 2; const pupilCenterY = pupil.top + pupil.height / 2; const deltaX = mouseX - pupilCenterX; const deltaY = mouseY - pupilCenterY; const distance = Math.min(Math.sqrt(deltaX ** 2 + deltaY ** 2), maxDistance); const angle = Math.atan2(deltaY, deltaX); const x = Math.cos(angle) * distance; const y = Math.sin(angle) * distance; return { x, y }; }; const pupilPosition = calculatePupilPosition(); return (
); }; interface EyeBallProps { size?: number; pupilSize?: number; maxDistance?: number; eyeColor?: string; pupilColor?: string; isBlinking?: boolean; forceLookX?: number; forceLookY?: number; } const EyeBall = ({ size = 48, pupilSize = 16, maxDistance = 10, eyeColor = "white", pupilColor = "black", isBlinking = false, forceLookX, forceLookY }: EyeBallProps) => { const [mouseX, setMouseX] = useState(0); const [mouseY, setMouseY] = useState(0); const eyeRef = useRef(null); useEffect(() => { const handleMouseMove = (e: MouseEvent) => { setMouseX(e.clientX); setMouseY(e.clientY); }; window.addEventListener("mousemove", handleMouseMove); return () => { window.removeEventListener("mousemove", handleMouseMove); }; }, []); const calculatePupilPosition = () => { if (!eyeRef.current) return { x: 0, y: 0 }; // If forced look direction is provided, use that instead of mouse tracking if (forceLookX !== undefined && forceLookY !== undefined) { return { x: forceLookX, y: forceLookY }; } const eye = eyeRef.current.getBoundingClientRect(); const eyeCenterX = eye.left + eye.width / 2; const eyeCenterY = eye.top + eye.height / 2; const deltaX = mouseX - eyeCenterX; const deltaY = mouseY - eyeCenterY; const distance = Math.min(Math.sqrt(deltaX ** 2 + deltaY ** 2), maxDistance); const angle = Math.atan2(deltaY, deltaX); const x = Math.cos(angle) * distance; const y = Math.sin(angle) * distance; return { x, y }; }; const pupilPosition = calculatePupilPosition(); return (
{!isBlinking && (
)}
); }; function LoginPage() { const [showPassword, setShowPassword] = useState(false); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); const [isLoading, setIsLoading] = useState(false); const [mouseX, setMouseX] = useState(0); const [mouseY, setMouseY] = useState(0); const [isPurpleBlinking, setIsPurpleBlinking] = useState(false); const [isBlackBlinking, setIsBlackBlinking] = useState(false); const [isTyping, setIsTyping] = useState(false); const [isLookingAtEachOther, setIsLookingAtEachOther] = useState(false); const [isPurplePeeking, setIsPurplePeeking] = useState(false); const purpleRef = useRef(null); const blackRef = useRef(null); const yellowRef = useRef(null); const orangeRef = useRef(null); useEffect(() => { const handleMouseMove = (e: MouseEvent) => { setMouseX(e.clientX); setMouseY(e.clientY); }; window.addEventListener("mousemove", handleMouseMove); return () => window.removeEventListener("mousemove", handleMouseMove); }, []); // Blinking effect for purple character useEffect(() => { const getRandomBlinkInterval = () => Math.random() * 4000 + 3000; // Random between 3-7 seconds const scheduleBlink = () => { const blinkTimeout = setTimeout(() => { setIsPurpleBlinking(true); setTimeout(() => { setIsPurpleBlinking(false); scheduleBlink(); }, 150); // Blink duration 150ms }, getRandomBlinkInterval()); return blinkTimeout; }; const timeout = scheduleBlink(); return () => clearTimeout(timeout); }, []); // Blinking effect for black character useEffect(() => { const getRandomBlinkInterval = () => Math.random() * 4000 + 3000; // Random between 3-7 seconds const scheduleBlink = () => { const blinkTimeout = setTimeout(() => { setIsBlackBlinking(true); setTimeout(() => { setIsBlackBlinking(false); scheduleBlink(); }, 150); // Blink duration 150ms }, getRandomBlinkInterval()); return blinkTimeout; }; const timeout = scheduleBlink(); return () => clearTimeout(timeout); }, []); // Looking at each other animation when typing starts useEffect(() => { if (isTyping) { setIsLookingAtEachOther(true); const timer = setTimeout(() => { setIsLookingAtEachOther(false); }, 800); // Look at each other for 1.5 seconds, then back to tracking mouse return () => clearTimeout(timer); } else { setIsLookingAtEachOther(false); } }, [isTyping]); // Purple sneaky peeking animation when typing password and it's visible useEffect(() => { if (password.length > 0 && showPassword) { const schedulePeek = () => { const peekInterval = setTimeout(() => { setIsPurplePeeking(true); setTimeout(() => { setIsPurplePeeking(false); }, 800); // Peek for 800ms }, Math.random() * 3000 + 2000); // Random peek every 2-5 seconds return peekInterval; }; const firstPeek = schedulePeek(); return () => clearTimeout(firstPeek); } else { setIsPurplePeeking(false); } }, [password, showPassword, isPurplePeeking]); const calculatePosition = (ref: React.RefObject) => { if (!ref.current) return { faceX: 0, faceY: 0, bodyRotation: 0 }; const rect = ref.current.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 3; // Focus on head area const deltaX = mouseX - centerX; const deltaY = mouseY - centerY; // Face movement (limited range) const faceX = Math.max(-15, Math.min(15, deltaX / 20)); const faceY = Math.max(-10, Math.min(10, deltaY / 30)); // Body lean (skew for lean while keeping bottom straight) - negative to lean towards mouse const bodySkew = Math.max(-6, Math.min(6, -deltaX / 120)); return { faceX, faceY, bodySkew }; }; const purplePos = calculatePosition(purpleRef); const blackPos = calculatePosition(blackRef); const yellowPos = calculatePosition(yellowRef); const orangePos = calculatePosition(orangeRef); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(""); setIsLoading(true); // Simulate API delay (quick) await new Promise(resolve => setTimeout(resolve, 300)); // Mock authentication - validate against dummy credentials if (email === "erik@gmail.com" && password === "1234") { console.log("✅ Login successful!"); alert("Login successful! Welcome, Erik!"); // In a real app, you would: // - Store auth token // - Redirect to dashboard // - Set user session } else { setError("Invalid email or password. Please try again."); console.log("❌ Login failed"); } setIsLoading(false); }; return (
{/* Left Content Section */}
YourBrand
{/* Cartoon Characters */}
{/* Purple tall rectangle character - Back layer */}
0 && !showPassword)) ? '440px' : '400px', backgroundColor: '#6C3FF5', borderRadius: '10px 10px 0 0', zIndex: 1, transform: (password.length > 0 && showPassword) ? `skewX(0deg)` : (isTyping || (password.length > 0 && !showPassword)) ? `skewX(${(purplePos.bodySkew || 0) - 12}deg) translateX(40px)` : `skewX(${purplePos.bodySkew || 0}deg)`, transformOrigin: 'bottom center', }} > {/* Eyes */}
0 && showPassword) ? `${20}px` : isLookingAtEachOther ? `${55}px` : `${45 + purplePos.faceX}px`, top: (password.length > 0 && showPassword) ? `${35}px` : isLookingAtEachOther ? `${65}px` : `${40 + purplePos.faceY}px`, }} > 0 && showPassword) ? (isPurplePeeking ? 4 : -4) : isLookingAtEachOther ? 3 : undefined} forceLookY={(password.length > 0 && showPassword) ? (isPurplePeeking ? 5 : -4) : isLookingAtEachOther ? 4 : undefined} /> 0 && showPassword) ? (isPurplePeeking ? 4 : -4) : isLookingAtEachOther ? 3 : undefined} forceLookY={(password.length > 0 && showPassword) ? (isPurplePeeking ? 5 : -4) : isLookingAtEachOther ? 4 : undefined} />
{/* Black tall rectangle character - Middle layer */}
0 && showPassword) ? `skewX(0deg)` : isLookingAtEachOther ? `skewX(${(blackPos.bodySkew || 0) * 1.5 + 10}deg) translateX(20px)` : (isTyping || (password.length > 0 && !showPassword)) ? `skewX(${(blackPos.bodySkew || 0) * 1.5}deg)` : `skewX(${blackPos.bodySkew || 0}deg)`, transformOrigin: 'bottom center', }} > {/* Eyes */}
0 && showPassword) ? `${10}px` : isLookingAtEachOther ? `${32}px` : `${26 + blackPos.faceX}px`, top: (password.length > 0 && showPassword) ? `${28}px` : isLookingAtEachOther ? `${12}px` : `${32 + blackPos.faceY}px`, }} > 0 && showPassword) ? -4 : isLookingAtEachOther ? 0 : undefined} forceLookY={(password.length > 0 && showPassword) ? -4 : isLookingAtEachOther ? -4 : undefined} /> 0 && showPassword) ? -4 : isLookingAtEachOther ? 0 : undefined} forceLookY={(password.length > 0 && showPassword) ? -4 : isLookingAtEachOther ? -4 : undefined} />
{/* Orange semi-circle character - Front left */}
0 && showPassword) ? `skewX(0deg)` : `skewX(${orangePos.bodySkew || 0}deg)`, transformOrigin: 'bottom center', }} > {/* Eyes - just pupils, no white */}
0 && showPassword) ? `${50}px` : `${82 + (orangePos.faceX || 0)}px`, top: (password.length > 0 && showPassword) ? `${85}px` : `${90 + (orangePos.faceY || 0)}px`, }} > 0 && showPassword) ? -5 : undefined} forceLookY={(password.length > 0 && showPassword) ? -4 : undefined} /> 0 && showPassword) ? -5 : undefined} forceLookY={(password.length > 0 && showPassword) ? -4 : undefined} />
{/* Yellow tall rectangle character - Front right */}
0 && showPassword) ? `skewX(0deg)` : `skewX(${yellowPos.bodySkew || 0}deg)`, transformOrigin: 'bottom center', }} > {/* Eyes - just pupils, no white */}
0 && showPassword) ? `${20}px` : `${52 + (yellowPos.faceX || 0)}px`, top: (password.length > 0 && showPassword) ? `${35}px` : `${40 + (yellowPos.faceY || 0)}px`, }} > 0 && showPassword) ? -5 : undefined} forceLookY={(password.length > 0 && showPassword) ? -4 : undefined} /> 0 && showPassword) ? -5 : undefined} forceLookY={(password.length > 0 && showPassword) ? -4 : undefined} />
{/* Horizontal line for mouth */}
0 && showPassword) ? `${10}px` : `${40 + (yellowPos.faceX || 0)}px`, top: (password.length > 0 && showPassword) ? `${88}px` : `${88 + (yellowPos.faceY || 0)}px`, }} />
{/* Decorative elements */}
{/* Right Login Section */}
{/* Mobile Logo */}
YourBrand
{/* Header */}

Welcome back!

Please enter your details

{/* Login Form */}
setEmail(e.target.value)} onFocus={() => setIsTyping(true)} onBlur={() => setIsTyping(false)} required className="h-12 bg-background border-border/60 focus:border-primary" />
setPassword(e.target.value)} required className="h-12 pr-10 bg-background border-border/60 focus:border-primary" />
Forgot password?
{error && (
{error}
)}
{/* Social Login */}
{/* Sign Up Link */}
Don't have an account?{" "} Sign Up
); } export const Component = LoginPage;