veza/apps/web/src/components/layout/PageTransition.tsx
senke 5f88c56113 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

41 lines
988 B
TypeScript

import { motion } from 'framer-motion';
import { useLocation } from 'react-router-dom';
import { ReactNode, useMemo } from 'react';
interface PageTransitionProps {
children: ReactNode;
}
/**
* S5.3: Subtile page transitions (Linear-style fade + slide-up)
* Respects prefers-reduced-motion for accessibility.
*/
export function PageTransition({ children }: PageTransitionProps) {
const location = useLocation();
const prefersReducedMotion = useMemo(
() =>
typeof window !== 'undefined' &&
window.matchMedia('(prefers-reduced-motion: reduce)').matches,
[],
);
if (prefersReducedMotion) {
return <div key={location.pathname}>{children}</div>;
}
return (
<motion.div
key={location.pathname}
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -8 }}
transition={{
duration: 0.2,
ease: [0.25, 0.1, 0.25, 1],
}}
>
{children}
</motion.div>
);
}