Rend les liens entre notes visibles et persistants (sync NoteLink au save, auto-save, graphe réseau rafraîchi), ajoute living blocks, Memory Echo, recherche globale, consentement IA explicite et consolide les prototypes design en architectural-grid. Co-authored-by: Cursor <cursoragent@cursor.com>
201 lines
10 KiB
TypeScript
201 lines
10 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { motion, AnimatePresence } from 'motion/react';
|
|
import { Mail, Lock, User, ArrowRight, Github, Globe, Sparkles } from 'lucide-react';
|
|
|
|
interface AuthPageProps {
|
|
onAuthComplete: () => void;
|
|
onBack: () => void;
|
|
initialMode?: 'login' | 'register';
|
|
}
|
|
|
|
export const AuthPage: React.FC<AuthPageProps> = ({ onAuthComplete, onBack, initialMode = 'login' }) => {
|
|
const [mode, setMode] = useState<'login' | 'register'>(initialMode);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setIsLoading(true);
|
|
// Simulate auth
|
|
setTimeout(() => {
|
|
setIsLoading(false);
|
|
onAuthComplete();
|
|
}, 1500);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[#FDFCFB] dark:bg-[#0D0D0D] flex flex-col relative overflow-hidden font-sans">
|
|
{/* Background Orbs */}
|
|
<div className="absolute top-[-10%] right-[-10%] w-[50%] h-[50%] bg-accent/5 blur-[120px] rounded-full" />
|
|
<div className="absolute bottom-[-10%] left-[-10%] w-[50%] h-[50%] bg-ochre/5 blur-[120px] rounded-full" />
|
|
|
|
{/* Header */}
|
|
<header className="p-8 flex justify-between items-center relative z-10">
|
|
<button
|
|
onClick={onBack}
|
|
className="flex items-center gap-2 text-concrete hover:text-ink transition-colors group"
|
|
>
|
|
<div className="w-8 h-8 rounded-full border border-border flex items-center justify-center group-hover:border-accent transition-colors">
|
|
<Globe size={14} className="group-hover:rotate-12 transition-transform" />
|
|
</div>
|
|
<span className="text-[10px] font-bold uppercase tracking-widest">Retour</span>
|
|
</button>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-8 h-8 bg-ink text-white rounded-xl flex items-center justify-center shadow-lg">
|
|
<span className="font-serif font-bold text-xl">M</span>
|
|
</div>
|
|
<span className="font-serif text-xl font-medium tracking-tight text-ink">Momento</span>
|
|
</div>
|
|
|
|
<div className="w-24" /> {/* Spacer */}
|
|
</header>
|
|
|
|
{/* Main Content */}
|
|
<main className="flex-1 flex items-center justify-center p-6 relative z-10">
|
|
<div className="w-full max-w-md">
|
|
<AnimatePresence mode="wait">
|
|
<motion.div
|
|
key={mode}
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -20 }}
|
|
transition={{ duration: 0.4, ease: [0.22, 1, 0.36, 1] }}
|
|
className="bg-white dark:bg-paper/50 border border-border p-10 rounded-[48px] shadow-2xl relative"
|
|
>
|
|
<div className="space-y-8">
|
|
<div className="text-center space-y-2">
|
|
<h1 className="text-3xl font-serif font-bold text-ink">
|
|
{mode === 'login' ? 'Bon retour parmi nous' : 'Créer votre espace'}
|
|
</h1>
|
|
<p className="text-concrete text-sm font-light">
|
|
{mode === 'login'
|
|
? 'Entrez vos identifiants pour accéder à vos notes.'
|
|
: 'Rejoignez la nouvelle ère de la prise de notes intelligente.'}
|
|
</p>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
{mode === 'register' && (
|
|
<div className="space-y-1.5">
|
|
<label className="text-[10px] uppercase tracking-widest font-bold text-concrete px-4">Nom complet</label>
|
|
<div className="relative group">
|
|
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-concrete group-focus-within:text-accent transition-colors">
|
|
<User size={16} />
|
|
</div>
|
|
<input
|
|
type="text"
|
|
placeholder="Jean Dupont"
|
|
className="w-full bg-slate-50 dark:bg-white/5 border border-border rounded-2xl py-4 pl-12 pr-4 text-sm outline-none focus:border-accent focus:ring-4 ring-accent/5 transition-all"
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-1.5">
|
|
<label className="text-[10px] uppercase tracking-widest font-bold text-concrete px-4">Email</label>
|
|
<div className="relative group">
|
|
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-concrete group-focus-within:text-accent transition-colors">
|
|
<Mail size={16} />
|
|
</div>
|
|
<input
|
|
type="email"
|
|
placeholder="jean@exemple.com"
|
|
className="w-full bg-slate-50 dark:bg-white/5 border border-border rounded-2xl py-4 pl-12 pr-4 text-sm outline-none focus:border-accent focus:ring-4 ring-accent/5 transition-all"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-1.5">
|
|
<div className="flex justify-between items-center px-4">
|
|
<label className="text-[10px] uppercase tracking-widest font-bold text-concrete">Mot de passe</label>
|
|
{mode === 'login' && (
|
|
<button type="button" className="text-[10px] text-accent font-bold uppercase tracking-widest hover:underline">Oublié ?</button>
|
|
)}
|
|
</div>
|
|
<div className="relative group">
|
|
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-concrete group-focus-within:text-accent transition-colors">
|
|
<Lock size={16} />
|
|
</div>
|
|
<input
|
|
type="password"
|
|
placeholder="••••••••"
|
|
className="w-full bg-slate-50 dark:bg-white/5 border border-border rounded-2xl py-4 pl-12 pr-4 text-sm outline-none focus:border-accent focus:ring-4 ring-accent/5 transition-all"
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={isLoading}
|
|
className="w-full bg-ink text-white py-4 rounded-2xl font-bold uppercase tracking-[0.2em] text-[10px] flex items-center justify-center gap-3 transition-all hover:shadow-xl hover:shadow-ink/20 active:scale-95 disabled:opacity-50 mt-4 overflow-hidden relative"
|
|
>
|
|
{isLoading ? (
|
|
<motion.div
|
|
animate={{ rotate: 360 }}
|
|
transition={{ repeat: Infinity, duration: 1, ease: 'linear' }}
|
|
>
|
|
<Sparkles size={16} />
|
|
</motion.div>
|
|
) : (
|
|
<>
|
|
{mode === 'login' ? 'Se connecter' : 'Créer mon compte'}
|
|
<ArrowRight size={14} />
|
|
</>
|
|
)}
|
|
</button>
|
|
</form>
|
|
|
|
<div className="relative">
|
|
<div className="absolute inset-0 flex items-center">
|
|
<div className="w-full border-t border-border" />
|
|
</div>
|
|
<div className="relative flex justify-center text-[10px] uppercase tracking-widest font-bold">
|
|
<span className="bg-white dark:bg-dark-paper px-4 text-concrete">Ou continuer avec</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<button className="flex items-center justify-center gap-3 py-3 border border-border rounded-xl hover:bg-slate-50 dark:hover:bg-white/5 transition-all group">
|
|
<div className="w-4 h-4 bg-white rounded-full flex items-center justify-center">
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" 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.1c-.22-.66-.35-1.36-.35-2.1s.13-1.44.35-2.1V7.06H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.94l3.66-2.84z" fill="#FBBC05"/>
|
|
<path d="M12 5.38c1.62 0 3.06.56 4.21 1.66l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.06l3.66 2.84c.87-2.6 3.3-4.52 6.16-4.52z" fill="#EA4335"/>
|
|
</svg>
|
|
</div>
|
|
<span className="text-[10px] font-bold uppercase tracking-widest text-ink">Google</span>
|
|
</button>
|
|
<button className="flex items-center justify-center gap-3 py-3 border border-border rounded-xl hover:bg-slate-50 dark:hover:bg-white/5 transition-all group">
|
|
<Github size={16} className="text-ink" />
|
|
<span className="text-[10px] font-bold uppercase tracking-widest text-ink">GitHub</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div className="text-center pt-4">
|
|
<p className="text-xs text-concrete">
|
|
{mode === 'login' ? "Vous n'avez pas de compte ?" : "Vous avez déjà un compte ?"}
|
|
{' '}
|
|
<button
|
|
onClick={() => setMode(mode === 'login' ? 'register' : 'login')}
|
|
className="text-accent font-bold hover:underline"
|
|
>
|
|
{mode === 'login' ? "S'inscrire" : "Se connecter"}
|
|
</button>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
|
|
<p className="text-center mt-8 text-[9px] text-concrete font-bold uppercase tracking-[0.3em] opacity-40">
|
|
© 2024 Momento Labs — Privacy • Terms
|
|
</p>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
};
|