'use client';
import { useEffect, useState } from 'react';
import { usePathname } from 'next/navigation';
import { Sidebar } from './Sidebar';
interface MobileDrawerProps {
isOpen: boolean;
onClose: () => void;
}
export function MobileDrawer({ isOpen, onClose }: MobileDrawerProps) {
const pathname = usePathname();
const [isVisible, setIsVisible] = useState(false);
const [isAnimating, setIsAnimating] = useState(false);
// Handle visibility and animation states
useEffect(() => {
if (isOpen) {
setIsVisible(true);
// Reset animation state first to ensure it starts from closed position
setIsAnimating(false);
// Trigger animation after DOM is ready - small delay ensures initial state is painted
const timer = setTimeout(() => {
setIsAnimating(true);
}, 10); // Small delay to ensure browser paints the initial closed state
return () => clearTimeout(timer);
} else {
setIsAnimating(false);
// Wait for animation to complete before removing from DOM
const timer = setTimeout(() => {
setIsVisible(false);
}, 300); // Match transition duration
return () => clearTimeout(timer);
}
}, [isOpen]);
// Close drawer on route change
useEffect(() => {
if (isOpen) {
onClose();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pathname]);
// Lock body scroll when open
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
return () => {
document.body.style.overflow = '';
};
}, [isOpen]);
// Close on escape key
useEffect(() => {
if (!isOpen) return;
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handleEscape);
return () => document.removeEventListener('keydown', handleEscape);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen]);
if (!isVisible) return null;
return (
<div className="fixed inset-0 z-[60] md:hidden">
{/* Backdrop */}
<div
className={`fixed inset-0 bg-surface-overlay backdrop-blur-sm transition-opacity duration-300 ${
isAnimating ? 'opacity-100' : 'opacity-0'
}`}
onClick={onClose}
aria-hidden="true"
/>
{/* Drawer */}
<div
className={`fixed inset-y-0 left-0 w-72 bg-surface shadow-xl overflow-y-auto z-10 transition-transform duration-300 ease-out ${
isAnimating ? 'translate-x-0' : '-translate-x-full'
}`}
>
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-default">
<div className="flex items-center gap-2">
<div className="w-8 h-8 bg-primary rounded-lg flex items-center justify-center">
<span className="text-primary-foreground font-bold text-sm">M</span>
</div>
<span className="font-semibold text-default">mcpsystem.design</span>
</div>
<button
type="button"
onClick={onClose}
className="w-8 h-8 flex items-center justify-center rounded-lg hover:bg-surface-hover transition-colors"
aria-label="Close menu"
>
<svg className="w-5 h-5 text-muted" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* Unified Navigation - reuses Sidebar component */}
<Sidebar isMobile onLinkClick={onClose} />
</div>
</div>
);
}