Files
my_site/模板/Login.tsx
2026-03-18 11:50:03 +08:00

262 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { motion, AnimatePresence } from 'motion/react';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/src/components/ui/card';
import { Button } from '@/src/components/ui/button';
import { Input } from '@/src/components/ui/input';
import { LogIn, User, Lock, UserPlus, Mail, ArrowLeft } from 'lucide-react';
import { cn } from '@/src/lib/utils';
export default function Login() {
const navigate = useNavigate();
const [isLogin, setIsLogin] = useState(true);
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
// Simulate auth
setTimeout(() => {
setLoading(false);
if (isLogin) {
navigate('/overview');
} else {
setIsLogin(true); // Switch back to login after "registering"
}
}, 1000);
};
return (
<div className="min-h-screen flex items-center justify-center bg-[#07101D] relative overflow-hidden">
{/* Background Glow */}
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-[#336EFF] rounded-full mix-blend-screen filter blur-[128px] opacity-20 animate-pulse" />
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-purple-600 rounded-full mix-blend-screen filter blur-[128px] opacity-20" />
<div className="container mx-auto px-4 relative z-10 flex items-center w-full min-h-[600px]">
{/* Left Side: Brand Info (Only visible in Login mode) */}
<AnimatePresence>
{isLogin && (
<motion.div
key="brand-info"
initial={{ opacity: 0, x: -50 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -50 }}
transition={{ duration: 0.5, ease: 'easeOut' }}
className="absolute left-4 lg:left-8 xl:left-12 w-1/2 max-w-lg hidden lg:flex flex-col space-y-6"
>
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full glass-panel border-white/10 w-fit">
<span className="w-2 h-2 rounded-full bg-[#336EFF] animate-pulse" />
<span className="text-sm text-slate-300 font-medium tracking-wide uppercase">Access Portal</span>
</div>
<div className="space-y-2">
<h2 className="text-xl text-[#336EFF] font-bold tracking-widest uppercase">YOYUZH.XYZ</h2>
<h1 className="text-5xl md:text-6xl font-bold text-white leading-tight">
<br />
</h1>
</div>
<p className="text-lg text-slate-400 leading-relaxed">
YOYUZH
</p>
</motion.div>
)}
</AnimatePresence>
{/* Form Container */}
<motion.div
layout
transition={{ type: 'spring', stiffness: 200, damping: 25 }}
className={cn(
"w-full max-w-md z-10",
isLogin ? "ml-auto lg:mr-8 xl:mr-12" : "mx-auto"
)}
>
<Card className="border-white/10 backdrop-blur-2xl bg-white/5 shadow-2xl overflow-hidden">
<AnimatePresence mode="wait">
{isLogin ? (
<motion.div
key="login-form"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
>
<CardHeader className="space-y-1 pb-8">
<CardTitle className="text-2xl font-bold text-white flex items-center gap-2">
<LogIn className="w-6 h-6 text-[#336EFF]" />
</CardTitle>
<CardDescription className="text-slate-400">
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-300 ml-1"></label>
<div className="relative">
<User className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
<Input
type="text"
placeholder="账号 / 用户名 / 学号"
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
required
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-300 ml-1"></label>
<div className="relative">
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
<Input
type="password"
placeholder="••••••••"
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
required
/>
</div>
</div>
</div>
{error && (
<div className="p-3 rounded-xl bg-red-500/10 border border-red-500/20 text-red-400 text-sm">
{error}
</div>
)}
<div className="space-y-4">
<Button
type="submit"
className="w-full h-12 text-base font-semibold"
disabled={loading}
>
{loading ? (
<span className="flex items-center gap-2">
<span className="w-4 h-4 border-2 border-white/20 border-t-white rounded-full animate-spin" />
...
</span>
) : (
'进入系统'
)}
</Button>
<div className="text-center">
<button
type="button"
onClick={() => setIsLogin(false)}
className="text-sm text-slate-400 hover:text-[#336EFF] transition-colors"
>
</button>
</div>
</div>
</form>
</CardContent>
</motion.div>
) : (
<motion.div
key="register-form"
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
>
<CardHeader className="space-y-1 pb-8">
<div className="flex items-center justify-between">
<CardTitle className="text-2xl font-bold text-white flex items-center gap-2">
<UserPlus className="w-6 h-6 text-[#336EFF]" />
</CardTitle>
<button
onClick={() => setIsLogin(true)}
className="p-2 rounded-full hover:bg-white/5 text-slate-400 transition-colors"
>
<ArrowLeft className="w-5 h-5" />
</button>
</div>
<CardDescription className="text-slate-400">
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-4">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-300 ml-1"></label>
<div className="relative">
<User className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
<Input
type="text"
placeholder="设置您的用户名"
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
required
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-300 ml-1"></label>
<div className="relative">
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
<Input
type="email"
placeholder="your@email.com"
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
required
/>
</div>
</div>
<div className="space-y-2">
<label className="text-sm font-medium text-slate-300 ml-1"></label>
<div className="relative">
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
<Input
type="password"
placeholder="设置您的密码"
className="pl-10 bg-black/20 border-white/10 focus-visible:ring-[#336EFF]"
required
/>
</div>
</div>
</div>
<div className="space-y-4">
<Button
type="submit"
className="w-full h-12 text-base font-semibold"
disabled={loading}
>
{loading ? (
<span className="flex items-center gap-2">
<span className="w-4 h-4 border-2 border-white/20 border-t-white rounded-full animate-spin" />
...
</span>
) : (
'创建账号'
)}
</Button>
<div className="text-center">
<button
type="button"
onClick={() => setIsLogin(true)}
className="text-sm text-slate-400 hover:text-[#336EFF] transition-colors"
>
</button>
</div>
</div>
</form>
</CardContent>
</motion.div>
)}
</AnimatePresence>
</Card>
</motion.div>
</div>
</div>
);
}