84 lines
2.7 KiB
TypeScript
84 lines
2.7 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import { usePathname } from 'next/navigation';
|
|
import Header from './nav/Header';
|
|
import Footer from './Footer';
|
|
import PageTransitionEffect from './animation/pageTransitionEffect';
|
|
|
|
import { useTranslation } from '../i18n/useTranslation';
|
|
|
|
// Utility to detect mobile devices
|
|
function isMobileDevice() {
|
|
if (typeof navigator === 'undefined') return false;
|
|
return /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
}
|
|
|
|
interface PageLayoutProps {
|
|
children: React.ReactNode;
|
|
showHeader?: boolean;
|
|
showFooter?: boolean;
|
|
className?: string;
|
|
contentClassName?: string;
|
|
}
|
|
|
|
export default function PageLayout({
|
|
children,
|
|
showHeader = true,
|
|
showFooter = true,
|
|
className = 'bg-white text-gray-900',
|
|
contentClassName = 'flex-1 relative z-10 w-full',
|
|
}: PageLayoutProps) {
|
|
const { t } = useTranslation();
|
|
const isMobile = isMobileDevice();
|
|
const [isLoggingOut, setIsLoggingOut] = useState(false); // NEW
|
|
const pathname = usePathname();
|
|
|
|
// Global scrollbar restore / leak cleanup (runs on navigation)
|
|
useEffect(() => {
|
|
const html = document.documentElement;
|
|
const body = document.body;
|
|
|
|
// ensure a visible/stable vertical scrollbar on desktop
|
|
html.style.overflowY = 'scroll';
|
|
body.style.overflowY = 'auto';
|
|
|
|
// clear common scroll-lock leftovers (gap where scrollbar should be)
|
|
if (html.style.overflow === 'hidden') html.style.overflow = '';
|
|
if (body.style.overflow === 'hidden') body.style.overflow = '';
|
|
html.style.paddingRight = '';
|
|
body.style.paddingRight = '';
|
|
}, [pathname]);
|
|
|
|
return (
|
|
<div className={`min-h-screen w-full flex flex-col ${className}`}>
|
|
|
|
{showHeader && (
|
|
<div className="relative z-50 w-full flex-shrink-0">
|
|
<Header setGlobalLoggingOut={setIsLoggingOut} />
|
|
</div>
|
|
)}
|
|
|
|
{/* Main content */}
|
|
<div className={contentClassName}>
|
|
<PageTransitionEffect>{children}</PageTransitionEffect>
|
|
</div>
|
|
|
|
{showFooter && (
|
|
<div className="relative z-50 w-full flex-shrink-0">
|
|
<Footer />
|
|
</div>
|
|
)}
|
|
|
|
{/* Global logout transition overlay (covers whole page) */}
|
|
{isLoggingOut && (
|
|
<div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/60 backdrop-blur-sm">
|
|
<div className="flex flex-col items-center gap-3 text-white">
|
|
<div className="h-10 w-10 rounded-full border-2 border-white/30 border-t-white animate-spin" />
|
|
<p className="text-sm font-medium">{t('autofix.kb1c1c0e5')}</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
} |