- 메인 화면(/) 3개 섹션 카드 (Collector/Bypass/Risk&Compliance) - 섹션별 Navbar 분리 + [← 메인] 버튼 - 플랫폼명 S&P Data Platform으로 변경 - gc-card 스타일 적용 (다크 모드 대응) - Dashboard 경로 / → /dashboard 이동 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
108 lines
4.3 KiB
TypeScript
108 lines
4.3 KiB
TypeScript
import { Link, useLocation } from 'react-router-dom';
|
|
import { useThemeContext } from '../contexts/ThemeContext';
|
|
|
|
interface NavSection {
|
|
key: string;
|
|
title: string;
|
|
paths: string[];
|
|
items: { path: string; label: string; icon: string }[];
|
|
}
|
|
|
|
const sections: NavSection[] = [
|
|
{
|
|
key: 'collector',
|
|
title: 'S&P Collector',
|
|
paths: ['/dashboard', '/jobs', '/executions', '/recollects', '/schedules', '/schedule-timeline'],
|
|
items: [
|
|
{ path: '/dashboard', label: '대시보드', icon: '📊' },
|
|
{ path: '/executions', label: '실행 이력', icon: '📋' },
|
|
{ path: '/recollects', label: '재수집 이력', icon: '🔄' },
|
|
{ path: '/jobs', label: '작업', icon: '⚙️' },
|
|
{ path: '/schedules', label: '스케줄', icon: '🕐' },
|
|
{ path: '/schedule-timeline', label: '타임라인', icon: '📅' },
|
|
],
|
|
},
|
|
{
|
|
key: 'bypass',
|
|
title: 'S&P Bypass',
|
|
paths: ['/bypass-config'],
|
|
items: [
|
|
{ path: '/bypass-config', label: 'Bypass API', icon: '🔗' },
|
|
],
|
|
},
|
|
{
|
|
key: 'risk',
|
|
title: 'S&P Risk & Compliance',
|
|
paths: ['/screening-guide', '/risk-compliance-history'],
|
|
items: [
|
|
{ path: '/screening-guide', label: 'Screening Guide', icon: '⚖️' },
|
|
{ path: '/risk-compliance-history', label: 'Change History', icon: '📜' },
|
|
],
|
|
},
|
|
];
|
|
|
|
function getCurrentSection(pathname: string): NavSection | null {
|
|
for (const section of sections) {
|
|
if (section.paths.some((p) => pathname === p || pathname.startsWith(p + '/'))) {
|
|
return section;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export default function Navbar() {
|
|
const location = useLocation();
|
|
const { theme, toggle } = useThemeContext();
|
|
const currentSection = getCurrentSection(location.pathname);
|
|
|
|
// 메인 화면에서는 Navbar 숨김
|
|
if (!currentSection) return null;
|
|
|
|
const isActive = (path: string) => {
|
|
if (path === '/dashboard') return location.pathname === '/dashboard';
|
|
return location.pathname === path || location.pathname.startsWith(path + '/');
|
|
};
|
|
|
|
return (
|
|
<nav className="bg-wing-glass-dense backdrop-blur-sm shadow-md rounded-xl mb-6 px-4 py-3 border border-wing-border">
|
|
<div className="flex items-center justify-between flex-wrap gap-2">
|
|
<div className="flex items-center gap-3">
|
|
<Link
|
|
to="/"
|
|
className="px-2.5 py-1.5 rounded-lg text-sm font-medium no-underline text-wing-muted hover:bg-wing-hover hover:text-wing-accent transition-colors"
|
|
title="메인 메뉴"
|
|
>
|
|
← 메인
|
|
</Link>
|
|
<span className="text-wing-border">|</span>
|
|
<span className="text-sm font-bold text-wing-accent">{currentSection.title}</span>
|
|
</div>
|
|
<div className="flex gap-1 flex-wrap items-center">
|
|
{currentSection.items.map((item) => (
|
|
<Link
|
|
key={item.path}
|
|
to={item.path}
|
|
className={`px-3 py-1.5 rounded-lg text-sm font-medium no-underline transition-colors
|
|
${isActive(item.path)
|
|
? 'bg-wing-accent text-white'
|
|
: 'text-wing-muted hover:bg-wing-hover hover:text-wing-accent'
|
|
}`}
|
|
>
|
|
<span className="mr-1">{item.icon}</span>
|
|
{item.label}
|
|
</Link>
|
|
))}
|
|
<button
|
|
onClick={toggle}
|
|
className="ml-2 px-2.5 py-1.5 rounded-lg text-sm bg-wing-card text-wing-muted
|
|
hover:text-wing-text border border-wing-border transition-colors"
|
|
title={theme === 'dark' ? '라이트 모드' : '다크 모드'}
|
|
>
|
|
{theme === 'dark' ? '☀️' : '🌙'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|