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({