diff --git a/frontend/src/components/login/CenteredCard.tsx b/frontend/src/components/login/CenteredCard.tsx index 60a8827..dc5d6c3 100644 --- a/frontend/src/components/login/CenteredCard.tsx +++ b/frontend/src/components/login/CenteredCard.tsx @@ -5,95 +5,98 @@ export default function CenteredCard() { return (
- {/* Full-screen dark gradient background with noise texture */} + {/* Aurora band 1 — Emerald green */}
- {/* Subtle noise / dot pattern overlay */} -
- {/* Extra floating glow orbs */} -
-
- {/* Center glassmorphism card */} + {/* Aurora band 2 — Indigo */} +
+ + {/* Aurora band 3 — Purple */} +
+ + {/* Glassmorphism card */}
- {/* Logo icon */} + {/* Logo — 44x44 gradient rounded square with database icon */}
- + @@ -109,7 +112,7 @@ export default function CenteredCard() {
{error && ( -
+
{error}
)} @@ -121,17 +124,25 @@ export default function CenteredCard() { onChange={(e) => setUsername(e.target.value)} className="w-full" style={{ - padding: '13px 16px', - borderRadius: 10, + padding: '14px 18px', + borderRadius: 12, background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.08)', color: '#fff', fontSize: 14, outline: 'none', - transition: 'border-color 0.2s, background 0.2s', + transition: 'border-color 0.3s, background 0.3s, box-shadow 0.3s', + }} + onFocus={(e) => { + e.target.style.borderColor = 'rgba(99,102,241,0.4)'; + e.target.style.background = 'rgba(255,255,255,0.08)'; + e.target.style.boxShadow = '0 0 0 3px rgba(99,102,241,0.1)'; + }} + onBlur={(e) => { + e.target.style.borderColor = 'rgba(255,255,255,0.08)'; + e.target.style.background = 'rgba(255,255,255,0.06)'; + e.target.style.boxShadow = 'none'; }} - onFocus={(e) => { e.target.style.borderColor = 'rgba(99,102,241,0.4)'; e.target.style.background = 'rgba(255,255,255,0.08)'; }} - onBlur={(e) => { e.target.style.borderColor = 'rgba(255,255,255,0.08)'; e.target.style.background = 'rgba(255,255,255,0.06)'; }} /> setPassword(e.target.value)} className="w-full" style={{ - padding: '13px 16px', - borderRadius: 10, + padding: '14px 18px', + borderRadius: 12, background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.08)', color: '#fff', fontSize: 14, outline: 'none', - transition: 'border-color 0.2s, background 0.2s', + transition: 'border-color 0.3s, background 0.3s, box-shadow 0.3s', + }} + onFocus={(e) => { + e.target.style.borderColor = 'rgba(99,102,241,0.4)'; + e.target.style.background = 'rgba(255,255,255,0.08)'; + e.target.style.boxShadow = '0 0 0 3px rgba(99,102,241,0.1)'; + }} + onBlur={(e) => { + e.target.style.borderColor = 'rgba(255,255,255,0.08)'; + e.target.style.background = 'rgba(255,255,255,0.06)'; + e.target.style.boxShadow = 'none'; }} - onFocus={(e) => { e.target.style.borderColor = 'rgba(99,102,241,0.4)'; e.target.style.background = 'rgba(255,255,255,0.08)'; }} - onBlur={(e) => { e.target.style.borderColor = 'rgba(255,255,255,0.08)'; e.target.style.background = 'rgba(255,255,255,0.06)'; }} />
+ + {/* Aurora keyframe animations */} +
); } diff --git a/frontend/src/components/login/FullImage.tsx b/frontend/src/components/login/FullImage.tsx index abf0df2..4faa236 100644 --- a/frontend/src/components/login/FullImage.tsx +++ b/frontend/src/components/login/FullImage.tsx @@ -8,81 +8,112 @@ export default function FullImage() { className="flex items-center justify-center min-h-screen relative" style={{ padding: 24, overflow: 'hidden' }} > - {/* Deep dark background #0d1117 */} + {/* Deep navy background */}
- {/* Particle grid — dots and lines */} -
+ {/* Star field — 30+ individual stars */} +
+ {/* Row 1 - top area */} +
+
+
+
+
+
- {/* Connecting grid lines */} -
+ {/* Row 2 */} +
+
+
+
+
- {/* Large glow orb — top right */} + {/* Row 3 */} +
+
+
+
+ + {/* Row 4 — mid area */} +
+
+
+
+ + {/* Row 5 */} +
+
+
+
+ + {/* Row 6 — lower area */} +
+
+
+ + {/* Row 7 — bottom area */} +
+
+
+
+ + {/* Row 8 — very bottom */} +
+
+
+ + {/* Constellation lines connecting adjacent stars */} +
+ {/* Line 1: top 3%/12% → 5%/28% → 2%/45% */} +
+ {/* Line 2: top 16%/22% → 12%/55% */} +
+ {/* Line 3: top 42%/48% → 36%/75% → 30%/82% */} +
+ {/* Line 4: top 55%/8% → 52%/40% */} +
+ {/* Line 5: top 72%/52% → 78%/65% */} +
+ {/* Line 6 (vertical): top 5%/28% → 16%/22% */} +
+
+ + {/* Large pulsating glow orb — top right (blue-purple) */}
- {/* Secondary glow — bottom left */} + {/* Smaller warm glow orb — bottom left */}
@@ -93,55 +124,51 @@ export default function FullImage() { zIndex: 10, width: '100%', maxWidth: 400, - background: 'rgba(13, 17, 23, 0.8)', + background: 'rgba(10, 22, 40, 0.7)', backdropFilter: 'blur(20px)', WebkitBackdropFilter: 'blur(20px)', + border: '1px solid rgba(255,255,255,0.06)', borderRadius: 16, padding: '40px 32px', - boxShadow: ` - 0 0 0 1px rgba(255,255,255,0.08), - 0 8px 40px rgba(0,0,0,0.5), - 0 0 100px rgba(99,102,241,0.04) - `, + boxShadow: '0 0 0 1px rgba(255,255,255,0.06), 0 8px 40px rgba(0,0,0,0.5)', }} > - {/* Small brand mark at top */} -
+ {/* Small brand mark */} +
- +
-

+

SQL审核平台

-

+

登录您的工作区

{error && ( -
+
{error}
)} - {/* Dark inset inputs */} + {/* Inset-style input: username */} { e.target.style.borderColor = 'rgba(99,102,241,0.3)'; e.target.style.background = 'rgba(255,255,255,0.06)'; }} - onBlur={(e) => { e.target.style.borderColor = 'rgba(255,255,255,0.06)'; e.target.style.background = 'rgba(255,255,255,0.04)'; }} + onFocus={(e) => { + e.target.style.borderColor = 'rgba(99,102,241,0.4)'; + e.target.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.2), 0 0 0 3px rgba(99,102,241,0.1)'; + }} + onBlur={(e) => { + e.target.style.borderColor = 'rgba(255,255,255,0.06)'; + e.target.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.2)'; + }} /> + + {/* Inset-style input: password */} { e.target.style.borderColor = 'rgba(99,102,241,0.3)'; e.target.style.background = 'rgba(255,255,255,0.06)'; }} - onBlur={(e) => { e.target.style.borderColor = 'rgba(255,255,255,0.06)'; e.target.style.background = 'rgba(255,255,255,0.04)'; }} + onFocus={(e) => { + e.target.style.borderColor = 'rgba(99,102,241,0.4)'; + e.target.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.2), 0 0 0 3px rgba(99,102,241,0.1)'; + }} + onBlur={(e) => { + e.target.style.borderColor = 'rgba(255,255,255,0.06)'; + e.target.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.2)'; + }} /> + {/* Full-width submit button */}
+ + {/* Keyframe animations */} +
); } diff --git a/frontend/src/components/login/MinimalDark.tsx b/frontend/src/components/login/MinimalDark.tsx index 2ba7cf1..a4bd472 100644 --- a/frontend/src/components/login/MinimalDark.tsx +++ b/frontend/src/components/login/MinimalDark.tsx @@ -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 ( -
-
- {/* Tiny gradient dot logo */} -
+ <> + {/* Inject keyframes once */} + - {/* Brand name with wide tracking */} -

- SQL审核平台 -

- - {/* Thin divider */} -
- -
- {error && ( -
- {error} -
- )} - - {/* Borderless inputs — bottom line only */} -
- 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)'; }} - /> -
- -
- 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)'; }} - /> -
- - {/* Full-width slim button */} - -
+ SQL审核平台 + + + {/* Thin divider */} +
+ + {/* Form */} +
+ {error && ( +
+ {error} +
+ )} + + {/* Username */} +
+ 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)'; + }} + /> +
+ + {/* Password */} +
+ 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)'; + }} + /> +
+ + {/* Submit */} + +
+
-
+ ); } diff --git a/frontend/src/components/login/SidePanel.tsx b/frontend/src/components/login/SidePanel.tsx index 69fca83..53d8bb4 100644 --- a/frontend/src/components/login/SidePanel.tsx +++ b/frontend/src/components/login/SidePanel.tsx @@ -1,115 +1,262 @@ import { useLogin } from '@/hooks/useLogin'; -const features = ['SQL审核', '变更审批', '实时监控', '权限管理']; - export default function SidePanel() { const { username, password, loading, error, setUsername, setPassword, handleLogin } = useLogin(); + /* 6 orbit light-points evenly spaced at 60° intervals on a 300px ring (radius 150px) */ + const orbitDots = [ + { angle: 0, size: 8, opacity: 0.9 }, + { angle: 60, size: 6, opacity: 0.6 }, + { angle: 120, size: 7, opacity: 0.75 }, + { angle: 180, size: 6, opacity: 0.5 }, + { angle: 240, size: 8, opacity: 0.8 }, + { angle: 300, size: 6, opacity: 0.55 }, + ]; + + /* Scattered twinkling stars */ + const stars = [ + { top: '6%', left: '12%', size: 3, delay: '0s', dur: '3s' }, + { top: '14%', left: '72%', size: 2, delay: '1.2s', dur: '4s' }, + { top: '25%', left: '38%', size: 4, delay: '0.5s', dur: '3.5s' }, + { top: '18%', left: '55%', size: 2, delay: '2s', dur: '5s' }, + { top: '60%', left: '15%', size: 3, delay: '1s', dur: '4.5s' }, + { top: '70%', left: '80%', size: 2, delay: '0.3s', dur: '3.2s' }, + { top: '82%', left: '30%', size: 4, delay: '1.8s', dur: '3.8s' }, + { top: '45%', left: '8%', size: 2, delay: '2.5s', dur: '4.2s' }, + { top: '35%', left: '88%', size: 3, delay: '0.8s', dur: '3.6s' }, + { top: '90%', left: '65%', size: 2, delay: '1.5s', dur: '5.2s' }, + ]; + return (
- {/* Left Panel — 38% Brand Area */} + {/* ========== Left Panel — 40% Celestial Animation ========== */}
- {/* Subtle decorative gradient orb */} + {/* --- Core Celestial Orb (200px, centered-upper) --- */}
+ {/* Main orb */} +
+
+ + {/* --- Orbit Ring (300px, dashed) with 6 light dots --- */} +
+ {orbitDots.map((dot, i) => { + const rad = (dot.angle * Math.PI) / 180; + const r = 150; // radius of the 300px ring + const x = 150 + r * Math.cos(rad) - dot.size / 2; + const y = 150 + r * Math.sin(rad) - dot.size / 2; + return ( +
+ ); + })} +
+ + {/* --- 3 Meteors --- */} + {/* Meteor 1 */} +
+ {/* Meteor 2 */} +
+ {/* Meteor 3 */} +
- {/* Top brand section */} -
- {/* Logo mark */} + {/* --- Scattered Twinkling Stars --- */} + {stars.map((s, i) => (
- - - - - -
+ /> + ))} - {/* Stacked large text — left aligned */} -
-
- SQL审核 -
-
- 平台 -
+ {/* --- Bottom-left brand text --- */} +
+
+ SQL审核平台 +
+
+ 企业级数据库审核与合规管理
-

- 企业级数据库审核与合规管理解决方案,为团队提供安全可靠的数据管理体验。 -

- {/* Bottom feature pills */} -
- {features.map((tag) => ( - - {tag} - - ))} -
+ {/* --- Keyframes --- */} +
- {/* Right Panel — 62% Login Form */} + {/* ========== Right Panel — 60% Login Form ========== */}
-

+

欢迎回来

-

+

登录以继续

{error && ( -
+
{error}
)} + {/* Username */}
-
+ {/* Password */} +
@@ -153,13 +301,14 @@ export default function SidePanel() { color: 'var(--dg-text-primary)', fontSize: 14, outline: 'none', - transition: 'background 0.2s', + transition: 'background 0.3s', }} onFocus={(e) => { e.target.style.background = 'var(--dg-bg-tertiary)'; }} onBlur={(e) => { e.target.style.background = 'var(--dg-bg-secondary)'; }} />
+ {/* Submit */}