se mejora el login
This commit is contained in:
1 parent
ae415fef4e
commit
155bd60b5f
4 files changed
+366
-398
No files matched your search
+1
-1
@@ -96,7 +96,7 @@ export function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-slate-950 text-slate-100 flex flex-col selection:bg-cyan-500 selection:text-slate-950">
|
<div className="min-h-screen bg-slate-950 text-slate-100 flex flex-col selection:bg-cyan-500 selection:text-slate-950">
|
||||||
|
|
||||||
{/* Toast notification banner */}
|
{/* Toast notification banner */}
|
||||||
{toastMessage && (
|
{toastMessage && (
|
||||||
<div className="fixed bottom-6 right-6 z-50 flex items-center gap-3 px-5 py-3.5 rounded-2xl bg-slate-900/95 border border-cyan-500/40 text-white shadow-2xl shadow-cyan-500/20 backdrop-blur-md animate-in slide-in-from-bottom-5 duration-300">
|
<div className="fixed bottom-6 right-6 z-50 flex items-center gap-3 px-5 py-3.5 rounded-2xl bg-slate-900/95 border border-cyan-500/40 text-white shadow-2xl shadow-cyan-500/20 backdrop-blur-md animate-in slide-in-from-bottom-5 duration-300">
|
||||||
|
|||||||
+47
-17
@@ -26,30 +26,39 @@
|
|||||||
background: #475569;
|
background: #475569;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cart Running Animation */
|
/* Full-Screen Crossing Flying Spaceship Animation */
|
||||||
@keyframes cart-run {
|
@keyframes float-spaceship {
|
||||||
0% {
|
0% {
|
||||||
transform: translateX(0) rotate(0deg) translateY(0);
|
transform: translate(-10vw, 68vh) rotate(23deg) scale(0.65);
|
||||||
|
opacity: 0.1;
|
||||||
}
|
}
|
||||||
20% {
|
|
||||||
transform: translateX(3px) rotate(-10deg) translateY(-2px);
|
15% {
|
||||||
|
opacity: 0.85;
|
||||||
}
|
}
|
||||||
40% {
|
|
||||||
transform: translateX(1px) rotate(-5deg) translateY(1px);
|
35% {
|
||||||
|
transform: translate(30vw, 45vh) rotate(25deg) scale(0.85);
|
||||||
|
opacity: 0.95;
|
||||||
}
|
}
|
||||||
60% {
|
|
||||||
transform: translateX(4px) rotate(-12deg) translateY(-2px);
|
65% {
|
||||||
|
transform: translate(65vw, 25vh) rotate(22deg) scale(1);
|
||||||
|
opacity: 0.95;
|
||||||
}
|
}
|
||||||
80% {
|
|
||||||
transform: translateX(2px) rotate(-8deg) translateY(0px);
|
85% {
|
||||||
|
opacity: 0.85;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: translateX(0) rotate(0deg) translateY(0);
|
transform: translate(110vw, 5vh) rotate(24deg) scale(0.7);
|
||||||
|
opacity: 0.1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.animate-cart-run {
|
.animate-spaceship {
|
||||||
animation: cart-run 0.5s ease-in-out infinite;
|
animation: float-spaceship 20s cubic-bezier(0.35, 0, 0.25, 1) infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Speed Streaks for Cart */
|
/* Speed Streaks for Cart */
|
||||||
@@ -58,10 +67,12 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(0) scaleX(0.2);
|
transform: translateX(0) scaleX(0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transform: translateX(-8px) scaleX(1);
|
transform: translateX(-8px) scaleX(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-16px) scaleX(0);
|
transform: translateX(-16px) scaleX(0);
|
||||||
@@ -77,23 +88,42 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-hover\\:animate-cart-run:hover .speed-line-1 {
|
.group:hover .speed-line-1 {
|
||||||
animation: speed-streak 0.6s infinite linear;
|
animation: speed-streak 0.6s infinite linear;
|
||||||
top: 30%;
|
top: 30%;
|
||||||
right: 110%;
|
right: 110%;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-hover\\:animate-cart-run:hover .speed-line-2 {
|
.group:hover .speed-line-2 {
|
||||||
animation: speed-streak 0.5s infinite linear 0.2s;
|
animation: speed-streak 0.5s infinite linear 0.2s;
|
||||||
top: 60%;
|
top: 60%;
|
||||||
right: 100%;
|
right: 100%;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-hover\\:animate-cart-run:hover .speed-line-3 {
|
.group:hover .speed-line-3 {
|
||||||
animation: speed-streak 0.7s infinite linear 0.4s;
|
animation: speed-streak 0.7s infinite linear 0.4s;
|
||||||
bottom: 10%;
|
bottom: 10%;
|
||||||
right: 120%;
|
right: 120%;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Twinkling Star Particles Animation */
|
||||||
|
@keyframes star-twinkle {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 0.15;
|
||||||
|
transform: scale(0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.95;
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-twinkle {
|
||||||
|
animation: star-twinkle 3s ease-in-out infinite alternate;
|
||||||
}
|
}
|
||||||
+165
-210
@@ -1,18 +1,15 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useNavigate, Link } from 'react-router';
|
import { useNavigate, Link } from 'react-router';
|
||||||
import { BrandLogo } from '../components/common/BrandLogo';
|
import { BrandLogo } from '../components/common/BrandLogo';
|
||||||
import {
|
import {
|
||||||
FiMail,
|
FiMail,
|
||||||
FiLock,
|
FiLock,
|
||||||
FiEye,
|
FiEye,
|
||||||
FiEyeOff,
|
FiEyeOff,
|
||||||
FiArrowRight,
|
FiArrowRight,
|
||||||
FiArrowLeft,
|
FiArrowLeft,
|
||||||
FiStar,
|
FiCheckCircle,
|
||||||
FiCheckCircle,
|
FiLoader
|
||||||
FiBookOpen,
|
|
||||||
FiAward,
|
|
||||||
FiUsers
|
|
||||||
} from 'react-icons/fi';
|
} from 'react-icons/fi';
|
||||||
import type { User } from '../types/course';
|
import type { User } from '../types/course';
|
||||||
|
|
||||||
@@ -27,223 +24,173 @@ export const LoginView: React.FC<LoginViewProps> = ({ onShowToast, onLogin }) =>
|
|||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [rememberMe, setRememberMe] = useState(true);
|
const [rememberMe, setRememberMe] = useState(true);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleMockLogin = (name: string, role: 'buyer' | 'seller', avatarUrl?: string) => {
|
const isValidEmail = email.includes('@') && email.includes('.');
|
||||||
const mockUser: User = {
|
|
||||||
id: Math.random().toString(36).substr(2, 9),
|
|
||||||
name,
|
|
||||||
email: email || `${role}@rycourses.com`,
|
|
||||||
role,
|
|
||||||
avatar: avatarUrl || 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',
|
|
||||||
};
|
|
||||||
onLogin(mockUser);
|
|
||||||
onShowToast(`¡Bienvenido de nuevo, ${name}!`);
|
|
||||||
navigate(role === 'seller' ? '/seller' : '/courses');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (email && password) {
|
if (!email || !password) return;
|
||||||
handleMockLogin('Usuario Estudiante', 'buyer');
|
|
||||||
}
|
setIsLoading(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
let derivedName = 'Usuario RyCourses';
|
||||||
|
if (email.includes('@')) {
|
||||||
|
const rawName = email.split('@')[0];
|
||||||
|
derivedName = rawName
|
||||||
|
.replace(/[._-]/g, ' ')
|
||||||
|
.replace(/\b\w/g, (char) => char.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSeller = email.toLowerCase().includes('instructor') || email.toLowerCase().includes('seller');
|
||||||
|
const role: 'buyer' | 'seller' = isSeller ? 'seller' : 'buyer';
|
||||||
|
|
||||||
|
const userObj: User = {
|
||||||
|
id: Math.random().toString(36).substring(2, 11),
|
||||||
|
name: derivedName,
|
||||||
|
email,
|
||||||
|
role,
|
||||||
|
avatar: role === 'seller'
|
||||||
|
? 'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=100&auto=format&fit=crop&q=80'
|
||||||
|
: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',
|
||||||
|
};
|
||||||
|
|
||||||
|
onLogin(userObj);
|
||||||
|
onShowToast(`¡Bienvenido de nuevo, ${derivedName}!`);
|
||||||
|
setIsLoading(false);
|
||||||
|
navigate(role === 'seller' ? '/seller' : '/courses');
|
||||||
|
}, 450);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen grid grid-cols-1 lg:grid-cols-12 bg-slate-950 text-slate-100 font-sans selection:bg-cyan-500 selection:text-slate-950 relative overflow-hidden">
|
<div className="min-h-screen flex flex-col justify-between bg-slate-950 text-slate-100 font-sans selection:bg-cyan-500 selection:text-slate-950 relative overflow-hidden p-6 sm:p-10 lg:p-12">
|
||||||
|
|
||||||
{/* Ambient background glow */}
|
|
||||||
<div className="absolute -top-40 -left-40 w-96 h-96 bg-cyan-600/15 rounded-full blur-[120px] pointer-events-none" />
|
|
||||||
<div className="absolute top-1/2 right-1/3 w-80 h-80 bg-blue-600/10 rounded-full blur-[140px] pointer-events-none" />
|
|
||||||
|
|
||||||
{/* ============================================================== */}
|
{/* Top-Right Background Radial Gradient Glow (RyCourses Cyan & Blue Brand Colors) */}
|
||||||
{/* LEFT COLUMN: BRANDING & GRAPHIC BANNER */}
|
<div
|
||||||
{/* ============================================================== */}
|
className="absolute -top-32 -right-32 w-[600px] sm:w-[850px] h-[600px] sm:h-[850px] rounded-full pointer-events-none opacity-35 blur-[150px]"
|
||||||
<div className="hidden lg:flex lg:col-span-6 xl:col-span-7 relative flex-col justify-between p-10 xl:p-14 overflow-hidden bg-slate-900/40 border-r border-slate-800/60">
|
style={{
|
||||||
|
background: 'radial-gradient(circle at center, rgba(6, 182, 212, 0.45) 0%, rgba(37, 99, 235, 0.3) 45%, transparent 70%)'
|
||||||
{/* Decorative Grid and Ambient Lights */}
|
}}
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(#334155_1px,transparent_1px)] [background-size:20px_20px] opacity-25" />
|
/>
|
||||||
<div className="absolute top-1/4 left-10 w-96 h-96 bg-cyan-500/20 rounded-full blur-[140px] pointer-events-none" />
|
<div className="absolute bottom-0 left-0 w-[450px] h-[450px] rounded-full pointer-events-none opacity-20 blur-[160px] bg-blue-900/30" />
|
||||||
<div className="absolute bottom-10 right-10 w-96 h-96 bg-blue-600/20 rounded-full blur-[140px] pointer-events-none" />
|
<div className="absolute inset-0 bg-[radial-gradient(#334155_1px,transparent_1px)] [background-size:24px_24px] opacity-10 pointer-events-none" />
|
||||||
|
|
||||||
{/* Brand Header Banner */}
|
{/* Interactive Background Atmosphere: Twinkling Star Particles & Flying Space Shuttle */}
|
||||||
<div className="relative z-10 flex items-center justify-between">
|
<div className="absolute inset-0 pointer-events-none overflow-hidden z-0">
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<BrandLogo size="lg" showSubtitle={true} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5 px-3.5 py-1.5 rounded-full bg-slate-900/80 border border-slate-700/60 text-xs font-semibold text-slate-300 backdrop-blur-md">
|
|
||||||
<FiCheckCircle className="text-emerald-400" />
|
|
||||||
<span>+1,200 Cursos Disponibles</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Hero Illustration Box */}
|
{/* Twinkling Star Field */}
|
||||||
<div className="relative z-10 my-auto py-6 max-w-2xl mx-auto w-full">
|
<div className="absolute top-12 left-1/6 w-1.5 h-1.5 rounded-full bg-cyan-300 animate-twinkle opacity-75" style={{ animationDelay: '0s' }} />
|
||||||
|
<div className="absolute top-1/4 right-1/5 w-2 h-2 rounded-full bg-blue-300 animate-twinkle opacity-85" style={{ animationDelay: '1.4s' }} />
|
||||||
{/* Main Visual Frame */}
|
<div className="absolute top-1/3 left-1/4 w-1 h-1 rounded-full bg-teal-200 animate-twinkle opacity-70" style={{ animationDelay: '2.1s' }} />
|
||||||
<div className="relative rounded-3xl p-1.5 bg-gradient-to-b from-slate-700/60 via-slate-800/40 to-cyan-500/30 border border-slate-700/80 shadow-2xl backdrop-blur-md group">
|
<div className="absolute top-1/2 right-1/3 w-1.5 h-1.5 rounded-full bg-cyan-200 animate-twinkle opacity-80" style={{ animationDelay: '0.6s' }} />
|
||||||
|
<div className="absolute top-2/3 left-1/5 w-2 h-2 rounded-full bg-cyan-400 animate-twinkle opacity-75" style={{ animationDelay: '1.8s' }} />
|
||||||
{/* Embedded 3D Learning Image */}
|
<div className="absolute bottom-1/4 right-1/4 w-1.5 h-1.5 rounded-full bg-blue-200 animate-twinkle opacity-65" style={{ animationDelay: '2.8s' }} />
|
||||||
<div className="relative overflow-hidden rounded-[20px] aspect-[4/3]">
|
<div className="absolute bottom-1/3 left-2/3 w-1 h-1 rounded-full bg-cyan-300 animate-twinkle opacity-80" style={{ animationDelay: '0.3s' }} />
|
||||||
<img
|
<div className="absolute top-16 right-1/3 w-1.5 h-1.5 rounded-full bg-teal-300 animate-twinkle opacity-70" style={{ animationDelay: '1.1s' }} />
|
||||||
src="/login-banner.jpg"
|
<div className="absolute bottom-20 left-1/3 w-2 h-2 rounded-full bg-blue-400 animate-twinkle opacity-75" style={{ animationDelay: '2.5s' }} />
|
||||||
alt="Aprende y crece en RyCourses"
|
<div className="absolute top-3/4 right-1/6 w-1 h-1 rounded-full bg-cyan-100 animate-twinkle opacity-80" style={{ animationDelay: '0.9s' }} />
|
||||||
className="w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-700"
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-slate-950 via-slate-950/20 to-transparent" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Top Badge Overlay */}
|
{/* Crossing Space Shuttle Rocket */}
|
||||||
<div className="absolute top-5 left-5 z-20 flex items-center gap-2 py-1.5 px-3.5 rounded-full bg-slate-950/80 border border-cyan-500/40 text-cyan-300 text-xs font-bold shadow-lg backdrop-blur-md">
|
<div className="absolute top-0 left-0 animate-spaceship">
|
||||||
<FiStar className="text-yellow-400 fill-yellow-400" />
|
<svg className="w-16 h-16 sm:w-20 sm:h-20 filter drop-shadow-[0_0_25px_rgba(6,182,212,0.8)]" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<span>Aprende con Tecnologías Reales</span>
|
{/* Plasma Rocket Flame Trail */}
|
||||||
</div>
|
<path d="M22 78L10 90L26 84L14 98L30 86L22 78Z" fill="url(#plasmaFlame)" className="animate-pulse" />
|
||||||
|
|
||||||
{/* Bottom Overlay Card */}
|
{/* Main Rocket Fuselage Body */}
|
||||||
<div className="absolute bottom-5 left-5 right-5 z-20 p-4 rounded-2xl bg-slate-950/85 border border-slate-800/90 shadow-2xl backdrop-blur-xl space-y-2">
|
<path d="M78 22C62 26 42 42 34 58L26 62L38 74L42 66C58 58 74 38 78 22Z" fill="url(#rocketBodyGradient)" stroke="#38bdf8" strokeWidth="2" strokeLinejoin="round" />
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="w-10 h-10 rounded-xl bg-cyan-500/20 border border-cyan-500/40 flex items-center justify-center text-cyan-400 font-bold text-lg">
|
|
||||||
🚀
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-xs font-bold text-white tracking-tight">
|
|
||||||
Aumenta tus habilidades profesionales
|
|
||||||
</p>
|
|
||||||
<p className="text-[11px] text-slate-400">
|
|
||||||
Cursos prácticos creados por mentores de la industria.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="hidden sm:flex items-center gap-1 bg-amber-500/10 px-2.5 py-1 rounded-lg border border-amber-500/30 text-amber-300 text-xs font-extrabold">
|
{/* Nose Cone Tip */}
|
||||||
<FiStar className="fill-amber-400 text-amber-400" />
|
<path d="M78 22C74 23 68 28 64 34L66 36C72 32 77 26 78 22Z" fill="#22d3ee" />
|
||||||
<span>4.9 / 5.0</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
{/* Left Booster Fin */}
|
||||||
|
<path d="M34 58L16 64L24 50L30 52Z" fill="#0284c7" stroke="#38bdf8" strokeWidth="1.5" strokeLinejoin="round" />
|
||||||
|
|
||||||
</div>
|
{/* Right Booster Fin */}
|
||||||
|
<path d="M42 66L48 84L50 76L46 70Z" fill="#0284c7" stroke="#38bdf8" strokeWidth="1.5" strokeLinejoin="round" />
|
||||||
|
|
||||||
{/* Feature Highlights Grid */}
|
{/* Porthole Window 1 */}
|
||||||
<div className="relative z-10 grid grid-cols-3 gap-4 pt-4 border-t border-slate-800/60">
|
<circle cx="58" cy="42" r="5" fill="#0f172a" stroke="#38bdf8" strokeWidth="1.5" />
|
||||||
<div className="flex items-center gap-3 p-3 rounded-2xl bg-slate-900/60 border border-slate-800/60">
|
<circle cx="58" cy="42" r="3.5" fill="#22d3ee" />
|
||||||
<div className="w-9 h-9 rounded-xl bg-cyan-500/10 border border-cyan-500/30 flex items-center justify-center text-cyan-400 shrink-0">
|
<circle cx="59.5" cy="40.5" r="1" fill="#ffffff" />
|
||||||
<FiBookOpen className="text-base" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-xs font-bold text-white">Acceso De Por Vida</p>
|
|
||||||
<p className="text-[10px] text-slate-400">Estudia a tu propio ritmo</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-3 p-3 rounded-2xl bg-slate-900/60 border border-slate-800/60">
|
{/* Porthole Window 2 */}
|
||||||
<div className="w-9 h-9 rounded-xl bg-blue-500/10 border border-blue-500/30 flex items-center justify-center text-blue-400 shrink-0">
|
<circle cx="48" cy="52" r="4" fill="#0f172a" stroke="#38bdf8" strokeWidth="1.5" />
|
||||||
<FiAward className="text-base" />
|
<circle cx="48" cy="52" r="2.5" fill="#22d3ee" />
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-xs font-bold text-white">Certificados</p>
|
|
||||||
<p className="text-[10px] text-slate-400">Acredita tus proyectos</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-3 p-3 rounded-2xl bg-slate-900/60 border border-slate-800/60">
|
<defs>
|
||||||
<div className="w-9 h-9 rounded-xl bg-emerald-500/10 border border-emerald-500/30 flex items-center justify-center text-emerald-400 shrink-0">
|
<linearGradient id="plasmaFlame" x1="30" y1="78" x2="10" y2="98" gradientUnits="userSpaceOnUse">
|
||||||
<FiUsers className="text-base" />
|
<stop stopColor="#38bdf8" />
|
||||||
</div>
|
<stop offset="0.5" stopColor="#06b6d4" />
|
||||||
<div>
|
<stop offset="1" stopColor="transparent" />
|
||||||
<p className="text-xs font-bold text-white">+50,000 Alumnos</p>
|
</linearGradient>
|
||||||
<p className="text-[10px] text-slate-400">Comunidad global activa</p>
|
<linearGradient id="rocketBodyGradient" x1="78" y1="22" x2="26" y2="74" gradientUnits="userSpaceOnUse">
|
||||||
</div>
|
<stop stopColor="#e0f2fe" />
|
||||||
</div>
|
<stop offset="0.4" stopColor="#38bdf8" />
|
||||||
|
<stop offset="0.8" stopColor="#0284c7" />
|
||||||
|
<stop offset="1" stopColor="#0f172a" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ============================================================== */}
|
{/* Top Navigation Bar (Only Back Link, No duplicate logo) */}
|
||||||
{/* RIGHT COLUMN: FORM & AUTHENTICATION */}
|
<div className="w-full max-w-6xl mx-auto flex items-center justify-end z-10 pt-2 pb-4">
|
||||||
{/* ============================================================== */}
|
<Link
|
||||||
<div className="lg:col-span-6 xl:col-span-5 flex flex-col justify-between p-6 sm:p-10 lg:p-12 z-10 bg-slate-950/90 backdrop-blur-2xl border-l border-slate-800/80">
|
to="/"
|
||||||
|
className="flex items-center gap-1.5 text-xs font-medium text-slate-400 hover:text-white transition-colors py-1.5 px-3.5 rounded-xl bg-slate-900/80 border border-slate-800 hover:border-slate-700 backdrop-blur-md"
|
||||||
{/* Top Header Navigation */}
|
>
|
||||||
<div className="flex items-center justify-between">
|
<FiArrowLeft className="text-sm" />
|
||||||
<Link to="/" className="inline-flex items-center gap-2 lg:hidden">
|
<span>Volver al inicio</span>
|
||||||
<BrandLogo size="md" showSubtitle={false} />
|
</Link>
|
||||||
</Link>
|
</div>
|
||||||
|
|
||||||
<div className="hidden lg:block" />
|
|
||||||
|
|
||||||
<Link
|
{/* Main Login Card Container */}
|
||||||
to="/"
|
<div className="my-auto w-full max-w-md mx-auto z-10">
|
||||||
className="flex items-center gap-1.5 text-xs font-semibold text-slate-400 hover:text-cyan-400 transition-colors py-2 px-3 rounded-xl bg-slate-900/80 border border-slate-800 hover:border-cyan-500/40"
|
<div className="relative p-6 sm:p-8 rounded-2xl bg-slate-900/75 border border-slate-800/90 shadow-2xl backdrop-blur-xl space-y-6">
|
||||||
>
|
|
||||||
<FiArrowLeft className="text-sm" />
|
|
||||||
<span>Volver al inicio</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Login Form Main Container */}
|
{/* Subtle Top Border Gradient Accent */}
|
||||||
<div className="my-auto py-8 max-w-md w-full mx-auto space-y-7">
|
<div className="absolute top-0 left-6 right-6 h-[1.5px] bg-gradient-to-r from-transparent via-cyan-500/60 to-transparent pointer-events-none" />
|
||||||
|
|
||||||
{/* Section Titles */}
|
{/* Centered Brand Logo & Titles inside Form Card */}
|
||||||
<div className="space-y-2">
|
<div className="text-center space-y-2 pt-1">
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-cyan-500/10 border border-cyan-500/20 text-cyan-400 text-xs font-medium">
|
<div className="flex justify-center pb-1">
|
||||||
<span className="w-2 h-2 rounded-full bg-cyan-400 animate-pulse" />
|
<BrandLogo size="lg" showSubtitle={true} />
|
||||||
Tu Portal Educativo
|
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-3xl sm:text-4xl font-extrabold text-white tracking-tight">
|
<h1 className="text-2xl sm:text-3xl font-bold text-white tracking-tight pt-2">
|
||||||
¡Hola de nuevo! <span className="inline-block animate-bounce">👋</span>
|
Iniciar Sesión
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xs sm:text-sm text-slate-400">
|
<p className="text-xs sm:text-sm text-slate-400">
|
||||||
Ingresa tus credenciales para continuar tu ruta de aprendizaje
|
Ingresa tus credenciales para acceder a tu cuenta.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Quick Demo Access Bar */}
|
{/* Form */}
|
||||||
<div className="p-3.5 rounded-2xl bg-slate-900/90 border border-slate-800 space-y-2">
|
|
||||||
<p className="text-[11px] font-semibold text-slate-400 uppercase tracking-wider">
|
|
||||||
Acceso Rápido Demo:
|
|
||||||
</p>
|
|
||||||
<div className="grid grid-cols-2 gap-2">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleMockLogin('Carlos Estudiante', 'buyer', 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80')}
|
|
||||||
className="flex items-center justify-center gap-2 py-2 px-3 rounded-xl bg-slate-800/80 hover:bg-cyan-950/60 border border-slate-700 hover:border-cyan-500/50 text-xs font-medium text-slate-200 hover:text-cyan-300 transition group"
|
|
||||||
>
|
|
||||||
<FiBookOpen className="text-cyan-400 group-hover:scale-110 transition-transform" />
|
|
||||||
<span>Como Estudiante</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleMockLogin('Dra. Elena Instructor', 'seller', 'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=100&auto=format&fit=crop&q=80')}
|
|
||||||
className="flex items-center justify-center gap-2 py-2 px-3 rounded-xl bg-slate-800/80 hover:bg-violet-950/60 border border-slate-700 hover:border-violet-500/50 text-xs font-medium text-slate-200 hover:text-violet-300 transition group"
|
|
||||||
>
|
|
||||||
<FiUsers className="text-violet-400 group-hover:scale-110 transition-transform" />
|
|
||||||
<span>Como Instructor</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Login Form */}
|
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
|
||||||
{/* Email field */}
|
{/* Email field */}
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs font-semibold text-slate-300 mb-1.5">
|
<div className="flex items-center justify-between mb-1.5">
|
||||||
Correo Electrónico
|
<label className="block text-xs font-medium text-slate-300">
|
||||||
</label>
|
Correo electrónico
|
||||||
|
</label>
|
||||||
|
{isValidEmail && (
|
||||||
|
<span className="flex items-center gap-1 text-[11px] text-emerald-400 font-medium animate-fadeIn">
|
||||||
|
<FiCheckCircle className="text-xs" /> Formato válido
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FiMail className="absolute left-3.5 top-3.5 text-slate-500 text-base" />
|
<FiMail className="absolute left-3.5 top-3.5 text-slate-500 text-base pointer-events-none" />
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
required
|
required
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
placeholder="estudiante@ejemplo.com"
|
placeholder="nombre@empresa.com"
|
||||||
className="w-full pl-10 pr-4 py-3 bg-slate-900/90 border border-slate-800 focus:border-cyan-500 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/30 transition"
|
className="w-full pl-10 pr-4 py-2.5 bg-slate-950/80 border border-slate-800 focus:border-cyan-500 focus:ring-2 focus:ring-cyan-500/20 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none transition-all"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -251,7 +198,7 @@ export const LoginView: React.FC<LoginViewProps> = ({ onShowToast, onLogin }) =>
|
|||||||
{/* Password field */}
|
{/* Password field */}
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between mb-1.5">
|
<div className="flex items-center justify-between mb-1.5">
|
||||||
<label className="block text-xs font-semibold text-slate-300">
|
<label className="block text-xs font-medium text-slate-300">
|
||||||
Contraseña
|
Contraseña
|
||||||
</label>
|
</label>
|
||||||
<a href="#" className="text-[11px] font-medium text-cyan-400 hover:text-cyan-300 hover:underline transition">
|
<a href="#" className="text-[11px] font-medium text-cyan-400 hover:text-cyan-300 hover:underline transition">
|
||||||
@@ -259,19 +206,20 @@ export const LoginView: React.FC<LoginViewProps> = ({ onShowToast, onLogin }) =>
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FiLock className="absolute left-3.5 top-3.5 text-slate-500 text-base" />
|
<FiLock className="absolute left-3.5 top-3.5 text-slate-500 text-base pointer-events-none" />
|
||||||
<input
|
<input
|
||||||
type={showPassword ? 'text' : 'password'}
|
type={showPassword ? 'text' : 'password'}
|
||||||
required
|
required
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
placeholder="••••••••"
|
placeholder="••••••••"
|
||||||
className="w-full pl-10 pr-10 py-3 bg-slate-900/90 border border-slate-800 focus:border-cyan-500 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/30 transition"
|
className="w-full pl-10 pr-10 py-2.5 bg-slate-950/80 border border-slate-800 focus:border-cyan-500 focus:ring-2 focus:ring-cyan-500/20 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none transition-all"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
onClick={() => setShowPassword(!showPassword)}
|
||||||
className="absolute right-3.5 top-3.5 text-slate-500 hover:text-slate-300 transition"
|
className="absolute right-3.5 top-3 text-slate-500 hover:text-slate-300 transition cursor-pointer"
|
||||||
|
title={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
|
||||||
>
|
>
|
||||||
{showPassword ? <FiEyeOff className="text-base" /> : <FiEye className="text-base" />}
|
{showPassword ? <FiEyeOff className="text-base" /> : <FiEye className="text-base" />}
|
||||||
</button>
|
</button>
|
||||||
@@ -279,47 +227,54 @@ export const LoginView: React.FC<LoginViewProps> = ({ onShowToast, onLogin }) =>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Remember Me */}
|
{/* Remember Me */}
|
||||||
<div className="flex items-center justify-between pt-1">
|
<div className="flex items-center justify-between pt-0.5">
|
||||||
<label className="flex items-center gap-2 cursor-pointer text-xs text-slate-400 hover:text-slate-300">
|
<label className="flex items-center gap-2 cursor-pointer text-xs text-slate-400 hover:text-slate-300">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={rememberMe}
|
checked={rememberMe}
|
||||||
onChange={(e) => setRememberMe(e.target.checked)}
|
onChange={(e) => setRememberMe(e.target.checked)}
|
||||||
className="rounded border-slate-700 bg-slate-900 text-cyan-500 focus:ring-cyan-500/50"
|
className="rounded border-slate-800 bg-slate-950 text-cyan-500 focus:ring-cyan-500/50"
|
||||||
/>
|
/>
|
||||||
<span>Recordar este dispositivo</span>
|
<span>Recordar sesión</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full py-3.5 px-4 bg-gradient-to-r from-blue-600 via-cyan-500 to-teal-400 hover:opacity-95 text-white font-bold rounded-xl text-xs sm:text-sm shadow-lg shadow-cyan-500/25 transition-all flex items-center justify-center gap-2 group cursor-pointer"
|
disabled={isLoading}
|
||||||
|
className="w-full py-3 px-4 bg-gradient-to-r from-cyan-500 to-blue-500 hover:from-cyan-400 hover:to-blue-400 text-slate-950 font-bold rounded-xl text-xs sm:text-sm shadow-lg shadow-cyan-500/20 active:scale-[0.99] transition-all flex items-center justify-center gap-2 cursor-pointer disabled:opacity-60"
|
||||||
>
|
>
|
||||||
<span>Ingresar a RyCourses</span>
|
{isLoading ? (
|
||||||
<FiArrowRight className="text-base group-hover:translate-x-1 transition-transform" />
|
<>
|
||||||
|
<FiLoader className="text-base animate-spin" />
|
||||||
|
<span>Verificando credenciales...</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<span>Acceder a la cuenta</span>
|
||||||
|
<FiArrowRight className="text-base" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Register Callout */}
|
{/* Register Callout */}
|
||||||
<div className="text-center text-xs text-slate-400 pt-2 border-t border-slate-900">
|
<div className="text-center text-xs text-slate-400 pt-3 border-t border-slate-800/80">
|
||||||
¿Aún no eres miembro de RyCourses?{' '}
|
¿Aún no tienes una cuenta?{' '}
|
||||||
<Link to="/register" className="text-cyan-400 font-bold hover:text-cyan-300 hover:underline transition">
|
<Link to="/register" className="text-cyan-400 font-semibold hover:text-cyan-300 hover:underline transition">
|
||||||
Regístrate gratis aquí
|
Regístrate aquí
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Footer info */}
|
{/* Footer info */}
|
||||||
<div className="text-center lg:text-left text-[11px] text-slate-600">
|
<div className="w-full max-w-6xl mx-auto text-center text-[11px] text-slate-600 z-10 pt-4 pb-2">
|
||||||
© 2026 RyCourses Platform. Todos los derechos reservados.
|
© 2026 RyCourses. Todos los derechos reservados.
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
+153
-170
@@ -1,19 +1,16 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useNavigate, Link } from 'react-router';
|
import { useNavigate, Link } from 'react-router';
|
||||||
import { BrandLogo } from '../components/common/BrandLogo';
|
import { BrandLogo } from '../components/common/BrandLogo';
|
||||||
import {
|
import {
|
||||||
FiMail,
|
FiMail,
|
||||||
FiLock,
|
FiLock,
|
||||||
FiUser,
|
FiUser,
|
||||||
FiArrowRight,
|
FiArrowRight,
|
||||||
FiArrowLeft,
|
FiArrowLeft,
|
||||||
FiCheckCircle,
|
FiCheckCircle,
|
||||||
FiStar,
|
|
||||||
FiBookOpen,
|
|
||||||
FiAward,
|
|
||||||
FiUsers,
|
|
||||||
FiEye,
|
FiEye,
|
||||||
FiEyeOff
|
FiEyeOff,
|
||||||
|
FiLoader
|
||||||
} from 'react-icons/fi';
|
} from 'react-icons/fi';
|
||||||
import { FaGraduationCap, FaChalkboardTeacher } from 'react-icons/fa';
|
import { FaGraduationCap, FaChalkboardTeacher } from 'react-icons/fa';
|
||||||
import type { User } from '../types/course';
|
import type { User } from '../types/course';
|
||||||
@@ -30,283 +27,269 @@ export const RegisterView: React.FC<RegisterViewProps> = ({ onShowToast, onLogin
|
|||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [accountType, setAccountType] = useState<'buyer' | 'seller'>('buyer');
|
const [accountType, setAccountType] = useState<'buyer' | 'seller'>('buyer');
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const isValidEmail = email.includes('@') && email.includes('.');
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (name && email && password) {
|
if (!name || !email || !password) return;
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
setTimeout(() => {
|
||||||
const newUser: User = {
|
const newUser: User = {
|
||||||
id: Math.random().toString(36).substr(2, 9),
|
id: Math.random().toString(36).substring(2, 11),
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
role: accountType,
|
role: accountType,
|
||||||
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',
|
avatar: accountType === 'seller'
|
||||||
|
? 'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=100&auto=format&fit=crop&q=80'
|
||||||
|
: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',
|
||||||
};
|
};
|
||||||
onLogin(newUser);
|
onLogin(newUser);
|
||||||
onShowToast(`¡Cuenta de ${accountType === 'buyer' ? 'Estudiante' : 'Instructor'} creada con éxito!`);
|
onShowToast(`¡Cuenta de ${accountType === 'buyer' ? 'Estudiante' : 'Instructor'} creada con éxito!`);
|
||||||
|
setIsLoading(false);
|
||||||
navigate(accountType === 'seller' ? '/seller' : '/courses');
|
navigate(accountType === 'seller' ? '/seller' : '/courses');
|
||||||
}
|
}, 450);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen grid grid-cols-1 lg:grid-cols-12 bg-slate-950 text-slate-100 font-sans selection:bg-cyan-500 selection:text-slate-950 relative overflow-hidden">
|
<div className="min-h-screen flex flex-col justify-between bg-slate-950 text-slate-100 font-sans selection:bg-cyan-500 selection:text-slate-950 relative overflow-hidden p-6 sm:p-10 lg:p-12">
|
||||||
|
|
||||||
{/* Ambient background glow */}
|
|
||||||
<div className="absolute -top-40 -left-40 w-96 h-96 bg-blue-600/15 rounded-full blur-[120px] pointer-events-none" />
|
|
||||||
<div className="absolute top-1/2 right-1/3 w-80 h-80 bg-cyan-600/10 rounded-full blur-[140px] pointer-events-none" />
|
|
||||||
|
|
||||||
{/* ============================================================== */}
|
{/* Top-Right Background Radial Gradient Glow (RyCourses Cyan & Blue Brand Colors) */}
|
||||||
{/* LEFT COLUMN: BRANDING BANNER */}
|
<div
|
||||||
{/* ============================================================== */}
|
className="absolute -top-32 -right-32 w-[600px] sm:w-[850px] h-[600px] sm:h-[850px] rounded-full pointer-events-none opacity-35 blur-[150px]"
|
||||||
<div className="hidden lg:flex lg:col-span-6 xl:col-span-7 relative flex-col justify-between p-10 xl:p-14 overflow-hidden bg-slate-900/40 border-r border-slate-800/60">
|
style={{
|
||||||
|
background: 'radial-gradient(circle at center, rgba(6, 182, 212, 0.45) 0%, rgba(37, 99, 235, 0.3) 45%, transparent 70%)'
|
||||||
{/* Ambient Lights */}
|
}}
|
||||||
<div className="absolute inset-0 bg-[radial-gradient(#334155_1px,transparent_1px)] [background-size:20px_20px] opacity-25" />
|
/>
|
||||||
<div className="absolute top-1/4 left-10 w-96 h-96 bg-cyan-500/20 rounded-full blur-[140px] pointer-events-none" />
|
<div className="absolute bottom-0 left-0 w-[450px] h-[450px] rounded-full pointer-events-none opacity-20 blur-[160px] bg-blue-900/30" />
|
||||||
<div className="absolute bottom-10 right-10 w-96 h-96 bg-blue-600/20 rounded-full blur-[140px] pointer-events-none" />
|
<div className="absolute inset-0 bg-[radial-gradient(#334155_1px,transparent_1px)] [background-size:24px_24px] opacity-10 pointer-events-none" />
|
||||||
|
|
||||||
{/* Brand Header */}
|
{/* Interactive Background Atmosphere: Twinkling Star Particles & Flying Space Shuttle */}
|
||||||
<div className="relative z-10 flex items-center justify-between">
|
<div className="absolute inset-0 pointer-events-none overflow-hidden z-0">
|
||||||
<BrandLogo size="lg" showSubtitle={true} />
|
|
||||||
|
|
||||||
<div className="flex items-center gap-1.5 px-3.5 py-1.5 rounded-full bg-slate-900/80 border border-slate-700/60 text-xs font-semibold text-slate-300 backdrop-blur-md">
|
|
||||||
<FiCheckCircle className="text-emerald-400" />
|
|
||||||
<span>Regístrate 100% Gratis</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Hero Visual Box */}
|
{/* Twinkling Star Field */}
|
||||||
<div className="relative z-10 my-auto py-6 max-w-2xl mx-auto w-full">
|
<div className="absolute top-12 left-1/6 w-1.5 h-1.5 rounded-full bg-cyan-300 animate-twinkle opacity-75" style={{ animationDelay: '0s' }} />
|
||||||
<div className="relative rounded-3xl p-1.5 bg-gradient-to-b from-slate-700/60 via-slate-800/40 to-cyan-500/30 border border-slate-700/80 shadow-2xl backdrop-blur-md group">
|
<div className="absolute top-1/4 right-1/5 w-2 h-2 rounded-full bg-blue-300 animate-twinkle opacity-85" style={{ animationDelay: '1.4s' }} />
|
||||||
|
<div className="absolute top-1/3 left-1/4 w-1 h-1 rounded-full bg-teal-200 animate-twinkle opacity-70" style={{ animationDelay: '2.1s' }} />
|
||||||
<div className="relative overflow-hidden rounded-[20px] aspect-[4/3]">
|
<div className="absolute top-1/2 right-1/3 w-1.5 h-1.5 rounded-full bg-cyan-200 animate-twinkle opacity-80" style={{ animationDelay: '0.6s' }} />
|
||||||
<img
|
<div className="absolute top-2/3 left-1/5 w-2 h-2 rounded-full bg-cyan-400 animate-twinkle opacity-75" style={{ animationDelay: '1.8s' }} />
|
||||||
src="/login-banner.jpg"
|
<div className="absolute bottom-1/4 right-1/4 w-1.5 h-1.5 rounded-full bg-blue-200 animate-twinkle opacity-65" style={{ animationDelay: '2.8s' }} />
|
||||||
alt="Comienza tu aprendizaje en RyCourses"
|
<div className="absolute bottom-1/3 left-2/3 w-1 h-1 rounded-full bg-cyan-300 animate-twinkle opacity-80" style={{ animationDelay: '0.3s' }} />
|
||||||
className="w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-700"
|
<div className="absolute top-16 right-1/3 w-1.5 h-1.5 rounded-full bg-teal-300 animate-twinkle opacity-70" style={{ animationDelay: '1.1s' }} />
|
||||||
/>
|
<div className="absolute bottom-20 left-1/3 w-2 h-2 rounded-full bg-blue-400 animate-twinkle opacity-75" style={{ animationDelay: '2.5s' }} />
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-slate-950 via-slate-950/20 to-transparent" />
|
<div className="absolute top-3/4 right-1/6 w-1 h-1 rounded-full bg-cyan-100 animate-twinkle opacity-80" style={{ animationDelay: '0.9s' }} />
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="absolute top-5 left-5 z-20 flex items-center gap-2 py-1.5 px-3.5 rounded-full bg-slate-950/80 border border-cyan-500/40 text-cyan-300 text-xs font-bold shadow-lg backdrop-blur-md">
|
{/* Crossing Space Shuttle Rocket */}
|
||||||
<FiStar className="text-yellow-400 fill-yellow-400" />
|
<div className="absolute top-0 left-0 animate-spaceship">
|
||||||
<span>Aprende a Tu Propio Ritmo</span>
|
<svg className="w-16 h-16 sm:w-20 sm:h-20 filter drop-shadow-[0_0_25px_rgba(6,182,212,0.8)]" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
</div>
|
{/* Plasma Rocket Flame Trail */}
|
||||||
|
<path d="M22 78L10 90L26 84L14 98L30 86L22 78Z" fill="url(#plasmaFlameReg)" className="animate-pulse" />
|
||||||
|
|
||||||
<div className="absolute bottom-5 left-5 right-5 z-20 p-4 rounded-2xl bg-slate-950/85 border border-slate-800/90 shadow-2xl backdrop-blur-xl space-y-2">
|
{/* Main Rocket Fuselage Body */}
|
||||||
<div className="flex items-center justify-between">
|
<path d="M78 22C62 26 42 42 34 58L26 62L38 74L42 66C58 58 74 38 78 22Z" fill="url(#rocketBodyGradientReg)" stroke="#38bdf8" strokeWidth="2" strokeLinejoin="round" />
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="w-10 h-10 rounded-xl bg-cyan-500/20 border border-cyan-500/40 flex items-center justify-center text-cyan-400 font-bold text-lg">
|
|
||||||
🎓
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-xs font-bold text-white tracking-tight">
|
|
||||||
Obtén certificados con reconocimiento internacional
|
|
||||||
</p>
|
|
||||||
<p className="text-[11px] text-slate-400">
|
|
||||||
Proyectos prácticos para enriquecer tu portafolio profesional.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
{/* Nose Cone Tip */}
|
||||||
</div>
|
<path d="M78 22C74 23 68 28 64 34L66 36C72 32 77 26 78 22Z" fill="#22d3ee" />
|
||||||
|
|
||||||
{/* Feature Highlights Grid */}
|
{/* Left Booster Fin */}
|
||||||
<div className="relative z-10 grid grid-cols-3 gap-4 pt-4 border-t border-slate-800/60">
|
<path d="M34 58L16 64L24 50L30 52Z" fill="#0284c7" stroke="#38bdf8" strokeWidth="1.5" strokeLinejoin="round" />
|
||||||
<div className="flex items-center gap-3 p-3 rounded-2xl bg-slate-900/60 border border-slate-800/60">
|
|
||||||
<div className="w-9 h-9 rounded-xl bg-cyan-500/10 border border-cyan-500/30 flex items-center justify-center text-cyan-400 shrink-0">
|
|
||||||
<FiBookOpen className="text-base" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-xs font-bold text-white">Cursos Prácticos</p>
|
|
||||||
<p className="text-[10px] text-slate-400">Proyectos reales</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-3 p-3 rounded-2xl bg-slate-900/60 border border-slate-800/60">
|
{/* Right Booster Fin */}
|
||||||
<div className="w-9 h-9 rounded-xl bg-blue-500/10 border border-blue-500/30 flex items-center justify-center text-blue-400 shrink-0">
|
<path d="M42 66L48 84L50 76L46 70Z" fill="#0284c7" stroke="#38bdf8" strokeWidth="1.5" strokeLinejoin="round" />
|
||||||
<FiAward className="text-base" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-xs font-bold text-white">Badges Digitales</p>
|
|
||||||
<p className="text-[10px] text-slate-400">Comparte en Linkedin</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-3 p-3 rounded-2xl bg-slate-900/60 border border-slate-800/60">
|
{/* Porthole Window 1 */}
|
||||||
<div className="w-9 h-9 rounded-xl bg-emerald-500/10 border border-emerald-500/30 flex items-center justify-center text-emerald-400 shrink-0">
|
<circle cx="58" cy="42" r="5" fill="#0f172a" stroke="#38bdf8" strokeWidth="1.5" />
|
||||||
<FiUsers className="text-base" />
|
<circle cx="58" cy="42" r="3.5" fill="#22d3ee" />
|
||||||
</div>
|
<circle cx="59.5" cy="40.5" r="1" fill="#ffffff" />
|
||||||
<div>
|
|
||||||
<p className="text-xs font-bold text-white">Mentores 24/7</p>
|
{/* Porthole Window 2 */}
|
||||||
<p className="text-[10px] text-slate-400">Soporte continuo</p>
|
<circle cx="48" cy="52" r="4" fill="#0f172a" stroke="#38bdf8" strokeWidth="1.5" />
|
||||||
</div>
|
<circle cx="48" cy="52" r="2.5" fill="#22d3ee" />
|
||||||
</div>
|
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="plasmaFlameReg" x1="30" y1="78" x2="10" y2="98" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stopColor="#38bdf8" />
|
||||||
|
<stop offset="0.5" stopColor="#06b6d4" />
|
||||||
|
<stop offset="1" stopColor="transparent" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="rocketBodyGradientReg" x1="78" y1="22" x2="26" y2="74" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stopColor="#e0f2fe" />
|
||||||
|
<stop offset="0.4" stopColor="#38bdf8" />
|
||||||
|
<stop offset="0.8" stopColor="#0284c7" />
|
||||||
|
<stop offset="1" stopColor="#0f172a" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ============================================================== */}
|
{/* Top Navigation Bar (Only Back Link, No duplicate logo) */}
|
||||||
{/* RIGHT COLUMN: FORM & REGISTER */}
|
<div className="w-full max-w-6xl mx-auto flex items-center justify-end z-10 pt-2 pb-4">
|
||||||
{/* ============================================================== */}
|
<Link
|
||||||
<div className="lg:col-span-6 xl:col-span-5 flex flex-col justify-between p-6 sm:p-10 lg:p-12 z-10 bg-slate-950/90 backdrop-blur-2xl border-l border-slate-800/80">
|
to="/"
|
||||||
|
className="flex items-center gap-1.5 text-xs font-medium text-slate-400 hover:text-white transition-colors py-1.5 px-3.5 rounded-xl bg-slate-900/80 border border-slate-800 hover:border-slate-700 backdrop-blur-md"
|
||||||
{/* Top Navigation Header */}
|
>
|
||||||
<div className="flex items-center justify-between">
|
<FiArrowLeft className="text-sm" />
|
||||||
<Link to="/" className="inline-flex items-center gap-2 lg:hidden">
|
<span>Volver al inicio</span>
|
||||||
<BrandLogo size="md" showSubtitle={false} />
|
</Link>
|
||||||
</Link>
|
</div>
|
||||||
|
|
||||||
<div className="hidden lg:block" />
|
|
||||||
|
|
||||||
<Link
|
{/* Main Centered Register Card Container */}
|
||||||
to="/"
|
<div className="my-auto w-full max-w-md mx-auto z-10">
|
||||||
className="flex items-center gap-1.5 text-xs font-semibold text-slate-400 hover:text-cyan-400 transition-colors py-2 px-3 rounded-xl bg-slate-900/80 border border-slate-800 hover:border-cyan-500/40"
|
<div className="relative p-6 sm:p-8 rounded-2xl bg-slate-900/75 border border-slate-800/90 shadow-2xl backdrop-blur-xl space-y-5">
|
||||||
>
|
|
||||||
<FiArrowLeft className="text-sm" />
|
|
||||||
<span>Volver al inicio</span>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Form Body Container */}
|
{/* Subtle Top Border Gradient Accent */}
|
||||||
<div className="my-auto py-8 max-w-md w-full mx-auto space-y-6">
|
<div className="absolute top-0 left-6 right-6 h-[1.5px] bg-gradient-to-r from-transparent via-cyan-500/60 to-transparent pointer-events-none" />
|
||||||
|
|
||||||
{/* Titles */}
|
{/* Centered Brand Logo & Header Titles inside Form Card */}
|
||||||
<div className="space-y-2">
|
<div className="text-center space-y-2 pt-1">
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-blue-500/10 border border-blue-500/20 text-cyan-400 text-xs font-medium">
|
<div className="flex justify-center pb-1">
|
||||||
<span className="w-2 h-2 rounded-full bg-cyan-400 animate-pulse" />
|
<BrandLogo size="lg" showSubtitle={true} />
|
||||||
Únete a RyCourses
|
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-3xl sm:text-4xl font-extrabold text-white tracking-tight">
|
<h1 className="text-2xl sm:text-3xl font-bold text-white tracking-tight pt-2">
|
||||||
Crear Cuenta Gratis ✨
|
Crear Cuenta
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xs sm:text-sm text-slate-400">
|
<p className="text-xs sm:text-sm text-slate-400">
|
||||||
Comienza a aprender o enseñar hoy mismo en la plataforma líder.
|
Crea tu perfil en RyCourses para comenzar tu experiencia.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Account type switcher */}
|
{/* Account type switcher */}
|
||||||
<div className="grid grid-cols-2 gap-2 p-1.5 bg-slate-900/90 rounded-2xl border border-slate-800">
|
<div className="grid grid-cols-2 gap-2 p-1 bg-slate-950/80 rounded-xl border border-slate-800">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setAccountType('buyer')}
|
onClick={() => setAccountType('buyer')}
|
||||||
className={`flex items-center justify-center gap-2 py-2.5 rounded-xl text-xs font-bold transition-all ${
|
className={`flex items-center justify-center gap-2 py-2 rounded-lg text-xs font-medium transition-all cursor-pointer ${accountType === 'buyer'
|
||||||
accountType === 'buyer'
|
? 'bg-slate-800 text-cyan-400 border border-slate-700 font-semibold shadow-sm'
|
||||||
? 'bg-gradient-to-r from-blue-600 to-cyan-500 text-white shadow-lg shadow-cyan-500/20'
|
|
||||||
: 'text-slate-400 hover:text-white'
|
: 'text-slate-400 hover:text-white'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<FaGraduationCap className="text-base" /> Estudiante
|
<FaGraduationCap className="text-sm" /> Estudiante
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setAccountType('seller')}
|
onClick={() => setAccountType('seller')}
|
||||||
className={`flex items-center justify-center gap-2 py-2.5 rounded-xl text-xs font-bold transition-all ${
|
className={`flex items-center justify-center gap-2 py-2 rounded-lg text-xs font-medium transition-all cursor-pointer ${accountType === 'seller'
|
||||||
accountType === 'seller'
|
? 'bg-slate-800 text-violet-400 border border-slate-700 font-semibold shadow-sm'
|
||||||
? 'bg-gradient-to-r from-violet-600 to-purple-500 text-white shadow-lg shadow-purple-500/20'
|
|
||||||
: 'text-slate-400 hover:text-white'
|
: 'text-slate-400 hover:text-white'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<FaChalkboardTeacher className="text-base" /> Instructor
|
<FaChalkboardTeacher className="text-sm" /> Instructor
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Form */}
|
{/* Form */}
|
||||||
<form onSubmit={handleSubmit} className="space-y-3.5">
|
<form onSubmit={handleSubmit} className="space-y-3.5">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs font-semibold text-slate-300 mb-1">
|
<label className="block text-xs font-medium text-slate-300 mb-1">
|
||||||
Nombre Completo
|
Nombre Completo
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FiUser className="absolute left-3.5 top-3.5 text-slate-500 text-base" />
|
<FiUser className="absolute left-3.5 top-3 text-slate-500 text-base pointer-events-none" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
placeholder="Ej. Sofía Rodríguez"
|
placeholder="Ej. Sofía Rodríguez"
|
||||||
className="w-full pl-10 pr-4 py-2.5 bg-slate-900/90 border border-slate-800 focus:border-cyan-500 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/30 transition"
|
className="w-full pl-10 pr-4 py-2.5 bg-slate-950/80 border border-slate-800 focus:border-cyan-500 focus:ring-2 focus:ring-cyan-500/20 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none transition-all"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs font-semibold text-slate-300 mb-1">
|
<div className="flex items-center justify-between mb-1">
|
||||||
Correo Electrónico
|
<label className="block text-xs font-medium text-slate-300">
|
||||||
</label>
|
Correo Electrónico
|
||||||
|
</label>
|
||||||
|
{isValidEmail && (
|
||||||
|
<span className="flex items-center gap-1 text-[11px] text-emerald-400 font-medium animate-fadeIn">
|
||||||
|
<FiCheckCircle className="text-xs" /> Formato válido
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FiMail className="absolute left-3.5 top-3.5 text-slate-500 text-base" />
|
<FiMail className="absolute left-3.5 top-3 text-slate-500 text-base pointer-events-none" />
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
required
|
required
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
placeholder="[email protected]"
|
placeholder="[email protected]"
|
||||||
className="w-full pl-10 pr-4 py-2.5 bg-slate-900/90 border border-slate-800 focus:border-cyan-500 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/30 transition"
|
className="w-full pl-10 pr-4 py-2.5 bg-slate-950/80 border border-slate-800 focus:border-cyan-500 focus:ring-2 focus:ring-cyan-500/20 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none transition-all"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-xs font-semibold text-slate-300 mb-1">
|
<label className="block text-xs font-medium text-slate-300 mb-1">
|
||||||
Contraseña
|
Contraseña
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FiLock className="absolute left-3.5 top-3.5 text-slate-500 text-base" />
|
<FiLock className="absolute left-3.5 top-3 text-slate-500 text-base pointer-events-none" />
|
||||||
<input
|
<input
|
||||||
type={showPassword ? 'text' : 'password'}
|
type={showPassword ? 'text' : 'password'}
|
||||||
required
|
required
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
placeholder="Mínimo 8 caracteres"
|
placeholder="Mínimo 8 caracteres"
|
||||||
className="w-full pl-10 pr-10 py-2.5 bg-slate-900/90 border border-slate-800 focus:border-cyan-500 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/30 transition"
|
className="w-full pl-10 pr-10 py-2.5 bg-slate-950/80 border border-slate-800 focus:border-cyan-500 focus:ring-2 focus:ring-cyan-500/20 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none transition-all"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
onClick={() => setShowPassword(!showPassword)}
|
||||||
className="absolute right-3.5 top-3 text-slate-500 hover:text-slate-300 transition"
|
className="absolute right-3.5 top-2.5 text-slate-500 hover:text-slate-300 transition cursor-pointer"
|
||||||
|
title={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
|
||||||
>
|
>
|
||||||
{showPassword ? <FiEyeOff className="text-base" /> : <FiEye className="text-base" />}
|
{showPassword ? <FiEyeOff className="text-base" /> : <FiEye className="text-base" />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2 pt-1 text-xs text-slate-400">
|
<div className="flex items-center gap-2 pt-0.5 text-xs text-slate-400">
|
||||||
<FiCheckCircle className="text-emerald-400 shrink-0" />
|
<FiCheckCircle className="text-emerald-400 shrink-0" />
|
||||||
<span>Acepto los Términos y Políticas de Privacidad.</span>
|
<span>Acepto los Términos de Servicio y Políticas de Privacidad.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full py-3.5 px-4 bg-gradient-to-r from-blue-600 via-cyan-500 to-teal-400 hover:opacity-95 text-white font-bold rounded-xl text-xs sm:text-sm shadow-lg shadow-cyan-500/25 transition-all flex items-center justify-center gap-2 group cursor-pointer"
|
disabled={isLoading}
|
||||||
|
className="w-full py-3 px-4 bg-gradient-to-r from-cyan-500 to-blue-500 hover:from-cyan-400 hover:to-blue-400 text-slate-950 font-bold rounded-xl text-xs sm:text-sm shadow-lg shadow-cyan-500/20 active:scale-[0.99] transition-all flex items-center justify-center gap-2 cursor-pointer disabled:opacity-60"
|
||||||
>
|
>
|
||||||
<span>Crear Cuenta como {accountType === 'buyer' ? 'Estudiante' : 'Instructor'}</span>
|
{isLoading ? (
|
||||||
<FiArrowRight className="text-base group-hover:translate-x-1 transition-transform" />
|
<>
|
||||||
|
<FiLoader className="text-base animate-spin" />
|
||||||
|
<span>Creando perfil...</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<span>Crear cuenta como {accountType === 'buyer' ? 'Estudiante' : 'Instructor'}</span>
|
||||||
|
<FiArrowRight className="text-base" />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Login Link */}
|
{/* Login Link */}
|
||||||
<div className="text-center text-xs text-slate-400 pt-2 border-t border-slate-900">
|
<div className="text-center text-xs text-slate-400 pt-3 border-t border-slate-800/80">
|
||||||
¿Ya tienes una cuenta registrada?{' '}
|
¿Ya tienes una cuenta registrada?{' '}
|
||||||
<Link to="/login" className="text-cyan-400 font-bold hover:text-cyan-300 hover:underline transition">
|
<Link to="/login" className="text-cyan-400 font-semibold hover:text-cyan-300 hover:underline transition">
|
||||||
Inicia sesión aquí
|
Inicia sesión aquí
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Footer info */}
|
{/* Footer info */}
|
||||||
<div className="text-center lg:text-left text-[11px] text-slate-600">
|
<div className="w-full max-w-6xl mx-auto text-center text-[11px] text-slate-600 z-10 pt-4 pb-2">
|
||||||
© 2026 RyCourses Platform. Todos los derechos reservados.
|
© 2026 RyCourses. Todos los derechos reservados.
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Reference in new issue
Block a user