diff --git a/package.json b/package.json
index 4e8c98c..57c722d 100644
--- a/package.json
+++ b/package.json
@@ -13,12 +13,15 @@
"prepare": "husky"
},
"lint-staged": {
- "*.{js,jsx,ts,tsx}": ["biome check"]
+ "*.{js,jsx,ts,tsx}": [
+ "biome check"
+ ]
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.13.5",
"@radix-ui/colors": "^3.0.0",
+ "@radix-ui/react-icons": "^1.3.2",
"@radix-ui/themes": "^3.1.6",
"@tanstack/react-query": "^5.62.10",
"@tanstack/react-query-devtools": "^5.62.11",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4992271..9de9780 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,6 +17,9 @@ importers:
'@radix-ui/colors':
specifier: ^3.0.0
version: 3.0.0
+ '@radix-ui/react-icons':
+ specifier: ^1.3.2
+ version: 1.3.2(react@19.0.0)
'@radix-ui/themes':
specifier: ^3.1.6
version: 3.1.6(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -668,6 +671,11 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-icons@1.3.2':
+ resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==}
+ peerDependencies:
+ react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc
+
'@radix-ui/react-id@1.1.0':
resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==}
peerDependencies:
@@ -2468,6 +2476,10 @@ snapshots:
'@types/react': 18.3.18
'@types/react-dom': 18.3.5(@types/react@18.3.18)
+ '@radix-ui/react-icons@1.3.2(react@19.0.0)':
+ dependencies:
+ react: 19.0.0
+
'@radix-ui/react-id@1.1.0(@types/react@18.3.18)(react@19.0.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.18)(react@19.0.0)
diff --git a/src/Menu/page.tsx b/src/Menu/page.tsx
index 9dc87f2..6452997 100644
--- a/src/Menu/page.tsx
+++ b/src/Menu/page.tsx
@@ -13,7 +13,7 @@ import { Link } from "react-router";
export default function MenuPage() {
return (
<>
-
+
{version}
menu
diff --git a/src/common/components/Header.tsx b/src/common/components/Header.tsx
index f665064..2480e06 100644
--- a/src/common/components/Header.tsx
+++ b/src/common/components/Header.tsx
@@ -1,19 +1,86 @@
import styled from "@emotion/styled";
+import { ChevronLeftIcon } from "@radix-ui/react-icons";
import type { ReactElement } from "react";
+import { useNavigate } from "react-router";
import { Z_INDEX } from "../constants/zIndex";
+import { rem } from "../utils/rem";
+/**
+ * Header 컴포넌트 Props
+ *
+ * 우선순위: render* > backButton, title > 기본 뒤로가기 버튼
+ */
interface HeaderProps {
- left?: ReactElement | string;
- center: ReactElement | string;
- right?: ReactElement | string;
+ /** 백 버튼 커스터마이징 */
+ backButton?: {
+ renderIcon?: () => ReactElement;
+ onClick?: () => void;
+ };
+ /** 헤더 제목 */
+ title?: string;
+ /** 왼쪽 섹션 커스터마이징 */
+ renderLeft?: () => ReactElement;
+ /** 중앙 섹션 커스터마이징 */
+ renderCenter?: () => ReactElement;
+ /** 오른쪽 섹션 커스터마이징 */
+ renderRight?: () => ReactElement;
}
-function Header({ left, center, right }: HeaderProps) {
+/**
+ * 페이지 헤더 컴포넌트
+ *
+ * @example
+ * ```tsx
+ * // default (backButton, title)
+ *
+ *
+ * // backButton ui, 이벤트 커스터마이징
+ * navigate('/') }} />
+ *
+ * // 섹션별 커스터마이징 (renderLeft, renderCenter, renderRight)
+ * } />
+ * ```
+ */
+function Header({ backButton, title, renderLeft, renderCenter, renderRight }: HeaderProps) {
+ const navigate = useNavigate();
+
+ const renderBackButton = () => {
+ const onClickBackButton = () => {
+ if (backButton && "onClick" in backButton && backButton.onClick) {
+ backButton.onClick();
+ return;
+ }
+ // default behavior
+ navigate(-1);
+ };
+
+ return (
+
+ );
+ };
+
+ const renderCenterElement = () => renderCenter && {renderCenter()};
+
+ const renderTitleElement = () =>
+ title && (
+
+ {title}
+
+ );
+
return (
- {left}
- {center}
- {right}
+ {renderLeft?.() ?? renderBackButton()}
+ {renderCenterElement() ?? renderTitleElement()}
+ {renderRight?.()}
);
}
@@ -31,6 +98,7 @@ const HeaderWrapper = styled.header({
height: "4.8rem",
backgroundColor: "white",
+ boxShadow: "0 2px 4px 0 rgba(0, 0, 0, 0.1)",
});
const LeftElement = styled.div({