-
Notifications
You must be signed in to change notification settings - Fork 4
✨feat: 버튼 컴포넌트 구현 + 스토리북 #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
abe448b
20d0cb7
5454199
3a53460
436b180
395d552
11d4e0c
a53fdd7
4497c12
9c4de38
9a3c194
e961a16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import type { Meta, StoryObj } from '@storybook/react'; | ||
| import Link from 'next/link'; | ||
| import Button from './button'; | ||
|
|
||
| const meta: Meta<typeof Button> = { | ||
| title: 'UI/Button', | ||
| component: Button, | ||
| tags: ['autodocs'], | ||
| }; | ||
| export default meta; | ||
|
|
||
| type Story = StoryObj<typeof Button>; | ||
|
|
||
| /** Primary */ | ||
| export const Primary: Story = { | ||
| args: { children: '로그인 하기', variant: 'primary', size: 'lg' }, | ||
| }; | ||
|
|
||
| /** Secondary */ | ||
| export const Secondary: Story = { | ||
| args: { children: '로그인 하기', variant: 'secondary', size: 'lg' }, | ||
| }; | ||
|
|
||
| /** Disabled */ | ||
| export const Disabled: Story = { | ||
| args: { children: '신청 불가', variant: 'disabled', size: 'lg' }, | ||
| }; | ||
|
|
||
| /** 승인/거절 아웃라인 버튼 */ | ||
| export const ApproveReject: Story = { | ||
| render: () => ( | ||
| <div className='flex items-center gap-4'> | ||
| <Button variant='approve' size='md'> | ||
| 승인하기 | ||
| </Button> | ||
| <Button variant='reject' size='md'> | ||
| 거절하기 | ||
| </Button> | ||
| </div> | ||
| ), | ||
| }; | ||
|
|
||
| /* Link로 렌더링 (as prop 사용 예) */ | ||
| export const AsLink: Story = { | ||
| args: { | ||
| as: Link, | ||
| href: '/profile/create', | ||
| variant: 'primary', | ||
| full: true, | ||
| children: '내 프로필 등록하기', | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import { ButtonHTMLAttributes, ElementType } from 'react'; | ||
|
|
||
| type ButtonProps = { | ||
| variant?: 'primary' | 'secondary' | 'disabled' | 'approve' | 'reject'; | ||
| size?: 'lg' | 'md' | 'sm'; | ||
| full?: boolean; | ||
| as?: ElementType; | ||
| } & ButtonHTMLAttributes<HTMLButtonElement> & { [key: string]: unknown }; | ||
|
|
||
| export default function Button({ | ||
| variant = 'primary', | ||
| size = 'lg', | ||
| full = false, | ||
| as: Component = 'button', | ||
| children, | ||
| ...props | ||
| }: ButtonProps) { | ||
| /* 1) 사이즈 */ | ||
| const sizeClass = | ||
| size === 'lg' | ||
| ? 'h-12 px-4 text-base sm:h-14 sm:px-6 sm:text-lg' | ||
| : size === 'md' | ||
| ? 'h-10 px-4 text-sm sm:h-11 sm:px-5 sm:text-base' | ||
| : 'h-8 px-3 text-sm sm:h-9 sm:px-4 sm:text-base'; | ||
|
|
||
| /* 2) variant에 따른 색상/테두리 */ | ||
| let variantClass = ''; | ||
| if (variant === 'primary') { | ||
| variantClass = 'bg-[#EA3C12] text-white hover:bg-[#d63810]'; | ||
| } else if (variant === 'secondary') { | ||
| variantClass = 'bg-white text-[#EA3C12] border border-[#EA3C12] hover:bg-[#fff5f2]'; | ||
| } else if (variant === 'approve') { | ||
| variantClass = | ||
| 'bg-white text-[#0080FF] border border-[#0080FF] hover:bg-[#0080FF] hover:text-white'; | ||
| } else if (variant === 'reject') { | ||
| variantClass = | ||
| 'bg-white text-[#EA3C12] border border-[#EA3C12] hover:bg-[#EA3C12] hover:text-white'; | ||
| } else if (variant === 'disabled') { | ||
| variantClass = 'bg-[#A9A7AE] text-white cursor-not-allowed'; | ||
|
||
| } | ||
|
|
||
| /* 3) 공통 */ | ||
| const baseClass = 'inline-flex items-center justify-center rounded-lg font-medium transition'; | ||
|
||
|
|
||
| return ( | ||
| <Component | ||
| className={`${baseClass} ${variantClass} ${sizeClass} ${full ? 'w-full' : ''}`} | ||
| {...(Component === 'button' | ||
| ? { disabled: variant === 'disabled' || props.disabled } | ||
| : { 'aria-disabled': variant === 'disabled' || props.disabled })} | ||
| {...props} // EX) type="submit" onClick={handleClick} aria-label="로그인 버튼" | ||
| > | ||
| {children} | ||
| </Component> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
기본으로 설치된 스토리북 패키지가 nextjs인데 react 여서 아마 lint 에서 오류가 난것 같습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네 맞아요 ㅜ 빨간줄로 안떠서 확인을 차마 못했네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아마 린트에서 패키지 다른거 오류잡는거 off 해놓아서 그런것 같습니다 ~!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞습니다 제가 .eslintrc.js 에서 'storybook/no-renderer-packages': 'off', 이거 설정 해놨었습니다..