You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import Head from 'next/head';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { TrendingUp, Database, BarChart3, Settings, AlertTriangle, Activity, Search, DollarSign } from 'lucide-react';
interface LayoutProps {
children: React.ReactNode;
title?: string;
}
const ClientLayout: React.FC<LayoutProps> = ({ children, title = 'Stock Oracle' }) => {
const router = useRouter();
const [currentTime, setCurrentTime] = useState<string>('');
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
setCurrentTime(new Date().toLocaleString('ko-KR'));
const timer = setInterval(() => {
setCurrentTime(new Date().toLocaleString('ko-KR'));
}, 1000);
return () => clearInterval(timer);
}, []);
const navigation = [
{
name: '대시보드',
href: '/',
icon: TrendingUp,
current: router.pathname === '/',
},
{
name: '종목 조회',
href: '/stock',
icon: Search,
current: router.pathname === '/stock',
},
{
name: '데이터 조회',
href: '/query',
icon: BarChart3,
current: router.pathname === '/query',
},
{
name: 'FRED 경제데이터',
href: '/fred',
icon: DollarSign,
current: router.pathname === '/fred',
},
{
name: 'DB 상태',
href: '/database',
icon: Database,
current: router.pathname === '/database',
},
{
name: '시스템 로그',
href: '/logs',
icon: Activity,
current: router.pathname === '/logs',
},
{
name: '설정',
href: '/settings',
icon: Settings,
current: router.pathname === '/settings',
},
];
return (
<>
<Head>
<title>{title}</title>
<meta name="description" content="Stock Oracle - 주식 데이터 분석 플랫폼" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{/* Favicon and Icons */}
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="alternate icon" href="/favicon.ico" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
{/* Web App Manifest */}
<link rel="manifest" href="/manifest.json" />
{/* Theme Colors */}
<meta name="theme-color" content="#3b82f6" />
<meta name="msapplication-TileColor" content="#3b82f6" />
{/* Open Graph */}
<meta property="og:title" content="Stock Oracle" />
<meta property="og:description" content="Investment Data Analysis Platform using SEC filings" />
<meta property="og:type" content="website" />
<meta property="og:image" content="/apple-touch-icon.png" />
{/* Twitter Card */}
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Stock Oracle" />
<meta name="twitter:description" content="Investment Data Analysis Platform using SEC filings" />
<meta name="twitter:image" content="/apple-touch-icon.png" />
</Head>
<div className="min-h-screen bg-gray-50">
{/* 사이드바 */}
<div className="fixed inset-y-0 left-0 z-50 w-64 bg-white shadow-lg">
<div className="flex h-16 items-center justify-center border-b border-gray-200">
<div className="flex items-center space-x-2">
<TrendingUp className="h-8 w-8 text-blue-600" />
<h1 className="text-xl font-bold text-gray-900">Stock Oracle</h1>
</div>
</div>
<nav className="mt-6 px-3">
<div className="space-y-1">
{navigation.map((item) => {
const Icon = item.icon;
return (
<Link
key={item.name}
href={item.href}
className={`group flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors ${
item.current
? 'bg-blue-50 text-blue-700 border-r-2 border-blue-700'
: 'text-gray-700 hover:bg-gray-50 hover:text-gray-900'
}`}
>
<Icon
className={`mr-3 h-5 w-5 ${
item.current ? 'text-blue-700' : 'text-gray-400 group-hover:text-gray-500'
}`}
/>
{item.name}
</Link>
);
})}
</div>
</nav>
{/* 하단 정보 */}
<div className="absolute bottom-0 w-full p-4 border-t border-gray-200">
<div className="text-xs text-gray-500">
<p>Stock Oracle v1.0.0</p>
<p>Real-time Financial Data</p>
</div>
</div>
</div>
{/* 메인 콘텐츠 */}
<div className="pl-64">
{/* 헤더 */}
<header className="bg-white shadow-sm border-b border-gray-200">
<div className="px-6 py-4">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-semibold text-gray-900">
{navigation.find(item => item.current)?.name || 'Stock Oracle'}
</h2>
<div className="flex items-center space-x-4">
{/* API 상태 표시 */}
<div className="flex items-center space-x-2">
<div className="h-2 w-2 bg-green-400 rounded-full"></div>
<span className="text-sm text-gray-600">API </span>
</div>
{/* 현재 시간 */}
<div className="text-sm text-gray-500">
{mounted ? currentTime : '--:--:--'}
</div>
</div>
</div>
</div>
</header>
{/* 페이지 콘텐츠 */}
<main className="p-6">
<div className="max-w-7xl mx-auto">
{children}
</div>
</main>
</div>
</div>
</>
);
};
export default ClientLayout;