This commit is contained in:
2026-01-21 08:21:19 +01:00
parent 4733e1a1cc
commit fd6e7c44e1
46 changed files with 3165 additions and 456 deletions

View File

@@ -5,7 +5,11 @@ import { useState } from 'react'
import { Check, ArrowRight, Loader2 } from 'lucide-react'
import { Button } from '@/components/ui/button'
export function WaitlistForm() {
interface WaitlistFormProps {
id?: string
}
export function WaitlistForm({ id }: WaitlistFormProps) {
const [email, setEmail] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const [isSuccess, setIsSuccess] = useState(false)
@@ -160,7 +164,7 @@ export function WaitlistForm() {
className="mt-6 inline-flex items-center gap-2 rounded-full bg-[hsl(var(--burgundy))]/10 border border-[hsl(var(--burgundy))]/30 px-4 py-2"
>
<span className="text-sm font-bold text-[hsl(var(--burgundy))]">
🎉 Early access: 50% off for 6 months
🎉 Early access
</span>
</motion.div>
</motion.div>
@@ -170,65 +174,69 @@ export function WaitlistForm() {
return (
<motion.form
id={id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
onSubmit={handleSubmit}
className="max-w-md mx-auto"
>
<div className="flex flex-col sm:flex-row gap-3">
{/* Email Input */}
<motion.div
className="flex-1 relative"
animate={error ? { x: [-10, 10, -10, 10, 0] } : {}}
transition={{ duration: 0.4 }}
>
<input
type="email"
value={email}
onChange={(e) => {
setEmail(e.target.value)
setError('')
}}
placeholder="Enter your email"
disabled={isSubmitting}
className={`w-full h-14 rounded-full px-6 text-base border-2 transition-all outline-none ${error
<div className="flex flex-col gap-3">
<div className="flex flex-col sm:flex-row gap-3">
{/* Email Input */}
<motion.div
className="flex-1 relative"
>
<input
type="email"
value={email}
onChange={(e) => {
setEmail(e.target.value)
setError('')
}}
placeholder="Enter your email"
disabled={isSubmitting}
className={`w-full h-14 rounded-full px-6 text-base border-2 transition-all outline-none ${error
? 'border-red-500 bg-red-50 focus:border-red-500 focus:ring-4 focus:ring-red-500/20'
: 'border-border bg-background focus:border-[hsl(var(--primary))] focus:ring-4 focus:ring-[hsl(var(--primary))]/20'
} disabled:opacity-50 disabled:cursor-not-allowed`}
/>
<AnimatePresence>
{error && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
className="absolute -bottom-6 left-4 text-xs font-medium text-red-500"
>
{error}
</motion.div>
)}
</AnimatePresence>
</motion.div>
} disabled:opacity-50 disabled:cursor-not-allowed`}
/>
</motion.div>
{/* Submit Button */}
<Button
type="submit"
disabled={isSubmitting || !email}
size="lg"
className="h-14 rounded-full bg-[hsl(var(--burgundy))] px-8 text-white hover:bg-[hsl(var(--burgundy))]/90 shadow-2xl shadow-[hsl(var(--burgundy))]/30 transition-all hover:scale-105 disabled:hover:scale-100 disabled:opacity-50 disabled:cursor-not-allowed font-bold text-base group whitespace-nowrap"
>
{isSubmitting ? (
<>
<Loader2 className="mr-2 h-5 w-5 animate-spin" />
Joining...
</>
) : (
<>
Reserve Your Spot
<ArrowRight className="ml-2 h-5 w-5 group-hover:translate-x-1 transition-transform" />
</>
{/* Submit Button */}
<Button
type="submit"
disabled={isSubmitting || !email}
size="lg"
className="h-14 rounded-full bg-[hsl(var(--burgundy))] px-8 text-white hover:bg-[hsl(var(--burgundy))]/90 shadow-2xl shadow-[hsl(var(--burgundy))]/30 transition-all hover:scale-105 disabled:hover:scale-100 disabled:opacity-50 disabled:cursor-not-allowed font-bold text-base group whitespace-nowrap"
>
{isSubmitting ? (
<>
<Loader2 className="mr-2 h-5 w-5 animate-spin" />
Joining...
</>
) : (
<>
Reserve Your Spot
<ArrowRight className="ml-2 h-5 w-5 group-hover:translate-x-1 transition-transform" />
</>
)}
</Button>
</div>
{/* Error Message - Visibility Improved */}
<AnimatePresence>
{error && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="text-red-600 bg-red-50 px-4 py-2 rounded-lg text-sm font-medium border border-red-100 flex items-center gap-2"
>
<div className="h-1.5 w-1.5 rounded-full bg-red-500 flex-shrink-0" />
{error}
</motion.div>
)}
</Button>
</AnimatePresence>
</div>
{/* Trust Signals Below Form */}