change layout/design of login page
This commit is contained in:
+70
-54
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
import { User, Briefcase, Lock, ArrowRight, AlertCircle, Eye, EyeOff } from 'lucide-react';
|
import { User, Briefcase, Lock, ArrowRight, AlertCircle, Eye, EyeOff, Zap } from 'lucide-react';
|
||||||
import { SpotlightCard } from '../components/SpotlightCard';
|
import { SpotlightCard } from '../components/SpotlightCard';
|
||||||
import Logo from '../assets/images/LynkedUp_Pro_F_logo_Y.png';
|
import Logo from '../assets/images/LynkedUp_Pro_F_logo_Y.png';
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ const Login = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-zinc-50 dark:bg-[#050505] flex items-center justify-center p-4 relative overflow-hidden selection:bg-blue-500/20 dark:selection:bg-white/20 transition-colors duration-300">
|
<div className="min-h-screen bg-zinc-50 dark:bg-[#050505] flex items-center justify-center p-4 py-8 sm:py-12 relative overflow-x-hidden selection:bg-blue-500/20 dark:selection:bg-white/20 transition-colors duration-300">
|
||||||
{/* Subtle Ambient Background */}
|
{/* Subtle Ambient Background */}
|
||||||
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-[0.03] dark:opacity-5 pointer-events-none mix-blend-overlay"></div>
|
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-[0.03] dark:opacity-5 pointer-events-none mix-blend-overlay"></div>
|
||||||
<div className="absolute top-0 left-0 w-full h-full overflow-hidden z-0 pointer-events-none">
|
<div className="absolute top-0 left-0 w-full h-full overflow-hidden z-0 pointer-events-none">
|
||||||
@@ -215,19 +215,73 @@ const Login = () => {
|
|||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
|
|
||||||
<div className="w-full max-w-lg z-10 relative">
|
<div className="w-full max-w-md lg:max-w-4xl z-10 relative">
|
||||||
<SpotlightCard className="bg-white/60 dark:bg-black/30 backdrop-blur-3xl border-0 ring-1 ring-black/5 dark:ring-white/5 shadow-2xl dark:shadow-2xl">
|
<SpotlightCard className="bg-white/60 dark:bg-black/30 backdrop-blur-3xl border-0 ring-1 ring-black/5 dark:ring-white/5 shadow-2xl dark:shadow-2xl overflow-hidden">
|
||||||
<div className="p-6 md:p-10"> {/* ADJUSTED PADDING FOR MOBILE */}
|
{/* Header — full width across both panels */}
|
||||||
<div className="text-center mb-8 md:mb-10 pt-2">
|
<div className="text-center px-5 sm:px-6 md:px-10 pt-4 sm:pt-5 md:pt-6 pb-1">
|
||||||
<img src={Logo} alt="LynkedUp Pro" className="w-20 md:w-24 h-20 md:h-24 mx-auto mb-4 md:mb-6 object-contain drop-shadow-2xl" />
|
<img src={Logo} alt="LynkedUp Pro" className="w-24 sm:w-28 md:w-32 h-24 sm:h-28 md:h-32 mx-auto mb-0.5 sm:mb-1 object-contain drop-shadow-2xl" />
|
||||||
<h1 className="text-2xl md:text-3xl font-black text-zinc-900 dark:text-white mb-2 tracking-tighter">
|
<h1 className="text-xl sm:text-2xl md:text-3xl font-black text-zinc-900 dark:text-white mb-1 tracking-tighter">
|
||||||
Welcome Back
|
Welcome Back
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-zinc-500 font-medium text-base md:text-lg">Sign in to your LynkedUp Pro account</p>
|
<p className="text-zinc-500 font-medium text-sm sm:text-base">Sign in to your LynkedUp Pro account</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Role Tabs — 3-col grid on mobile, 6-col on desktop */}
|
{/* Two-panel body: demo access + manual sign-in.
|
||||||
<div className="grid grid-cols-3 md:grid-cols-6 gap-1.5 p-1.5 bg-zinc-100 dark:bg-black/40 rounded-xl mb-8 md:mb-10 border border-zinc-200 dark:border-white/5">
|
Mobile → stacked, demo access shown FIRST (above the form).
|
||||||
|
Desktop (lg) → side-by-side, sign-in left / demo access right. */}
|
||||||
|
<div className="flex flex-col lg:flex-row">
|
||||||
|
{/* Quick Demo Access — order-first on mobile so links are instantly visible */}
|
||||||
|
<div className="order-1 lg:order-2 lg:w-1/2 p-5 sm:p-6 md:p-8 mt-4 lg:mt-0 border-t lg:border-t-0 lg:border-l border-zinc-200 dark:border-white/5 bg-zinc-50/60 dark:bg-white/[0.02]">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<Zap size={15} className="text-amber-500 shrink-0" />
|
||||||
|
<p className="text-[11px] text-zinc-700 dark:text-zinc-200 uppercase tracking-widest font-bold">Quick Demo Access</p>
|
||||||
|
</div>
|
||||||
|
<p className="text-[11px] text-zinc-400 dark:text-zinc-500 mb-4">Pick a role to sign in instantly — no password needed.</p>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
{Object.keys(DEMO_ACCOUNTS).map((roleKey) => {
|
||||||
|
const styles = DEMO_ROLE_STYLES[roleKey] || DEMO_ROLE_STYLES.customer;
|
||||||
|
const isExpanded = expandedDemoRole === roleKey;
|
||||||
|
const isSingle = DEMO_ACCOUNTS[roleKey].length === 1;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={roleKey}
|
||||||
|
onClick={() => toggleDemoRole(roleKey)}
|
||||||
|
className={`flex items-center justify-center gap-1 text-[11px] font-bold uppercase tracking-wider border px-3 py-2.5 rounded-lg transition-all duration-200 ${isExpanded ? styles.active : styles.chip}`}
|
||||||
|
>
|
||||||
|
{DEMO_ROLE_LABELS[roleKey]}
|
||||||
|
{!isSingle && (
|
||||||
|
<span className={`transition-transform duration-200 inline-block ${isExpanded ? 'rotate-180' : ''}`}>▾</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{/* Person picker — expands below chips when a multi-person role is selected */}
|
||||||
|
{expandedDemoRole && DEMO_ACCOUNTS[expandedDemoRole] && (
|
||||||
|
<div className="mt-2 p-2.5 bg-white dark:bg-zinc-900/60 border border-zinc-200 dark:border-white/5 rounded-xl flex flex-col gap-1">
|
||||||
|
{DEMO_ACCOUNTS[expandedDemoRole].map((account) => (
|
||||||
|
<button
|
||||||
|
key={account.id}
|
||||||
|
onClick={() => handleDemoLogin(account)}
|
||||||
|
className="w-full text-left text-[11px] font-semibold text-zinc-700 dark:text-zinc-300 px-3 py-2 rounded-lg hover:bg-zinc-100 dark:hover:bg-zinc-800 hover:text-zinc-900 dark:hover:text-white transition-colors flex items-center justify-between group"
|
||||||
|
>
|
||||||
|
<span>{account.name}</span>
|
||||||
|
<span className="text-zinc-400 dark:text-zinc-600 text-[10px] font-mono group-hover:text-zinc-500 dark:group-hover:text-zinc-400 transition-colors">{account.id}</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Manual sign-in */}
|
||||||
|
<div className="order-2 lg:order-1 lg:w-1/2 p-5 sm:p-6 md:p-8 border-t lg:border-t-0 border-zinc-200 dark:border-white/5">
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<Lock size={15} className="text-zinc-400 dark:text-zinc-500 shrink-0" />
|
||||||
|
<p className="text-[11px] text-zinc-700 dark:text-zinc-200 uppercase tracking-widest font-bold">Sign in with your account</p>
|
||||||
|
</div>
|
||||||
|
<p className="text-[11px] text-zinc-400 dark:text-zinc-500 mb-4">Enter your username and password below.</p>
|
||||||
|
{/* Role Tabs — 3-col grid (temporarily disabled) */}
|
||||||
|
{/* <div className="grid grid-cols-3 gap-1.5 p-1.5 bg-zinc-100 dark:bg-black/40 rounded-xl mb-5 sm:mb-6 border border-zinc-200 dark:border-white/5">
|
||||||
{[
|
{[
|
||||||
{ key: 'customer', label: 'Customer' },
|
{ key: 'customer', label: 'Customer' },
|
||||||
{ key: 'employee', label: 'Employee' },
|
{ key: 'employee', label: 'Employee' },
|
||||||
@@ -246,9 +300,9 @@ const Login = () => {
|
|||||||
{label}
|
{label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<form onSubmit={handleLogin} className="space-y-6 md:space-y-8">
|
<form onSubmit={handleLogin} className="space-y-4 sm:space-y-5">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label htmlFor="identifier" className="text-xs font-bold text-zinc-500 ml-1 uppercase tracking-widest">
|
<label htmlFor="identifier" className="text-xs font-bold text-zinc-500 ml-1 uppercase tracking-widest">
|
||||||
{loginType === 'employee' ? 'Employee ID' : 'Username'}
|
{loginType === 'employee' ? 'Employee ID' : 'Username'}
|
||||||
@@ -263,7 +317,7 @@ const Login = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
value={identifier}
|
value={identifier}
|
||||||
onChange={(e) => setIdentifier(e.target.value)}
|
onChange={(e) => setIdentifier(e.target.value)}
|
||||||
className="w-full bg-zinc-100 dark:bg-zinc-900/50 border border-zinc-200 dark:border-white/5 text-zinc-900 dark:text-white rounded-xl py-4 pl-12 pr-4 focus:outline-none focus:ring-1 focus:ring-black/10 dark:focus:ring-white/20 focus:bg-white dark:focus:bg-zinc-900 transition-all placeholder:text-zinc-400 dark:placeholder:text-zinc-700 font-medium relative z-0"
|
className="w-full bg-zinc-100 dark:bg-zinc-900/50 border border-zinc-200 dark:border-white/5 text-zinc-900 dark:text-white rounded-xl py-2.5 sm:py-3 pl-12 pr-4 focus:outline-none focus:ring-1 focus:ring-black/10 dark:focus:ring-white/20 focus:bg-white dark:focus:bg-zinc-900 transition-all placeholder:text-zinc-400 dark:placeholder:text-zinc-700 font-medium relative z-0"
|
||||||
placeholder={loginType === 'employee' ? "e.g., LUP-1040" : "e.g., username"}
|
placeholder={loginType === 'employee' ? "e.g., LUP-1040" : "e.g., username"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -286,7 +340,7 @@ const Login = () => {
|
|||||||
type={showPassword ? "text" : "password"}
|
type={showPassword ? "text" : "password"}
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
className="w-full bg-zinc-100 dark:bg-zinc-900/50 border border-zinc-200 dark:border-white/5 text-zinc-900 dark:text-white rounded-xl py-4 pl-12 pr-12 focus:outline-none focus:ring-1 focus:ring-black/10 dark:focus:ring-white/20 focus:bg-white dark:focus:bg-zinc-900 transition-all placeholder:text-zinc-400 dark:placeholder:text-zinc-700 font-medium relative z-0"
|
className="w-full bg-zinc-100 dark:bg-zinc-900/50 border border-zinc-200 dark:border-white/5 text-zinc-900 dark:text-white rounded-xl py-2.5 sm:py-3 pl-12 pr-12 focus:outline-none focus:ring-1 focus:ring-black/10 dark:focus:ring-white/20 focus:bg-white dark:focus:bg-zinc-900 transition-all placeholder:text-zinc-400 dark:placeholder:text-zinc-700 font-medium relative z-0"
|
||||||
placeholder="Enter your password"
|
placeholder="Enter your password"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
@@ -306,49 +360,11 @@ const Login = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<RainbowButton type="submit" className="mt-4 text-white py-4 md:py-5 text-base md:text-lg">
|
<RainbowButton type="submit" className="mt-2 text-white py-3.5 sm:py-4 text-base md:text-lg">
|
||||||
<span>Sign In</span>
|
<span>Sign In</span>
|
||||||
<ArrowRight size={20} />
|
<ArrowRight size={20} />
|
||||||
</RainbowButton>
|
</RainbowButton>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Demo Quick Links — per-role person picker */}
|
|
||||||
<div className="mt-8 md:mt-10 pt-6 md:pt-8 border-t border-zinc-200 dark:border-white/5">
|
|
||||||
<p className="text-[10px] text-center text-zinc-500 uppercase tracking-widest font-bold mb-4">Quick Demo Access</p>
|
|
||||||
<div className="flex flex-wrap gap-2 justify-center mb-3">
|
|
||||||
{Object.keys(DEMO_ACCOUNTS).map((roleKey) => {
|
|
||||||
const styles = DEMO_ROLE_STYLES[roleKey] || DEMO_ROLE_STYLES.customer;
|
|
||||||
const isExpanded = expandedDemoRole === roleKey;
|
|
||||||
const isSingle = DEMO_ACCOUNTS[roleKey].length === 1;
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
key={roleKey}
|
|
||||||
onClick={() => toggleDemoRole(roleKey)}
|
|
||||||
className={`text-[10px] font-bold uppercase tracking-wider border px-3 py-2 rounded-lg transition-all duration-200 ${isExpanded ? styles.active : styles.chip}`}
|
|
||||||
>
|
|
||||||
{DEMO_ROLE_LABELS[roleKey]}
|
|
||||||
{!isSingle && (
|
|
||||||
<span className={`ml-1 transition-transform duration-200 inline-block ${isExpanded ? 'rotate-180' : ''}`}>▾</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
{/* Person picker — expands below chips when a multi-person role is selected */}
|
|
||||||
{expandedDemoRole && DEMO_ACCOUNTS[expandedDemoRole] && (
|
|
||||||
<div className="mt-2 p-2.5 bg-zinc-50 dark:bg-zinc-900/60 border border-zinc-200 dark:border-white/5 rounded-xl flex flex-col gap-1">
|
|
||||||
{DEMO_ACCOUNTS[expandedDemoRole].map((account) => (
|
|
||||||
<button
|
|
||||||
key={account.id}
|
|
||||||
onClick={() => handleDemoLogin(account)}
|
|
||||||
className="w-full text-left text-[11px] font-semibold text-zinc-700 dark:text-zinc-300 px-3 py-2 rounded-lg hover:bg-zinc-100 dark:hover:bg-zinc-800 hover:text-zinc-900 dark:hover:text-white transition-colors flex items-center justify-between group"
|
|
||||||
>
|
|
||||||
<span>{account.name}</span>
|
|
||||||
<span className="text-zinc-400 dark:text-zinc-600 text-[10px] font-mono group-hover:text-zinc-500 dark:group-hover:text-zinc-400 transition-colors">{account.id}</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SpotlightCard>
|
</SpotlightCard>
|
||||||
|
|||||||
Reference in New Issue
Block a user