107 lines
4.5 KiB
JavaScript
107 lines
4.5 KiB
JavaScript
import React, { useEffect } from 'react';
|
|
import { Routes, Route, useLocation } from 'react-router-dom';
|
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
import DeviceLayout, { useIsMobile } from './components/DeviceLayout';
|
|
import Sidebar from './components/Sidebar';
|
|
import ServerDetail from './pages/ServerDetail';
|
|
import WorldsPage from './pages/WorldsPage';
|
|
import PlayersPage from './pages/PlayersPage';
|
|
import PlayerStatsPage from './pages/PlayerStatsPage';
|
|
import WorldMapPage from './pages/WorldMapPage';
|
|
import LoginPage from './pages/LoginPage';
|
|
import RegisterPage from './pages/RegisterPage';
|
|
import VerifyEmailPage from './pages/VerifyEmailPage';
|
|
import Admin from './pages/Admin';
|
|
import ProfilePage from './pages/ProfilePage';
|
|
|
|
// 페이지 전환 애니메이션 래퍼 컴포넌트
|
|
const PageWrapper = ({ children }) => (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: -20 }}
|
|
transition={{ duration: 0.2, ease: 'easeOut' }}
|
|
>
|
|
{children}
|
|
</motion.div>
|
|
);
|
|
|
|
function App() {
|
|
const isMobile = useIsMobile();
|
|
const location = useLocation();
|
|
|
|
// 인증 페이지 여부 확인 (사이드바 없이 렌더링)
|
|
const isAuthPage = ['/login', '/register'].includes(location.pathname) ||
|
|
location.pathname.startsWith('/verify/');
|
|
|
|
// 별도 레이아웃 페이지 (관리자, 프로필)
|
|
const isStandalonePage = ['/admin', '/profile'].includes(location.pathname);
|
|
|
|
// 라우트 전환 시 스크롤 맨 위로
|
|
useEffect(() => {
|
|
window.scrollTo(0, 0);
|
|
}, [location.pathname]);
|
|
|
|
// 인증 페이지는 사이드바 없이 렌더링
|
|
if (isAuthPage) {
|
|
return (
|
|
<DeviceLayout>
|
|
<div className="min-h-screen bg-mc-bg text-gray-200 font-sans selection:bg-mc-green/30">
|
|
<div className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] opacity-[0.03] pointer-events-none"></div>
|
|
<AnimatePresence mode="wait">
|
|
<Routes location={location} key={location.pathname}>
|
|
<Route path="/login" element={<PageWrapper><LoginPage /></PageWrapper>} />
|
|
<Route path="/register" element={<PageWrapper><RegisterPage /></PageWrapper>} />
|
|
<Route path="/verify/:token" element={<PageWrapper><VerifyEmailPage /></PageWrapper>} />
|
|
</Routes>
|
|
</AnimatePresence>
|
|
</div>
|
|
</DeviceLayout>
|
|
);
|
|
}
|
|
|
|
// 관리자/프로필 페이지는 별도 레이아웃
|
|
if (isStandalonePage) {
|
|
return (
|
|
<DeviceLayout>
|
|
<div className="bg-mc-bg text-gray-200 font-sans selection:bg-mc-green/30">
|
|
<div className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] opacity-[0.03] pointer-events-none"></div>
|
|
<AnimatePresence mode="wait">
|
|
<Routes location={location} key={location.pathname}>
|
|
<Route path="/admin" element={<PageWrapper><Admin /></PageWrapper>} />
|
|
<Route path="/profile" element={<PageWrapper><ProfilePage /></PageWrapper>} />
|
|
</Routes>
|
|
</AnimatePresence>
|
|
</div>
|
|
</DeviceLayout>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<DeviceLayout>
|
|
<div className="min-h-screen bg-mc-bg text-gray-200 font-sans selection:bg-mc-green/30">
|
|
<div className="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/cubes.png')] opacity-[0.03] pointer-events-none"></div>
|
|
|
|
{/* 사이드바 + 메인 콘텐츠 레이아웃 */}
|
|
<div className={`flex min-h-screen ${isMobile ? 'flex-col' : ''}`}>
|
|
<Sidebar isMobile={isMobile} />
|
|
|
|
{/* 메인 콘텐츠 영역 */}
|
|
<main className="flex-1 min-w-0 overflow-hidden">
|
|
<AnimatePresence mode="wait">
|
|
<Routes location={location} key={location.pathname}>
|
|
<Route path="/" element={<PageWrapper><ServerDetail isMobile={isMobile} /></PageWrapper>} />
|
|
<Route path="/worlds" element={<PageWrapper><WorldsPage isMobile={isMobile} /></PageWrapper>} />
|
|
<Route path="/players" element={<PageWrapper><PlayersPage isMobile={isMobile} /></PageWrapper>} />
|
|
<Route path="/player/:uuid/stats" element={<PageWrapper><PlayerStatsPage isMobile={isMobile} /></PageWrapper>} />
|
|
<Route path="/worldmap" element={<PageWrapper><WorldMapPage isMobile={isMobile} /></PageWrapper>} />
|
|
</Routes>
|
|
</AnimatePresence>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
</DeviceLayout>
|
|
);
|
|
}
|
|
|
|
export default App;
|