Skip to content

Commit 4845247

Browse files
authored
Merge pull request #20 from YAPP-Github/feat/#19
[FEAT] 공통 Top bar 컴포넌트 구현
2 parents 159bc13 + 03f9de4 commit 4845247

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2+
3+
import TopBar from './TopBar';
4+
5+
const meta: Meta<typeof TopBar> = {
6+
title: 'Shared/UI/TopBar',
7+
component: TopBar,
8+
parameters: {
9+
layout: 'fullscreen',
10+
},
11+
tags: ['autodocs'],
12+
argTypes: {
13+
title: { control: 'text' },
14+
leftIcon: {
15+
control: 'select',
16+
options: [
17+
undefined,
18+
'arrow_prev',
19+
'arrow_next',
20+
'ic_hamburger',
21+
'ic_menu_close',
22+
'ic_refresh',
23+
],
24+
},
25+
rightIcon: {
26+
control: 'select',
27+
options: [
28+
undefined,
29+
'arrow_prev',
30+
'arrow_next',
31+
'ic_hamburger',
32+
'ic_menu_close',
33+
'ic_refresh',
34+
],
35+
},
36+
iconColor: { control: 'color' },
37+
},
38+
args: {
39+
onLeftClick: () => console.log('Left clicked'),
40+
onRightClick: () => console.log('Right clicked'),
41+
},
42+
};
43+
44+
export default meta;
45+
type Story = StoryObj<typeof meta>;
46+
47+
export const Default: Story = {
48+
args: {
49+
title: '페이지 제목',
50+
},
51+
};
52+
53+
export const WithBack: Story = {
54+
args: {
55+
title: '페이지 제목',
56+
leftIcon: 'arrow_prev',
57+
},
58+
};
59+
60+
export const WithBackAndAction: Story = {
61+
args: {
62+
title: '페이지 제목',
63+
leftIcon: 'arrow_prev',
64+
rightIcon: 'ic_menu_close',
65+
},
66+
};
67+
68+
export const OnlyIcons: Story = {
69+
args: {
70+
leftIcon: 'ic_hamburger',
71+
rightIcon: 'ic_refresh',
72+
},
73+
};
74+
75+
export const LongTitle: Story = {
76+
args: {
77+
leftIcon: 'arrow_prev',
78+
title:
79+
'엄청나게 긴 페이지 제목입니다 엄청나게 긴 페이지 제목입니다 확인해보세요',
80+
rightIcon: 'ic_menu_close',
81+
},
82+
};

src/shared/ui/top-bar/TopBar.tsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { HTMLAttributes } from 'react';
2+
3+
import { IconName } from '../../assets/icons';
4+
import Icon from '../icon/Icon';
5+
6+
interface TopBarProps extends HTMLAttributes<HTMLElement> {
7+
title?: string;
8+
leftIcon?: IconName;
9+
onLeftClick?: () => void;
10+
rightIcon?: IconName;
11+
onRightClick?: () => void;
12+
className?: string;
13+
/**
14+
* 좌우 아이콘의 색상을 지정합니다.
15+
* 현재는 일관된 스타일 유지를 위해 동일한 색상을 적용하지만, 추후 확장이 필요하면 개별 로직으로 분리할 수 있습니다.
16+
*/
17+
iconColor?: string;
18+
}
19+
20+
export default function TopBar({
21+
title,
22+
leftIcon,
23+
onLeftClick,
24+
rightIcon,
25+
onRightClick,
26+
className,
27+
iconColor,
28+
...props
29+
}: TopBarProps) {
30+
return (
31+
<header
32+
className={`bg-gray-0 relative flex h-14 w-full shrink-0 items-center justify-between px-1 ${
33+
className || ''
34+
}`}
35+
{...props}
36+
>
37+
{/* 좌측 아이콘 영역 - 터치 타겟 확보를 위해 고정 크기 사용 */}
38+
<div className='flex h-12 w-12 items-center justify-center'>
39+
{leftIcon && (
40+
<button
41+
type='button'
42+
onClick={onLeftClick}
43+
className='flex h-full w-full items-center justify-center rounded-full p-2 active:bg-gray-100'
44+
aria-label='Left Action'
45+
>
46+
<Icon name={leftIcon} size={24} color={iconColor} />
47+
</button>
48+
)}
49+
</div>
50+
51+
{/* 제목 영역 - 완벽한 중앙 정렬을 위해 absolute 포지셔닝 사용 */}
52+
<h1 className='text-title-7 absolute top-1/2 left-1/2 max-w-[calc(100%-120px)] -translate-x-1/2 -translate-y-1/2 truncate text-center text-gray-900'>
53+
{title}
54+
</h1>
55+
56+
{/* 우측 아이콘 영역 - 터치 타겟 확보를 위해 고정 크기 사용 */}
57+
<div className='flex h-12 w-12 items-center justify-center'>
58+
{rightIcon && (
59+
<button
60+
type='button'
61+
onClick={onRightClick}
62+
className='flex h-full w-full items-center justify-center rounded-full p-2 active:bg-gray-100'
63+
aria-label='Right Action'
64+
>
65+
<Icon name={rightIcon} size={24} color={iconColor} />
66+
</button>
67+
)}
68+
</div>
69+
</header>
70+
);
71+
}

src/shared/ui/top-bar/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as TopBar } from './TopBar';

0 commit comments

Comments
 (0)