From 388d99d05fbf06bb94de4c45442e09e9bbf975b6 Mon Sep 17 00:00:00 2001 From: HYOJIN Date: Tue, 31 Mar 2026 15:16:14 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EA=B3=B5=ED=86=B5=20UI=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20=EB=B0=98=EC=98=81=20-=202=EB=8B=A8=20?= =?UTF-8?q?=ED=83=AD=20=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B9=B4=EB=93=9C=20=EB=86=92=EC=9D=B4=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC=20(#121)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 2단 탭 레이아웃 (섹션 탭 slate-900 + 서브 탭 언더라인) - 섹션 탭에서 다른 섹션으로 직접 이동 가능 - 메인화면 카드 CSS Grid 전환 (높이 자동 동기화) - h-screen 고정 + 탭/콘텐츠 영역 분리 - 중앙 정렬 (메인 섹션 + 서브 섹션) Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/App.tsx | 54 +++++---- frontend/src/components/Navbar.tsx | 183 ++++++++++++++++++----------- frontend/src/theme/base.css | 13 +- 3 files changed, 156 insertions(+), 94 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 96c6356..416167e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -25,26 +25,40 @@ function AppLayout() { const isMainMenu = location.pathname === '/'; return ( -
-
- - }> - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - -
+
+ {/* 메인 화면: 전체화면, 섹션 페이지: 탭 + 스크롤 콘텐츠 */} + {isMainMenu ? ( +
+ }> + + } /> + + +
+ ) : ( + <> +
+ +
+
+ }> + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + +
+ + )}
); diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index adf72d7..564edcf 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -1,49 +1,75 @@ -import { Link, useLocation } from 'react-router-dom'; +import { Link, useLocation, useNavigate } from 'react-router-dom'; import { useThemeContext } from '../contexts/ThemeContext'; -interface NavSection { - key: string; - title: string; - paths: string[]; - items: { path: string; label: string; icon: string }[]; +interface MenuItem { + id: string; + label: string; + path: string; } -const sections: NavSection[] = [ +interface MenuSection { + id: string; + label: string; + shortLabel: string; + icon: React.ReactNode; + defaultPath: string; + children: MenuItem[]; +} + +const MENU_STRUCTURE: MenuSection[] = [ { - 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: '📅' }, + id: 'collector', + label: 'S&P Collector', + shortLabel: 'Collector', + icon: ( + + + + ), + defaultPath: '/dashboard', + children: [ + { id: 'dashboard', label: '대시보드', path: '/dashboard' }, + { id: 'executions', label: '실행 이력', path: '/executions' }, + { id: 'recollects', label: '재수집 이력', path: '/recollects' }, + { id: 'jobs', label: '작업 관리', path: '/jobs' }, + { id: 'schedules', label: '스케줄', path: '/schedules' }, + { id: 'timeline', label: '타임라인', path: '/schedule-timeline' }, ], }, { - key: 'bypass', - title: 'S&P Bypass', - paths: ['/bypass-config'], - items: [ - { path: '/bypass-config', label: 'Bypass API', icon: '🔗' }, + id: 'bypass', + label: 'S&P Bypass', + shortLabel: 'Bypass', + icon: ( + + + + ), + defaultPath: '/bypass-config', + children: [ + { id: 'bypass-config', label: 'Bypass API', path: '/bypass-config' }, ], }, { - 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: '📜' }, + id: 'risk', + label: 'S&P Risk & Compliance', + shortLabel: 'Risk & Compliance', + icon: ( + + + + ), + defaultPath: '/screening-guide', + children: [ + { id: 'screening-guide', label: 'Screening Guide', path: '/screening-guide' }, + { id: 'risk-compliance-history', label: 'Change History', path: '/risk-compliance-history' }, ], }, ]; -function getCurrentSection(pathname: string): NavSection | null { - for (const section of sections) { - if (section.paths.some((p) => pathname === p || pathname.startsWith(p + '/'))) { +function getCurrentSection(pathname: string): MenuSection | null { + for (const section of MENU_STRUCTURE) { + if (section.children.some((c) => pathname === c.path || pathname.startsWith(c.path + '/'))) { return section; } } @@ -52,56 +78,75 @@ function getCurrentSection(pathname: string): NavSection | null { export default function Navbar() { const location = useLocation(); + const navigate = useNavigate(); 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'; + const isActivePath = (path: string) => { return location.pathname === path || location.pathname.startsWith(path + '/'); }; return ( - +
); } diff --git a/frontend/src/theme/base.css b/frontend/src/theme/base.css index 7148406..de7d284 100644 --- a/frontend/src/theme/base.css +++ b/frontend/src/theme/base.css @@ -27,16 +27,19 @@ body { /* Main Menu Cards */ .gc-cards { padding: 2rem 0; - display: flex; - justify-content: center; - align-items: stretch; + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-auto-rows: 1fr; gap: 2rem; width: 80%; margin: 0 auto; } -.gc-cards > * { - flex: 1 1 0; +@media (max-width: 768px) { + .gc-cards { + grid-template-columns: 1fr; + width: 90%; + } } .gc-card { From 27972126755c6ba58941ab64f8b6ab9955d91e88 Mon Sep 17 00:00:00 2001 From: HYOJIN Date: Tue, 31 Mar 2026 15:18:29 +0900 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=EB=A6=B4=EB=A6=AC=EC=A6=88=20?= =?UTF-8?q?=EB=85=B8=ED=8A=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/RELEASE-NOTES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/RELEASE-NOTES.md b/docs/RELEASE-NOTES.md index 6817940..c9dee1d 100644 --- a/docs/RELEASE-NOTES.md +++ b/docs/RELEASE-NOTES.md @@ -4,6 +4,12 @@ ## [Unreleased] +### 추가 +- 공통 UI 피드백 반영 (#121) + - 2단 탭 네비게이션 (섹션 탭 + 서브 탭) + - 섹션 간 직접 이동 + - 메인화면 카드 높이 동기화 (CSS Grid) + ## [2026-03-31] ### 추가