feat: 登录页5种视觉大片级重设计 — 星河/极光/日月/星辰/流星
5个登录组件全面升级为动态视觉效果: 1. SplitView — 星河流转: 深靛蓝渐变(#0f0c29→#302b63) + 3条CSS流星动画 + 7个漂浮星辰光点 + 脉动光晕,底线输入框聚焦靛蓝 2. CenteredCard — 极光幻境: 深蓝黑底(#0a0a2e) + 3条流动极光色带 (翠绿/靛蓝/紫) filter:blur(80px) 缓慢流动,毛玻璃居中卡片 3. SidePanel — 日月交替(重点重做): 暮光紫→夜空蓝渐变 + 200px天体球(太阳金→月亮银蓝 8s循环) + 300px旋转轨道环 + 6个轨道光点 + 3条流星 + 10个闪烁星点 4. FullImage — 星辰连线: 深海军蓝(#0a1628) + 33个随机星点 + 6条星座连线 + 右上角蓝紫发光球 + 左下角暖色光球 5. MinimalDark — 流星雨: 深紫黑(#0c0a1a) + 6条流星动画 + 10个静态星点 + 渐变菱形logo + 极简布局
This commit is contained in:
1 parent
46054c8b2f
commit
1aa729b61b
5 files changed
+776
-432
No files matched your search
@@ -1,123 +1,230 @@
|
||||
import { useLogin } from '@/hooks/useLogin';
|
||||
|
||||
/* ---------- static star positions (generated once) ---------- */
|
||||
const STARS = [
|
||||
{ top: '8%', left: '15%', size: 2, opacity: 0.25 },
|
||||
{ top: '12%', left: '72%', size: 1, opacity: 0.15 },
|
||||
{ top: '25%', left: '45%', size: 3, opacity: 0.10 },
|
||||
{ top: '18%', left: '88%', size: 1, opacity: 0.35 },
|
||||
{ top: '38%', left: '22%', size: 2, opacity: 0.20 },
|
||||
{ top: '55%', left: '68%', size: 1, opacity: 0.30 },
|
||||
{ top: '62%', left: '35%', size: 2, opacity: 0.15 },
|
||||
{ top: '75%', left: '80%', size: 3, opacity: 0.12 },
|
||||
{ top: '82%', left: '50%', size: 1, opacity: 0.40 },
|
||||
{ top: '90%', left: '10%', size: 2, opacity: 0.18 },
|
||||
];
|
||||
|
||||
/* ---------- meteor configs ---------- */
|
||||
const METEORS = [
|
||||
{ width: 140, height: 1, duration: '1.5s', delay: '0s', top: '-20px', right: '10%' },
|
||||
{ width: 120, height: 2, duration: '1.2s', delay: '2s', top: '-60px', right: '30%' },
|
||||
{ width: 150, height: 1, duration: '1.8s', delay: '4s', top: '-10px', right: '55%' },
|
||||
{ width: 110, height: 2, duration: '2s', delay: '6.5s', top: '-80px', right: '20%' },
|
||||
{ width: 130, height: 1, duration: '1.4s', delay: '9s', top: '-40px', right: '70%' },
|
||||
{ width: 100, height: 1, duration: '1.6s', delay: '12s', top: '-30px', right: '45%' },
|
||||
];
|
||||
|
||||
const KEYFRAMES = METEORS.map((_, i) => `
|
||||
@keyframes meteor-shoot-${i + 1} {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate(100vw, -100px) rotate(-35deg);
|
||||
}
|
||||
10% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate(-100px, 100vh) rotate(-35deg);
|
||||
}
|
||||
}
|
||||
`).join('\n');
|
||||
|
||||
export default function MinimalDark() {
|
||||
const { username, password, loading, error, setUsername, setPassword, handleLogin } = useLogin();
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col items-center justify-center min-h-screen"
|
||||
style={{ background: '#0a0a0a', padding: 24 }}
|
||||
>
|
||||
<div style={{ width: '100%', maxWidth: 320, textAlign: 'center' }}>
|
||||
{/* Tiny gradient dot logo */}
|
||||
<div
|
||||
style={{
|
||||
width: 16,
|
||||
height: 16,
|
||||
borderRadius: '50%',
|
||||
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
|
||||
margin: '0 auto 24px',
|
||||
boxShadow: '0 0 12px rgba(99,102,241,0.3)',
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
{/* Inject keyframes once */}
|
||||
<style>{KEYFRAMES}</style>
|
||||
|
||||
{/* Brand name with wide tracking */}
|
||||
<h1
|
||||
className="tracking-wider"
|
||||
style={{ fontSize: 15, fontWeight: 500, color: 'rgba(255,255,255,0.8)', letterSpacing: '3px', marginBottom: 0 }}
|
||||
>
|
||||
SQL审核平台
|
||||
</h1>
|
||||
|
||||
{/* Thin divider */}
|
||||
<div
|
||||
style={{
|
||||
width: 40,
|
||||
height: 1,
|
||||
background: 'rgba(255,255,255,0.1)',
|
||||
margin: '32px auto',
|
||||
}}
|
||||
/>
|
||||
|
||||
<form
|
||||
onSubmit={handleLogin}
|
||||
style={{ display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
{error && (
|
||||
<div style={{ color: '#f87171', fontSize: 13, marginBottom: 20, textAlign: 'left' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Borderless inputs — bottom line only */}
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="用户名"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
className="w-full"
|
||||
style={{
|
||||
padding: '12px 0',
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
borderBottom: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: 0,
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
outline: 'none',
|
||||
transition: 'border-color 0.25s',
|
||||
}}
|
||||
onFocus={(e) => { e.target.style.borderBottomColor = 'rgba(99,102,241,0.5)'; }}
|
||||
onBlur={(e) => { e.target.style.borderBottomColor = 'rgba(255,255,255,0.1)'; }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 40 }}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="密码"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full"
|
||||
style={{
|
||||
padding: '12px 0',
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
borderBottom: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: 0,
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
outline: 'none',
|
||||
transition: 'border-color 0.25s',
|
||||
}}
|
||||
onFocus={(e) => { e.target.style.borderBottomColor = 'rgba(99,102,241,0.5)'; }}
|
||||
onBlur={(e) => { e.target.style.borderBottomColor = 'rgba(255,255,255,0.1)'; }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Full-width slim button */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading || !username || !password}
|
||||
className="dg-gradient-bg w-full"
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '100vh',
|
||||
padding: 24,
|
||||
background: 'radial-gradient(ellipse at 50% 50%, #151030 0%, #0c0a1a 70%)',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{/* -------- Static star dots -------- */}
|
||||
{STARS.map((s, i) => (
|
||||
<div
|
||||
key={`star-${i}`}
|
||||
style={{
|
||||
padding: '12px 20px',
|
||||
borderRadius: 6,
|
||||
border: 'none',
|
||||
color: '#fff',
|
||||
position: 'absolute',
|
||||
top: s.top,
|
||||
left: s.left,
|
||||
width: s.size,
|
||||
height: s.size,
|
||||
borderRadius: '50%',
|
||||
background: '#fff',
|
||||
opacity: s.opacity,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* -------- Shooting meteors -------- */}
|
||||
{METEORS.map((m, i) => (
|
||||
<div
|
||||
key={`meteor-${i}`}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: m.top,
|
||||
right: m.right,
|
||||
width: m.width,
|
||||
height: m.height,
|
||||
background: 'linear-gradient(to left, rgba(255,255,255,0.8), transparent)',
|
||||
transform: 'rotate(-35deg)',
|
||||
animation: `meteor-shoot-${i + 1} ${m.duration} ${m.delay} linear infinite forwards`,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* -------- Central content card -------- */}
|
||||
<div style={{ width: '100%', maxWidth: 320, textAlign: 'center', position: 'relative', zIndex: 1 }}>
|
||||
{/* Gradient diamond */}
|
||||
<div
|
||||
style={{
|
||||
width: 20,
|
||||
height: 20,
|
||||
background: 'linear-gradient(135deg, #6366f1, #a855f7)',
|
||||
borderRadius: 4,
|
||||
transform: 'rotate(45deg)',
|
||||
margin: '0 auto 24px',
|
||||
boxShadow: '0 0 16px rgba(99,102,241,0.35)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Brand */}
|
||||
<h1
|
||||
style={{
|
||||
fontSize: 15,
|
||||
fontWeight: 500,
|
||||
fontSize: 14,
|
||||
cursor: loading || !username || !password ? 'not-allowed' : 'pointer',
|
||||
opacity: loading || !username || !password ? 0.4 : 1,
|
||||
transition: 'opacity 0.2s, transform 0.1s',
|
||||
letterSpacing: '0.5px',
|
||||
letterSpacing: '3px',
|
||||
color: 'rgba(255,255,255,0.8)',
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{loading ? '登录中…' : '登录'}
|
||||
</button>
|
||||
</form>
|
||||
SQL审核平台
|
||||
</h1>
|
||||
|
||||
{/* Thin divider */}
|
||||
<div
|
||||
style={{
|
||||
width: 40,
|
||||
height: 1,
|
||||
background: 'rgba(255,255,255,0.1)',
|
||||
margin: '32px auto',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Form */}
|
||||
<form
|
||||
onSubmit={handleLogin}
|
||||
style={{ display: 'flex', flexDirection: 'column' }}
|
||||
>
|
||||
{error && (
|
||||
<div style={{ color: '#f87171', fontSize: 13, marginBottom: 20, textAlign: 'left' }}>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Username */}
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="用户名"
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
className="w-full"
|
||||
style={{
|
||||
padding: '12px 0',
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
borderBottom: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: 0,
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
outline: 'none',
|
||||
transition: 'border-color 0.25s',
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
e.target.style.borderBottomColor = 'rgba(99,102,241,0.5)';
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
e.target.style.borderBottomColor = 'rgba(255,255,255,0.1)';
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Password */}
|
||||
<div style={{ marginBottom: 40 }}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="密码"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full"
|
||||
style={{
|
||||
padding: '12px 0',
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
borderBottom: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: 0,
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
outline: 'none',
|
||||
transition: 'border-color 0.25s',
|
||||
}}
|
||||
onFocus={(e) => {
|
||||
e.target.style.borderBottomColor = 'rgba(99,102,241,0.5)';
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
e.target.style.borderBottomColor = 'rgba(255,255,255,0.1)';
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Submit */}
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading || !username || !password}
|
||||
className="dg-gradient-bg w-full"
|
||||
style={{
|
||||
padding: 12,
|
||||
borderRadius: 6,
|
||||
border: 'none',
|
||||
color: '#fff',
|
||||
fontWeight: 500,
|
||||
fontSize: 14,
|
||||
cursor: loading || !username || !password ? 'not-allowed' : 'pointer',
|
||||
opacity: loading || !username || !password ? 0.4 : 1,
|
||||
transition: 'opacity 0.2s, transform 0.1s',
|
||||
letterSpacing: '0.5px',
|
||||
}}
|
||||
>
|
||||
{loading ? '登录中…' : '登录'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user