refactor(design): implement improved OLED dark palette and typography system

- Upgraded color palette with enhanced contrast (5.2:1 to 15:1 ratios)
- Replaced all text-slate-* utilities with semantic color tokens
- Added Fira Code + Fira Sans typography stack
- Converted CSS variables from SCSS to direct hex values
- Updated 26 components with improved color semantics
- Added cursor-pointer and focus states (accessibility phase 1)
- Added aria-labels to 35+ icon-only buttons
- Added prefers-reduced-motion support in globals.css

WCAG AA compliance verified across all text color combinations.
Fixes invisible text issues (slate-500 4.2:1 → muted 5.2:1).
This commit is contained in:
2026-04-17 13:14:09 +03:00
parent 21b1d815d3
commit 9611b991b6
27 changed files with 648 additions and 346 deletions

View File

@@ -79,16 +79,16 @@ export default function LoginPage() {
if (!mounted) return null;
return (
<div className="min-h-screen bg-slate-950 flex items-center justify-center p-4">
<div className="min-h-screen bg-background flex items-center justify-center p-4">
<Toaster position="top-center" />
<div className="bg-slate-900 border border-slate-800 rounded-3xl p-8 max-w-sm w-full shadow-2xl space-y-8 animate-in fade-in zoom-in duration-500">
<div className="bg-surface border border-slate-800 rounded-3xl p-8 max-w-sm w-full shadow-2xl space-y-8 animate-in fade-in zoom-in duration-500">
<div className="text-center space-y-2">
<div className="w-16 h-16 bg-primary/10 text-primary rounded-2xl flex items-center justify-center mx-auto mb-4 border border-primary/20">
<User size={32} />
</div>
<h2 className="text-2xl font-black text-white tracking-tight">Identity Check</h2>
<p className="text-slate-500 text-sm">Select operator profile or use direct login</p>
<p className="text-muted text-sm">Select operator profile or use direct login</p>
</div>
<div className="grid gap-3">
@@ -103,20 +103,20 @@ export default function LoginPage() {
className="bg-slate-800/50 hover:bg-slate-800 border border-slate-800 hover:border-primary/40 p-4 rounded-2xl text-left transition-all group flex items-center justify-between"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-full bg-slate-900 border border-slate-700 flex items-center justify-center text-slate-500 group-hover:text-primary transition-colors">
<div className="w-8 h-8 rounded-full bg-surface border border-slate-700 flex items-center justify-center text-muted group-hover:text-primary transition-colors">
{user.role === 'admin' ? <Shield size={14} /> : <User size={14} />}
</div>
<div>
<p className="text-white font-black text-sm">{user.username}</p>
<p className="text-xs text-slate-500 font-bold mt-1">{user.role}</p>
<p className="text-xs text-muted font-bold mt-1">{user.role}</p>
</div>
</div>
<ChevronRight size={16} className="text-slate-600 group-hover:text-primary transition-colors" />
<ChevronRight size={16} className="text-secondary group-hover:text-primary transition-colors" />
</button>
))}
</>
) : (
<div className="text-center p-4 text-slate-500 text-xs font-bold animate-pulse">
<div className="text-center p-4 text-muted text-xs font-bold animate-pulse">
Connectivity issues? Use manual login below.
</div>
)}
@@ -124,7 +124,7 @@ export default function LoginPage() {
<div className="pt-2 grid grid-cols-2 gap-3">
<button
onClick={() => setIsEnterprise(true)}
className="flex items-center justify-center gap-2 py-4 rounded-2xl border border-dashed border-slate-700 text-slate-500 hover:text-white hover:border-slate-500 transition-all font-bold text-xs"
className="flex items-center justify-center gap-2 py-4 rounded-2xl border border-dashed border-slate-700 text-muted hover:text-white hover:border-slate-500 transition-all font-bold text-xs"
>
<Lock size={12} />
Enterprise
@@ -144,7 +144,7 @@ export default function LoginPage() {
) : isEnterprise ? (
<div className="space-y-4 animate-in slide-in-from-right-4 duration-300">
<div className="flex justify-between items-center px-1">
<p className="text-xs font-black text-slate-500">Enterprise Account</p>
<p className="text-xs font-black text-muted">Enterprise Account</p>
<button
onClick={() => setIsEnterprise(false)}
className="text-xs font-black text-primary hover:underline"
@@ -154,9 +154,9 @@ export default function LoginPage() {
</div>
<div className="space-y-2">
<label className="text-xs font-black text-slate-500 px-1">Username</label>
<label className="text-xs font-black text-muted px-1">Username</label>
<div className="relative">
<User className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500" size={16} />
<User className="absolute left-4 top-1/2 -translate-y-1/2 text-muted" size={16} />
<input
ref={enterpriseUserRef}
type="text"
@@ -168,9 +168,9 @@ export default function LoginPage() {
</div>
<div className="space-y-2">
<label className="text-xs font-black text-slate-500 px-1">Password</label>
<label className="text-xs font-black text-muted px-1">Password</label>
<div className="relative">
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500" size={16} />
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 text-muted" size={16} />
<input
ref={enterprisePassRef}
type="password"
@@ -195,19 +195,19 @@ export default function LoginPage() {
onClick={() => setSelectedUserForLogin(null)}
className="p-1 hover:bg-slate-700 rounded-lg transition-colors"
>
<X size={16} className="text-slate-400" />
<X size={16} className="text-secondary" />
</button>
<div>
<p className="text-sm font-bold text-slate-500">Logging in as</p>
<p className="text-sm font-bold text-muted">Logging in as</p>
<p className="text-white font-black">{selectedUserForLogin.username || "Manual Input"}</p>
</div>
</div>
{!selectedUserForLogin.username && (
<div className="space-y-2">
<label className="text-xs font-black text-slate-500 px-1">Username</label>
<label className="text-xs font-black text-muted px-1">Username</label>
<div className="relative">
<User className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500" size={16} />
<User className="absolute left-4 top-1/2 -translate-y-1/2 text-muted" size={16} />
<input
type="text"
autoFocus
@@ -220,9 +220,9 @@ export default function LoginPage() {
)}
<div className="space-y-2">
<label className="text-xs font-black text-slate-500 px-1">Password</label>
<label className="text-xs font-black text-muted px-1">Password</label>
<div className="relative">
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 text-slate-500" size={16} />
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 text-muted" size={16} />
<input
ref={localPassRef}
type="password"