← back to IWasCute
src/app/login/page.tsx
243 lines
'use client'
import { useState } from 'react'
import { motion } from 'framer-motion'
import { Mail, Lock, Eye, EyeOff, ArrowRight } from 'lucide-react'
import Link from 'next/link'
export default function LoginPage() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [showPassword, setShowPassword] = useState(false)
const [mode, setMode] = useState<'login' | 'signup'>('login')
return (
<div
className="min-h-screen flex flex-col items-center justify-center px-4 py-12 relative overflow-hidden"
style={{ background: 'var(--color-cream)' }}
>
{/* Decorative blobs */}
<div
className="absolute -top-32 -left-32 w-96 h-96 rounded-full opacity-20 blur-3xl pointer-events-none"
style={{ background: 'var(--color-peach)' }}
/>
<div
className="absolute -bottom-40 -right-32 w-[30rem] h-[30rem] rounded-full opacity-15 blur-3xl pointer-events-none"
style={{ background: 'var(--color-sage)' }}
/>
{/* Logo */}
<div className="mb-10 text-center">
<Link
href="/"
className="text-3xl font-black tracking-tighter transition-opacity hover:opacity-70"
style={{ color: 'var(--color-brown)' }}
>
i was cute
</Link>
</div>
{/* Card */}
<div
className="relative z-10 w-full max-w-sm rounded-3xl p-8"
style={{ background: 'rgba(255,255,255,0.7)', border: '1px solid var(--color-cream-dark)' }}
>
{/* Mode toggle */}
<div
className="flex gap-1 p-1 rounded-2xl mb-8"
style={{ background: 'var(--color-cream-dark)' }}
>
{(['login', 'signup'] as const).map((m) => (
<button
key={m}
onClick={() => setMode(m)}
className="relative flex-1 py-2.5 text-sm font-semibold rounded-xl transition-all"
style={{
color: mode === m ? 'var(--color-brown)' : 'var(--color-warm-gray)',
}}
>
{mode === m && (
<motion.div
layoutId="auth-tab"
className="absolute inset-0 rounded-xl"
style={{ background: 'white', boxShadow: '0 1px 3px rgba(0,0,0,0.08)' }}
transition={{ type: 'spring', stiffness: 380, damping: 30 }}
/>
)}
<span className="relative z-10">
{m === 'login' ? 'Sign In' : 'Sign Up'}
</span>
</button>
))}
</div>
<form
onSubmit={(e) => {
e.preventDefault()
// TODO: wire up NextAuth.js
}}
className="flex flex-col gap-4"
>
{/* Email */}
<div className="flex flex-col gap-1.5">
<label
htmlFor="email"
className="text-sm font-semibold"
style={{ color: 'var(--color-brown)' }}
>
Email
</label>
<div className="relative">
<Mail
size={16}
className="absolute left-3.5 top-1/2 -translate-y-1/2 pointer-events-none"
style={{ color: 'var(--color-warm-gray)' }}
/>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
autoComplete="email"
required
className="w-full pl-10 pr-4 py-3 rounded-2xl text-sm border outline-none transition-all focus:ring-2"
style={{
background: 'rgba(255,255,255,0.8)',
borderColor: 'var(--color-cream-dark)',
color: 'var(--color-brown)',
}}
/>
</div>
</div>
{/* Password */}
<div className="flex flex-col gap-1.5">
<label
htmlFor="password"
className="text-sm font-semibold"
style={{ color: 'var(--color-brown)' }}
>
Password
</label>
<div className="relative">
<Lock
size={16}
className="absolute left-3.5 top-1/2 -translate-y-1/2 pointer-events-none"
style={{ color: 'var(--color-warm-gray)' }}
/>
<input
id="password"
type={showPassword ? 'text' : 'password'}
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder={mode === 'signup' ? 'Create a password' : 'Your password'}
autoComplete={mode === 'signup' ? 'new-password' : 'current-password'}
required
className="w-full pl-10 pr-12 py-3 rounded-2xl text-sm border outline-none transition-all focus:ring-2"
style={{
background: 'rgba(255,255,255,0.8)',
borderColor: 'var(--color-cream-dark)',
color: 'var(--color-brown)',
}}
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-lg transition-all hover:scale-110"
style={{ color: 'var(--color-warm-gray)' }}
aria-label={showPassword ? 'Hide password' : 'Show password'}
>
{showPassword ? <EyeOff size={16} /> : <Eye size={16} />}
</button>
</div>
</div>
{mode === 'signup' && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
className="overflow-hidden"
>
<label className="flex items-start gap-3 cursor-pointer">
<input
type="checkbox"
required
className="mt-1"
/>
<p className="text-xs leading-relaxed" style={{ color: 'var(--color-warm-gray)' }}>
I am 18 years or older and agree to the{' '}
<Link href="/terms" className="underline" style={{ color: 'var(--color-peach-dark)' }}>
Terms of Service
</Link>{' '}
and{' '}
<Link href="/privacy" className="underline" style={{ color: 'var(--color-peach-dark)' }}>
Privacy Policy
</Link>
.
</p>
</label>
</motion.div>
)}
{/* Submit */}
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
type="submit"
className="flex items-center justify-center gap-2 w-full py-3.5 rounded-3xl text-sm font-semibold tracking-wide mt-2 transition-all"
style={{ background: 'var(--color-peach)', color: 'var(--color-brown)' }}
>
{mode === 'login' ? 'Sign In' : 'Create Account'}
<ArrowRight size={14} />
</motion.button>
</form>
{/* Divider */}
<div className="flex items-center gap-3 my-6">
<div className="flex-1 h-px" style={{ background: 'var(--color-cream-dark)' }} />
<span className="text-xs font-medium" style={{ color: 'var(--color-warm-gray)' }}>
or
</span>
<div className="flex-1 h-px" style={{ background: 'var(--color-cream-dark)' }} />
</div>
{/* Google OAuth */}
<button
className="flex items-center justify-center gap-3 w-full py-3 rounded-2xl text-sm font-medium border transition-all hover:scale-[1.02]"
style={{
background: 'rgba(255,255,255,0.8)',
borderColor: 'var(--color-cream-dark)',
color: 'var(--color-brown)',
}}
>
<svg width="18" height="18" viewBox="0 0 24 24">
<path
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"
fill="#4285F4"
/>
<path
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
fill="#34A853"
/>
<path
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
fill="#FBBC05"
/>
<path
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
fill="#EA4335"
/>
</svg>
Continue with Google
</button>
</div>
{/* Footer note */}
<p className="mt-8 text-xs text-center" style={{ color: 'var(--color-warm-gray)' }}>
Must be 18+ to create an account. We never sell your data.
</p>
</div>
)
}