"use client"; import { useState, useEffect, useRef } from "react"; import { motion } from "framer-motion"; import { ArrowRight, Lock, Shield, Fingerprint } from "lucide-react"; interface AnimatedLoginFormProps { redirectUrl: string; loginAction: (formData: FormData) => Promise; projectName: string; } export function AnimatedLoginForm({ redirectUrl, loginAction, }: AnimatedLoginFormProps) { const [isFocused, setIsFocused] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [mounted, setMounted] = useState(false); const wrapperRef = useRef(null); const beamRef = useRef(null); // Mouse tracking refs (no re-render) const mouse = useRef({ x: 0, y: 0 }); const angle = useRef(0); const tilt = useRef({ x: 0, y: 0 }); useEffect(() => { setMounted(true); }, []); // Single rAF loop: iridescent border + perspective tilt useEffect(() => { let animId: number; const onMouseMove = (e: MouseEvent) => { mouse.current = { x: e.clientX, y: e.clientY }; }; window.addEventListener("mousemove", onMouseMove); const animate = () => { if (!wrapperRef.current || !beamRef.current) { animId = requestAnimationFrame(animate); return; } const rect = wrapperRef.current.getBoundingClientRect(); const cx = rect.left + rect.width / 2; const cy = rect.top + rect.height / 2; const dx = mouse.current.x - cx; const dy = mouse.current.y - cy; // Angle from form center to mouse → positions the bright highlight const targetAngle = (Math.atan2(dy, dx) * 180) / Math.PI; // Lerp angle smoothly (shortest path) let diff = targetAngle - angle.current; while (diff > 180) diff -= 360; while (diff < -180) diff += 360; angle.current += diff * 0.06; // Intensity: slightly stronger on focus const intensity = isFocused ? 1 : 0.7; // Mouse-aligned iridescent conic gradient // The "hotspot" (brightest white) faces the mouse beamRef.current.style.background = `conic-gradient(from ${angle.current}deg at 50% 50%, rgba(255,255,255,${1.0 * intensity}) 0deg, rgba(200,210,255,${0.8 * intensity}) 20deg, rgba(255,200,230,${0.7 * intensity}) 45deg, rgba(150,160,180,${0.6 * intensity}) 80deg, rgba(40,40,50,${0.5 * intensity}) 160deg, rgba(20,20,30,${0.4 * intensity}) 200deg, rgba(140,150,170,${0.5 * intensity}) 280deg, rgba(210,225,255,${0.7 * intensity}) 320deg, rgba(255,255,255,${1.0 * intensity}) 360deg)`; // Subtle perspective tilt — max ±4deg const maxTilt = 4; const normX = dx / (rect.width * 2); const normY = dy / (rect.height * 2); const targetTiltY = normX * maxTilt; const targetTiltX = -normY * maxTilt; tilt.current.x += (targetTiltX - tilt.current.x) * 0.08; tilt.current.y += (targetTiltY - tilt.current.y) * 0.08; wrapperRef.current.style.transform = `perspective(800px) rotateX(${tilt.current.x}deg) rotateY(${tilt.current.y}deg)`; animId = requestAnimationFrame(animate); }; animId = requestAnimationFrame(animate); return () => { window.removeEventListener("mousemove", onMouseMove); cancelAnimationFrame(animId); }; }, [isFocused]); const handleSubmit = async (formData: FormData) => { setIsSubmitting(true); try { await loginAction(formData); } finally { setIsSubmitting(false); } }; return ( {/* Outer wrapper for tilt (refs need non-motion div) */}
{/* ── Always-on iridescent beam border ── */}
{/* Sharp edge layer */}
{/* Soft glow bloom */}
{/* ── Glassmorphism card — high-fidelity glossy light ── */}
{/* Subtle surface "sheen" gradient */}
{/* Shield icon header */}
{mounted && (
)}
setIsFocused(true)} onBlur={(e) => { if (!e.currentTarget.contains(e.relatedTarget as Node)) { setIsFocused(false); } }} >
{/* Email Input */} setIsFocused(true)} className="w-full bg-black/[0.02] border border-black/[0.06] rounded-2xl pl-11 pr-4 py-3.5 focus:outline-none focus:border-black/15 focus:bg-white/80 transition-all duration-300 text-[11px] font-sans font-medium tracking-[0.08em] placeholder:text-black/25 placeholder:normal-case placeholder:tracking-normal text-black/70" />
{/* Password Input */} setIsFocused(true)} className="w-full bg-black/[0.02] border border-black/[0.06] rounded-2xl pl-11 pr-4 py-3.5 focus:outline-none focus:border-black/15 focus:bg-white/80 transition-all duration-300 text-[13px] font-sans font-medium tracking-[0.15em] placeholder:text-black/25 placeholder:tracking-normal placeholder:text-[11px] placeholder:font-normal text-black/80" />
{/* Submit Button */} {!isSubmitting && (
)} {isSubmitting ? ( Authenticating... ) : ( Unlock Access )} {/* Security badge */}
Encrypted Connection
); }