Skip to content

Commit

Permalink
✨ feat: IconButton 컴포넌트 구현 (#29)
Browse files Browse the repository at this point in the history
* ✨ feat: IconButton 컴포넌트 작성

* ✨ feat: Icon Button 스토리북 작성

* ✨ feat: IconButton 스토리북에 새로운 스토리 추가 및 기존 스토리 수정

* 🔨 refactor: ButtonVariant 타입의 'Arrow' 를 'Carousel' 로 변경
  • Loading branch information
easyhyun00 authored Jan 26, 2024
1 parent b27c15b commit c338732
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/assets/icons/heart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/icons/leftArrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/icons/person.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/assets/icons/rightArrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 51 additions & 0 deletions src/components/IconButton/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { Meta, StoryObj } from '@storybook/react';
import { css } from '@emotion/react';
import Person from '@/assets/icons/person.svg?react';
import RightArrow from '@/assets/icons/rightArrow.svg?react';
import LeftArrow from '@/assets/icons/leftArrow.svg?react';
import Heart from '@/assets/icons/heart.svg?react';
import IconButton from './';

const meta = {
title: 'Components/IconButton',
component: IconButton,
tags: ['autodocs'],
} satisfies Meta<typeof IconButton>;

export default meta;

type Story = StoryObj<typeof meta>;

const styles = {
iconContainer: css`
display: flex;
gap: 20px;
`,
};

export const Primary: Story = {
args: {
variant: 'header',
children: <Person />,
},
};

export const 아이콘_버튼: StoryObj = {
storyName: '아이콘 버튼(상단, 하단, 오른쪽, 왼쪽 화살표)',
render: () => (
<div css={styles.iconContainer}>
<IconButton>
<Person />
</IconButton>
<IconButton variant="bottom">
<Heart />
</IconButton>
<IconButton variant="leftCarousel">
<LeftArrow />
</IconButton>
<IconButton variant="rightCarousel">
<RightArrow />
</IconButton>
</div>
),
};
23 changes: 23 additions & 0 deletions src/components/IconButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import style, { ButtonVariant } from './styles';

interface IconButtonProps extends React.ComponentProps<'button'> {
/** 아이콘의 색상 입니다. */
variant?: ButtonVariant;
/** IconButton 컴포넌트 안에 들어갈 아이콘입니다. */
children: React.ReactNode;
}

const IconButton = ({
variant = 'header',
children,
...props
}: IconButtonProps) => {
return (
<button {...props} css={style.button(variant)}>
{children}
</button>
);
};

export default IconButton;
68 changes: 68 additions & 0 deletions src/components/IconButton/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { css } from '@emotion/react';

export type ButtonVariant =
| 'header'
| 'leftCarousel'
| 'rightCarousel'
| 'bottom';

const style = {
button: (variant: ButtonVariant) => css`
display: flex;
padding: 8px;
border: ${variants[variant].border};
border-radius: 100px;
background: ${variants[variant].background};
cursor: pointer;
transition: all 0.2s ease;
backdrop-filter: blur(2px);
&:hover {
background: ${variants[variant].hoverBackground};
}
&:active {
background: ${variants[variant].activeBackground};
box-shadow: 0 2px 10px rgb(0 0 0 / 0.2);
transform: scale(0.95);
}
`,
};

const variants = {
header: {
border: '1px solid rgba(255, 255, 255, 0.1)',
background: 'rgba(255, 255, 255, 0.3)',
hoverBackground: 'rgba(255, 255, 255, 0.4)',
activeBackground: 'rgba(255, 255, 255, 0.5)',
},
leftCarousel: {
border: '1px solid rgba(255, 255, 255, 0.30)',
background:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.70) 0%, rgba(255, 255, 255, 0.50) 100%)',
hoverBackground:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.80) 0%, rgba(255, 255, 255, 0.60) 100%)',
activeBackground:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.90) 0%, rgba(255, 255, 255, 0.70) 100%)',
},
rightCarousel: {
border: '1px solid rgba(255, 255, 255, 0.30)',
background:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.70) 0%, rgba(255, 255, 255, 0.51) 38.5%, rgba(255, 255, 255, 0.20) 100%)',
hoverBackground:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.80) 0%, rgba(255, 255, 255, 0.61) 38.5%, rgba(255, 255, 255, 0.30) 100%)',
activeBackground:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.90) 0%, rgba(255, 255, 255, 0.71) 38.5%, rgba(255, 255, 255, 0.40) 100%)',
},
bottom: {
border: '1px solid rgba(255, 255, 255, 0.3)',
background:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.70) 0%, rgba(255, 255, 255, 0.28) 100%)',
hoverBackground:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.80) 0%, rgba(255, 255, 255, 0.38) 100%)',
activeBackground:
'radial-gradient(491.85% 132.88% at 0% 12.5%, rgba(255, 255, 255, 0.90) 0%, rgba(255, 255, 255, 0.48) 100%)',
},
};

export default style;

0 comments on commit c338732

Please sign in to comment.