Skip to content

Commit

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

* ✨ feat: Chip 스토리북 작성

* 📝 style: color 상수 적용 및 rem 단위로 변경

* 💄 design: bottle-tag 스타일 변경

* ✨ feat: VariantType에 bottle-tag-bubble 추가

* 📝 style: storybook 이름 변경 및 rem 단위로 변경

* 📝 style: ChipProps interface 로 변경 및 button 타입 설정 및 SerializedStyles 제거
  • Loading branch information
easyhyun00 authored Jan 30, 2024
1 parent 3268968 commit 059b758
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 0 deletions.
148 changes: 148 additions & 0 deletions src/components/Chip/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { css } from '@emotion/react';
import { HourGlass } from '@/assets/icons';
import Chip from '.';

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

export default meta;

type Story = StoryObj<typeof meta>;

export const Primary: Story = {
args: {
children: '안녕하세요',
},
};

const styles = {
container: css`
width: 100%;
max-width: 37.5rem;
background-color: skyblue;
`,
chipContainer: css`
display: flex;
flex-wrap: wrap;
gap: 0.4375rem;
justify-content: center;
`,
chip: css`
margin-block: 0.4375rem;
`,
formContainer: css`
display: flex;
gap: 0.5rem;
`,
formChip: css`
flex: 1;
`,
};

export const 고민_종류_칩: StoryObj = {
render: () => {
const ChipComponent = () => {
type VariantType = 'primary' | 'primary-selected' | 'primary-disabled';
const [selectedChips, setSelectedChips] = useState<string[]>([]);

const handleChipClick = (chip: string) => {
setSelectedChips((currentChips) => {
if (currentChips.includes(chip)) {
return currentChips.filter((c) => c !== chip);
} else if (currentChips.length < 3) {
return [...currentChips, chip];
}
return currentChips;
});
};

const getVariant = (label: string): VariantType => {
if (selectedChips.includes(label)) {
return 'primary-selected';
} else if (selectedChips.length >= 3) {
return 'primary-disabled';
}
return 'primary';
};

const chipLabels = [
'일·직장',
'취업·진로',
'인간관계',
'이별·상실',
'연애',
'학업',
'가족',
'기타',
];

return (
<div css={styles.container}>
<p>최대 3개까지만 선택 가능합니다.</p>
<div css={styles.chipContainer}>
{chipLabels.map((label) => (
<Chip
key={label}
variant={getVariant(label)}
onClick={() => handleChipClick(label)}
css={styles.chip}
>
{label}
</Chip>
))}
</div>
</div>
);
};

return <ChipComponent />;
},
};

export const 물병_칩: StoryObj = {
render: () => (
<div css={styles.chipContainer}>
<Chip variant="bottle-tag">
<HourGlass color="#828282" width={14} height={14} />
<p>26h</p>
</Chip>
<Chip variant="bottle-tag">NEW</Chip>
<Chip variant="bottle-tag-bubble">답장이 도착했어요</Chip>
</div>
),
};

export const 필터링_칩: StoryObj = {
render: () => (
<div css={styles.chipContainer}>
<Chip variant="filter">17~</Chip>
<Chip variant="filter">모두에게</Chip>
<Chip variant="filter">진로</Chip>
</div>
),
};

export const 폼_칩: StoryObj = {
render: () => (
<div css={{ backgroundColor: 'white', padding: '0.625rem' }}>
<div css={styles.formContainer}>
<Chip variant="form-selected" css={styles.formChip}>
모두에게 보내기
</Chip>
<Chip variant="form" css={styles.formChip}>
나와 같은 성별에게 보내기
</Chip>
</div>
<div>
<Chip variant="form" css={styles.formChip}>
일·직장
</Chip>
</div>
</div>
),
};
25 changes: 25 additions & 0 deletions src/components/Chip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import style, { VariantType } from './styles';

interface ChipProps {
/** Chip의 내용입니다. */
variant?: VariantType;
/** Chip의 테마입니다. */
children: React.ReactNode;
/** Chip의 클릭 이벤트 입니다. */
onClick?: () => void;
}

const Chip = ({ variant = 'primary', children, ...props }: ChipProps) => {
return (
<button
{...props}
type="button"
disabled={variant === 'primary-disabled'}
css={style.chip(variant)}
>
{children}
</button>
);
};

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

export type VariantType =
| 'primary'
| 'primary-selected'
| 'primary-disabled'
| 'bottle-tag'
| 'bottle-tag-bubble'
| 'filter'
| 'form'
| 'form-selected';

const styles = {
chip: (variant: VariantType) => css`
cursor: ${variant === 'primary-disabled' ? 'not-allowed' : 'pointer'};
${variants[variant]}
`,
};

const baseChipStyle = css`
display: flex;
justify-content: center;
align-items: center;
border-radius: 6.25rem;
font-style: normal;
text-align: center;
backdrop-filter: blur(0.4688rem);
`;

const baseTextStyles = css`
font-weight: 500;
font-size: 1rem;
line-height: 160%;
`;

const formChipStyles = css`
${baseChipStyle};
padding: 0.75rem 1rem;
font-weight: 700;
line-height: 1rem;
font-size: 0.75rem;
color: ${COLORS.gray1};
`;

const bottleTagStyles = css`
${baseChipStyle};
background: white;
font-weight: 500;
gap: 0.25rem;
padding: 0.25rem 0.75rem;
font-size: 0.875rem;
line-height: 1rem;
border: 1px solid rgb(255 255 255 / 0.3);
`;

const variants = {
primary: css`
${baseChipStyle};
background: radial-gradient(
491.85% 132.88% at 0% 12.5%,
rgb(255 255 255 / 0.7) 0%,
rgb(255 255 255 / 0.28) 100%
);
padding: 0.25rem 1rem;
border: 1px solid rgb(255 255 255 / 0.3);
color: var(--kakao-logo, #000);
${baseTextStyles};
`,
'primary-selected': css`
${baseChipStyle};
${baseTextStyles};
padding: 0.25rem 1rem;
border: 1px solid rgb(255 255 255 / 0.3);
color: var(--kakao-logo, #000);
`,
'primary-disabled': css`
${baseChipStyle};
${baseTextStyles};
padding: 0.25rem 1rem;
border: 1px solid rgb(255 255 255 / 0.3);
color: ${COLORS.gray4};
`,
'bottle-tag': css`
${bottleTagStyles};
`,
'bottle-tag-bubble': css`
${bottleTagStyles}
&::after {
content: '';
position: absolute;
top: 1.5625rem;
right: 1.375rem;
border-width: 0.5rem;
border-style: solid;
border-color: white transparent transparent;
}
`,
filter: css`
${baseChipStyle};
padding: 0.25rem 0.5rem;
font-weight: 500;
gap: 0.625rem;
border: 1px solid ${COLORS.gray4};
background: ${COLORS.gray5};
color: ${COLORS.gray1};
line-height: 1rem;
font-size: 0.875rem;
`,
form: css`
${formChipStyles};
background: white;
border: 1px solid ${COLORS.gray5};
`,
'form-selected': css`
${formChipStyles};
border: 1px solid #2f80ed;
background: rgb(47 128 237 / 0.2);
`,
};

export default styles;

0 comments on commit 059b758

Please sign in to comment.