veza/apps/web/src/components/ui/NavigationProgress.tsx
senke 038b637a3f fix: UI remediation Phase 1 (S0-S5) + Phase 2 Sprint 6 shadow system
Phase 1:
- S0: Fix open redirect (safeNavigate), delete AuthContext/legacy auth, encrypt API keys, gitignore .env files
- S1: Split client.ts god object into 5 modules, unify toast system, delete unused Sidebar
- S2: Add glass button variant, migrate 32 z-index to SUMI tokens, fix card dark mode
- S3: Skip nav link, aria-hidden on icons, focus-visible ring fixes, alt attrs, aria-live regions
- S4: React.memo on list items, fix key={index}, loading=lazy on images
- S5: Branded loading screen, page transitions respect reduced-motion, LikeButton micro-interaction, i18n sidebar/header

Phase 2 Sprint 6:
- Wire Tailwind shadow utilities to SUMI tokens in @theme block (fixes 50+ files)
- Define shadow-card/shadow-card-hover tokens
- Remove dark:shadow-none workarounds from card.tsx (SUMI handles per-theme shadows)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 10:13:44 +01:00

51 lines
1.5 KiB
TypeScript

import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { motion, AnimatePresence } from 'framer-motion';
export function NavigationProgress() {
const location = useLocation();
const [isNavigating, setIsNavigating] = useState(false);
const [progress, setProgress] = useState(0);
useEffect(() => {
setIsNavigating(true);
setProgress(0);
// Simulate progress
const timer1 = setTimeout(() => setProgress(30), 50);
const timer2 = setTimeout(() => setProgress(60), 150);
const timer3 = setTimeout(() => setProgress(80), 300);
const timer4 = setTimeout(() => {
setProgress(100);
setTimeout(() => setIsNavigating(false), 200);
}, 500);
return () => {
clearTimeout(timer1);
clearTimeout(timer2);
clearTimeout(timer3);
clearTimeout(timer4);
};
}, [location.pathname]);
return (
<AnimatePresence>
{isNavigating && (
<motion.div
className="fixed top-0 left-0 right-0 z-[var(--sumi-z-modal)] h-0.5"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.15 }}
>
<motion.div
className="h-full bg-primary shadow-sm"
initial={{ width: '0%' }}
animate={{ width: `${progress}%` }}
transition={{ duration: 0.3, ease: 'easeOut' }}
/>
</motion.div>
)}
</AnimatePresence>
);
}