diff --git a/src/App.tsx b/src/App.tsx
index f702fa08..b09fa42b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,7 +1,22 @@
+import { Outlet, useLocation } from 'react-router-dom';
+
import './App.css';
+import { Gnb, Layout } from './components/layout';
+import { DEFAULT_TAB, PATH_TO_TAB } from './constants/navigation';
function App() {
- return <>>;
+ const location = useLocation();
+ const activeTab = PATH_TO_TAB[location.pathname] ?? DEFAULT_TAB;
+
+ return (
+ 로고}
+ headerCenter={}
+ headerRight={로그인
}
+ >
+
+
+ );
}
export default App;
diff --git a/src/components/layout/GNB.tsx b/src/components/layout/Gnb.tsx
similarity index 53%
rename from src/components/layout/GNB.tsx
rename to src/components/layout/Gnb.tsx
index 144f59b7..2db7fff9 100644
--- a/src/components/layout/GNB.tsx
+++ b/src/components/layout/Gnb.tsx
@@ -1,32 +1,32 @@
+import { Link } from 'react-router-dom';
+
import clsx from 'clsx';
-import { TABS, type Tab } from '../../constants/navigation';
+import { DEFAULT_TAB, TABS, type Tab } from '../../constants/navigation';
-interface GNBProps {
+interface GnbProps {
activeTab?: Tab;
- onTabChange?: (tab: Tab) => void;
}
-export function GNB({ activeTab = 'slide', onTabChange }: GNBProps) {
+export function Gnb({ activeTab = DEFAULT_TAB }: GnbProps) {
return (
diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx
index 9dd91d49..caf158d9 100644
--- a/src/components/layout/Header.tsx
+++ b/src/components/layout/Header.tsx
@@ -1,13 +1,17 @@
import type { ReactNode } from 'react';
interface HeaderProps {
- children?: ReactNode;
+ left?: ReactNode;
+ center?: ReactNode;
+ right?: ReactNode;
}
-export function Header({ children }: HeaderProps) {
+export function Header({ left, center, right }: HeaderProps) {
return (
-
- {children}
+
+ {left}
+ {center}
+ {right}
);
}
diff --git a/src/components/layout/Layout.tsx b/src/components/layout/Layout.tsx
index 1517a961..ff060363 100644
--- a/src/components/layout/Layout.tsx
+++ b/src/components/layout/Layout.tsx
@@ -3,14 +3,16 @@ import type { ReactNode } from 'react';
import { Header } from './Header';
interface LayoutProps {
- header: ReactNode;
+ headerLeft?: ReactNode;
+ headerCenter?: ReactNode;
+ headerRight?: ReactNode;
children?: ReactNode;
}
-export function Layout({ children, header }: LayoutProps) {
+export function Layout({ headerLeft, headerCenter, headerRight, children }: LayoutProps) {
return (
-
+
{children}
);
diff --git a/src/components/layout/index.ts b/src/components/layout/index.ts
index 985c4f27..e5fd9468 100644
--- a/src/components/layout/index.ts
+++ b/src/components/layout/index.ts
@@ -1,3 +1,3 @@
-export { GNB } from './GNB';
+export { Gnb } from './Gnb';
export { Header } from './Header';
export { Layout } from './Layout';
diff --git a/src/constants/navigation.ts b/src/constants/navigation.ts
index 9224f64e..a547c29a 100644
--- a/src/constants/navigation.ts
+++ b/src/constants/navigation.ts
@@ -1,7 +1,14 @@
export const TABS = [
- { key: 'slide', label: '슬라이드' },
- { key: 'video', label: '영상' },
- { key: 'insight', label: '인사이트' },
+ { key: 'slide', label: '슬라이드', path: '/slide' },
+ { key: 'video', label: '영상', path: '/video' },
+ { key: 'insight', label: '인사이트', path: '/insight' },
] as const;
export type Tab = (typeof TABS)[number]['key'];
+
+export const DEFAULT_TAB: Tab = 'slide';
+
+export const PATH_TO_TAB: Record = {
+ '/': DEFAULT_TAB,
+ ...Object.fromEntries(TABS.map((tab) => [tab.path, tab.key])),
+};
diff --git a/src/main.tsx b/src/main.tsx
index 66b0f0df..406b8e1e 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,11 +1,28 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
+import { RouterProvider, createBrowserRouter } from 'react-router-dom';
-import App from './App.tsx';
+import App from './App';
+import InsightPage from './pages/InsightPage';
+import SlidePage from './pages/SlidePage';
+import VideoPage from './pages/VideoPage';
import './styles/index.css';
+const router = createBrowserRouter([
+ {
+ path: '/',
+ element: ,
+ children: [
+ { index: true, element: }, // DEFAULT_TAB 변경 시 동기화 필요
+ { path: 'slide', element: },
+ { path: 'video', element: },
+ { path: 'insight', element: },
+ ],
+ },
+]);
+
createRoot(document.querySelector('#root')!).render(
-
+
,
);
diff --git a/src/pages/InsightPage.tsx b/src/pages/InsightPage.tsx
new file mode 100644
index 00000000..38d9ac0e
--- /dev/null
+++ b/src/pages/InsightPage.tsx
@@ -0,0 +1,7 @@
+export default function InsightPage() {
+ return (
+
+
인사이트
+
+ );
+}
diff --git a/src/pages/SlidePage.tsx b/src/pages/SlidePage.tsx
new file mode 100644
index 00000000..7e3229fb
--- /dev/null
+++ b/src/pages/SlidePage.tsx
@@ -0,0 +1,7 @@
+export default function SlidePage() {
+ return (
+
+
슬라이드
+
+ );
+}
diff --git a/src/pages/VideoPage.tsx b/src/pages/VideoPage.tsx
new file mode 100644
index 00000000..c6b10470
--- /dev/null
+++ b/src/pages/VideoPage.tsx
@@ -0,0 +1,7 @@
+export default function VideoPage() {
+ return (
+
+
영상
+
+ );
+}
diff --git a/src/styles/index.css b/src/styles/index.css
index 1da34e2c..d029f3af 100644
--- a/src/styles/index.css
+++ b/src/styles/index.css
@@ -23,4 +23,8 @@
--font-size-caption: var(--font-size-caption);
--font-size-body-s: var(--font-size-body-s);
--font-size-body-m: var(--font-size-body-m);
+
+ --spacing-15: 3.75rem;
+ --spacing-18: 4.5rem;
+ --spacing-25: 6.25rem;
}
diff --git a/src/styles/theme.css b/src/styles/theme.css
index a00eaff8..fb7cfecf 100644
--- a/src/styles/theme.css
+++ b/src/styles/theme.css
@@ -25,9 +25,9 @@
--line-height: 1.5;
/* 폰트 크기 */
- --font-size-caption: 12px;
- --font-size-body-s: 14px;
- --font-size-body-m: 16px;
+ --font-size-caption: 0.75rem;
+ --font-size-body-s: 0.875rem;
+ --font-size-body-m: 1rem;
/* 폰트 굵기 */
--font-weight-regular: 400;