94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
import { Outlet, useLocation } from "react-router-dom";
|
|
import { motion } from "motion/react";
|
|
import { BottomNav } from "./BottomNav";
|
|
import { Header } from "./Header";
|
|
import { AppBackground } from "./shared/AppBackground";
|
|
import { getLayoutBackgroundByPath } from "../../config/backgroundConfig";
|
|
import { AppHeader } from "./AppHeader";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { useMemo } from "react";
|
|
|
|
export function Layout() {
|
|
const location = useLocation();
|
|
const navigate = useNavigate();
|
|
const shouldShowBackHeader = location.pathname === "/edit-profile";
|
|
const enterFromLogin = useMemo(() => {
|
|
const fromLogin = sessionStorage.getItem("homeEntranceFromLogin") === "1";
|
|
if (fromLogin) {
|
|
sessionStorage.removeItem("homeEntranceFromLogin");
|
|
return true;
|
|
}
|
|
return false;
|
|
}, []);
|
|
|
|
const headerInitial = enterFromLogin ? { opacity: 0, y: -28 } : undefined;
|
|
const headerAnimate = enterFromLogin ? { opacity: 1, y: 0 } : undefined;
|
|
const mainInitial = enterFromLogin ? { opacity: 0, y: 28, scale: 0.985 } : undefined;
|
|
const mainAnimate = enterFromLogin ? { opacity: 1, y: 0, scale: 1 } : undefined;
|
|
const navInitial = enterFromLogin ? { opacity: 0, y: 44 } : undefined;
|
|
const navAnimate = enterFromLogin ? { opacity: 1, y: 0 } : undefined;
|
|
|
|
return (
|
|
<div className="fixed inset-0 w-full h-screen overflow-hidden">
|
|
{/* Background */}
|
|
<AppBackground
|
|
position="fixed"
|
|
zIndex={0}
|
|
imageUrl={getLayoutBackgroundByPath(location.pathname)}
|
|
/>
|
|
|
|
{/* Content */}
|
|
<div className="relative z-10 max-w-md mx-auto h-full flex flex-col">
|
|
{/* Header - Fixed */}
|
|
<motion.div
|
|
initial={headerInitial}
|
|
animate={headerAnimate}
|
|
transition={{ duration: 0.95, delay: 0.28, ease: [0.25, 0.1, 0.25, 1] }}
|
|
className="flex-shrink-0 w-full"
|
|
style={{
|
|
background: "rgba(10, 31, 46, 0)",
|
|
WebkitBackdropFilter: "blur(12px)",
|
|
}}
|
|
>
|
|
{shouldShowBackHeader ? (
|
|
<AppHeader showBack onBack={() => navigate("/profile")} />
|
|
) : (
|
|
<Header />
|
|
)}
|
|
</motion.div>
|
|
|
|
{/* Main Content - Scrollable */}
|
|
<motion.main
|
|
initial={mainInitial}
|
|
animate={mainAnimate}
|
|
transition={{ duration: 1.05, delay: 0.36, ease: [0.25, 0.1, 0.25, 1] }}
|
|
className="flex-1 overflow-y-auto px-4 pb-20"
|
|
style={{
|
|
maskImage: "linear-gradient(to bottom, transparent 0%, black 48px)",
|
|
WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, black 48px)",
|
|
scrollbarWidth: "none",
|
|
msOverflowStyle: "none",
|
|
}}
|
|
>
|
|
<Outlet />
|
|
</motion.main>
|
|
</div>
|
|
|
|
{/* Bottom Navigation - Fixed */}
|
|
<motion.div
|
|
initial={navInitial}
|
|
animate={navAnimate}
|
|
transition={{ duration: 0.98, delay: 0.46, ease: [0.25, 0.1, 0.25, 1] }}
|
|
>
|
|
<BottomNav />
|
|
</motion.div>
|
|
|
|
<style>{`
|
|
main::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
`}</style>
|
|
</div>
|
|
);
|
|
}
|