diff --git a/client/src/pages/LoginPage.tsx b/client/src/pages/LoginPage.tsx index 93308e803..ebb0abf69 100644 --- a/client/src/pages/LoginPage.tsx +++ b/client/src/pages/LoginPage.tsx @@ -1,28 +1,41 @@ import { - BookMarked, - CheckSquare, ChevronDown, Eye, EyeOff, Fingerprint, - FolderOpen, Globe, KeyRound, Lock, Mail, - Map, Plane, - Route, Shield, User, - Users, - Wallet, - Zap, } from 'lucide-react'; import React from 'react'; import ToggleSwitch from '../components/Settings/ToggleSwitch'; import { SUPPORTED_LANGUAGES, useTranslation } from '../i18n'; import { useLogin } from './login/useLogin'; +import LoginWorld from './login/LoginWorld'; + +/** Fixed so the sky does not reshuffle on every render. */ +const STARFIELD = [ + { top: 6, left: 12, size: 1, opacity: 0.3, delay: 0 }, + { top: 11, left: 68, size: 2, opacity: 0.22, delay: 1.4 }, + { top: 17, left: 34, size: 1, opacity: 0.35, delay: 2.6 }, + { top: 22, left: 84, size: 1, opacity: 0.25, delay: 0.7 }, + { top: 28, left: 19, size: 2, opacity: 0.2, delay: 3.1 }, + { top: 33, left: 57, size: 1, opacity: 0.32, delay: 1.9 }, + { top: 39, left: 91, size: 1, opacity: 0.24, delay: 2.2 }, + { top: 46, left: 8, size: 1, opacity: 0.28, delay: 0.4 }, + { top: 52, left: 73, size: 2, opacity: 0.18, delay: 3.6 }, + { top: 58, left: 42, size: 1, opacity: 0.3, delay: 1.1 }, + { top: 64, left: 88, size: 1, opacity: 0.26, delay: 2.9 }, + { top: 71, left: 26, size: 1, opacity: 0.22, delay: 0.9 }, + { top: 77, left: 63, size: 1, opacity: 0.3, delay: 3.3 }, + { top: 83, left: 15, size: 2, opacity: 0.2, delay: 1.7 }, + { top: 88, left: 79, size: 1, opacity: 0.27, delay: 2.4 }, + { top: 93, left: 48, size: 1, opacity: 0.23, delay: 0.2 }, +]; export default function LoginPage(): React.ReactElement { const { t, language } = useTranslation(); @@ -96,190 +109,110 @@ export default function LoginPage(): React.ReactElement { if (showTakeoff) { return ( -
- {/* Sky gradient */} -
- - {/* Stars */} - {Array.from({ length: 60 }, (_, i) => ( -
0.7 ? 3 : 1.5, - height: Math.random() > 0.7 ? 3 : 1.5, - borderRadius: '50%', - background: 'white', - top: `${Math.random() * 100}%`, - left: `${Math.random() * 100}%`, - animationDelay: `${0.3 + Math.random() * 0.5}s, ${Math.random() * 1}s`, - }} - /> - ))} - - {/* Clouds rushing past */} - {[0, 1, 2, 3, 4].map((i) => ( -
- ))} - - {/* Speed lines */} - {Array.from({ length: 12 }, (_, i) => ( -
- ))} - - {/* Plane */} -
- - - - - - - - - - +
+ {/* Signing in picks up exactly where the login panel left off: the same dot + map, except now every route departs at once. The network finishing is + the moment — no separate imagery, no plane flying off alone. */} +
+
- {/* Contrail */} -
+ {/* The colour rises with the departures rather than sitting there from the start. */} +
+
- {/* Logo fade in + burst */} -
- TREK +
+ TREK

{t('login.tagline')}

+ {/* Hands over to the app instead of cutting to it. */} +
+
@@ -389,7 +322,7 @@ export default function LoginPage(): React.ReactElement { style={{ display: 'none', width: '55%', - background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #0f172a 100%)', + background: '#070c1a', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', @@ -401,240 +334,87 @@ export default function LoginPage(): React.ReactElement { > - {/* Stars */} + {/* Aurora — three drifting colour fields. They are the whole background: + deep indigo, a cold cyan and a warm violet, blurred past recognition so + what is left is the gradient, not the shapes. */} +
+
+
+ + {/* Depth: a handful of pinpricks, far enough back to read as distance. */}
- {Array.from({ length: 40 }, (_, i) => ( + {STARFIELD.map((s, i) => (
0.7 ? 2 : 1, - height: Math.random() > 0.7 ? 2 : 1, + width: s.size, + height: s.size, borderRadius: '50%', background: 'white', - opacity: 0.15 + Math.random() * 0.25, - top: `${Math.random() * 70}%`, - left: `${Math.random() * 100}%`, - animationDelay: `${Math.random() * 4}s`, + opacity: s.opacity, + top: `${s.top}%`, + left: `${s.left}%`, + animationDelay: `${s.delay}s`, }} /> ))}
- {/* Animated glow orbs */} -
-
+ {/* Coastlines as a dot map, with routes lighting up between cities across + it. The geometry is TREK's own Atlas bundle, baked in at build time + because this screen is unauthenticated. */} + - {/* Animated planes — realistic silhouettes at different sizes/speeds */} -
- {/* Plane 1 — large, slow, foreground */} - - - - - - - - - - - - {/* Plane 2 — small, faster, higher */} - - - - - - - - - - {/* Plane 3 — medium, mid-speed */} - - - - - - - - - - - - {/* Plane 4 — tiny, fast, high */} - - - - - - - - - - {/* Plane 5 — medium, right to left, lower */} - - - - - - - - - - - - {/* Plane 6 — tiny distant */} - - - - - - - - -
- -
- {/* Logo */} -
- TREK + {/* No max-width: the tagline stays on one line, so the block is allowed to + use the whole panel rather than wrapping inside it. */} +
+ {/* Logo. The soft dark halo is what separates it from the dot map behind — + wide and low-opacity rather than a hard drop shadow, so it reads as the + map dimming around the mark instead of an outline. */} +
+ TREK

{t('login.tagline')}

{t('login.description')}

- -
- {[ - { Icon: Map, label: t('login.features.maps'), desc: t('login.features.mapsDesc') }, - { Icon: Zap, label: t('login.features.realtime'), desc: t('login.features.realtimeDesc') }, - { Icon: Wallet, label: t('login.features.budget'), desc: t('login.features.budgetDesc') }, - { Icon: Users, label: t('login.features.collab'), desc: t('login.features.collabDesc') }, - { Icon: CheckSquare, label: t('login.features.packing'), desc: t('login.features.packingDesc') }, - { Icon: BookMarked, label: t('login.features.bookings'), desc: t('login.features.bookingsDesc') }, - { Icon: FolderOpen, label: t('login.features.files'), desc: t('login.features.filesDesc') }, - { Icon: Route, label: t('login.features.routes'), desc: t('login.features.routesDesc') }, - ].map(({ Icon, label, desc }) => ( -
) => { - e.currentTarget.style.background = 'rgba(255,255,255,0.08)'; - e.currentTarget.style.borderColor = 'rgba(255,255,255,0.12)'; - }} - onMouseLeave={(e: React.MouseEvent) => { - e.currentTarget.style.background = 'rgba(255,255,255,0.04)'; - e.currentTarget.style.borderColor = 'rgba(255,255,255,0.06)'; - }} - > - -
- {label} -
-
- {desc} -
-
- ))} -
- -

- {t('login.selfHosted')} -

@@ -1441,20 +1221,45 @@ export default function LoginPage(): React.ReactElement {