2026-01-07 10:10:12 +09:00
|
|
|
import { NavLink, useLocation } from 'react-router-dom';
|
|
|
|
|
import { Home, Users, Disc3, Calendar } from 'lucide-react';
|
2026-01-09 09:26:51 +09:00
|
|
|
import { useEffect } from 'react';
|
2026-01-09 18:05:07 +09:00
|
|
|
import '../../mobile.css';
|
2026-01-07 10:10:12 +09:00
|
|
|
|
|
|
|
|
// 모바일 헤더 컴포넌트
|
|
|
|
|
function MobileHeader({ title }) {
|
|
|
|
|
return (
|
|
|
|
|
<header className="bg-white shadow-sm sticky top-0 z-50">
|
|
|
|
|
<div className="flex items-center justify-center h-14 px-4">
|
|
|
|
|
{title ? (
|
|
|
|
|
<span className="text-xl font-bold text-primary">{title}</span>
|
|
|
|
|
) : (
|
|
|
|
|
<NavLink to="/" className="text-xl font-bold text-primary">
|
|
|
|
|
fromis_9
|
|
|
|
|
</NavLink>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 모바일 하단 네비게이션
|
|
|
|
|
function MobileBottomNav() {
|
|
|
|
|
const location = useLocation();
|
|
|
|
|
|
|
|
|
|
const navItems = [
|
|
|
|
|
{ path: '/', label: '홈', icon: Home },
|
|
|
|
|
{ path: '/members', label: '멤버', icon: Users },
|
|
|
|
|
{ path: '/album', label: '앨범', icon: Disc3 },
|
|
|
|
|
{ path: '/schedule', label: '일정', icon: Calendar },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return (
|
2026-01-09 09:26:51 +09:00
|
|
|
<nav className="flex-shrink-0 bg-white border-t border-gray-200 z-50 safe-area-bottom">
|
2026-01-07 10:10:12 +09:00
|
|
|
<div className="flex items-center justify-around h-16">
|
|
|
|
|
{navItems.map((item) => {
|
|
|
|
|
const Icon = item.icon;
|
|
|
|
|
const isActive = location.pathname === item.path ||
|
|
|
|
|
(item.path !== '/' && location.pathname.startsWith(item.path));
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<NavLink
|
|
|
|
|
key={item.path}
|
|
|
|
|
to={item.path}
|
|
|
|
|
className={`flex flex-col items-center justify-center gap-1 w-full h-full transition-colors ${
|
|
|
|
|
isActive ? 'text-primary' : 'text-gray-400'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<Icon size={22} strokeWidth={isActive ? 2.5 : 2} />
|
|
|
|
|
<span className="text-xs font-medium">{item.label}</span>
|
|
|
|
|
</NavLink>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
</nav>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 모바일 레이아웃 컴포넌트
|
|
|
|
|
// pageTitle: 헤더에 표시할 제목 (없으면 fromis_9)
|
|
|
|
|
// hideHeader: true면 헤더 숨김 (일정 페이지처럼 자체 헤더가 있는 경우)
|
2026-01-09 09:26:51 +09:00
|
|
|
// useCustomLayout: true면 자체 레이아웃 사용 (mobile-layout-container를 페이지에서 관리)
|
|
|
|
|
function MobileLayout({ children, pageTitle, hideHeader = false, useCustomLayout = false }) {
|
|
|
|
|
// 모바일 레이아웃 활성화 (body 스크롤 방지)
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
document.documentElement.classList.add('mobile-layout');
|
|
|
|
|
return () => {
|
|
|
|
|
document.documentElement.classList.remove('mobile-layout');
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// 자체 레이아웃 사용 시 (Schedule 페이지 등)
|
|
|
|
|
if (useCustomLayout) {
|
|
|
|
|
return (
|
2026-01-12 14:51:15 +09:00
|
|
|
<div className="mobile-layout-container bg-white">
|
2026-01-09 09:26:51 +09:00
|
|
|
{children}
|
|
|
|
|
<MobileBottomNav />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-07 10:10:12 +09:00
|
|
|
return (
|
2026-01-12 14:51:15 +09:00
|
|
|
<div className="mobile-layout-container bg-white">
|
2026-01-07 10:10:12 +09:00
|
|
|
{!hideHeader && <MobileHeader title={pageTitle} />}
|
2026-01-09 09:26:51 +09:00
|
|
|
<main className="mobile-content">{children}</main>
|
2026-01-07 10:10:12 +09:00
|
|
|
<MobileBottomNav />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default MobileLayout;
|
|
|
|
|
|