Skip to content
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

design: Chips 및 상단 배너 컴포넌트 UI 구현 #120

Merged
merged 9 commits into from
Jun 20, 2024
29 changes: 29 additions & 0 deletions src/components/common/Chips/Chips.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { css } from '@emotion/react';
import typo from '@/styles/typo';
import color from '@/styles/color';
import type { ChipsProps } from './Chips';

export const getSizeStyling = (size: Required<ChipsProps>['size']) => {
const style = {
large: css(typo.Body.SemiBold_5, {
padding: '6px 12px',
borderRadius: '8px',
}),
small: css(typo.Body.Medium_5, {
padding: '2px 8px',
borderRadius: '6px',
}),
};

return style[size];
};

export const chipsStyling = css({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: 'fit-content',
backgroundColor: color.Primary[400],
color: color.Neutral[50],
cursor: 'pointer',
});
15 changes: 15 additions & 0 deletions src/components/common/Chips/Chips.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint-disable react/react-in-jsx-scope */
import { ReactNode } from 'react';
import type { Size } from '@/types/temp';
import { chipsStyling, getSizeStyling } from './Chips.style';

export interface ChipsProps {
size?: Extract<Size, 'small' | 'large'>;
children?: ReactNode;
}

const Chips = ({ size = 'large', children }: ChipsProps) => (
<div css={[chipsStyling, getSizeStyling(size)]}>{children}</div>
);

export default Chips;
45 changes: 45 additions & 0 deletions src/components/pattern/TopBanner/TopBanner.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* eslint-disable import/no-cycle */
import { css } from '@emotion/react';
import typo from '@/styles/typo';
import color from '@/styles/color';
import { loadingStyle } from '@/styles/keyframes';

export const loadingStyling = css`
animation: ${loadingStyle} 2s infinite;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로딩 애니메이션 추가 좋습니다 👍🏻

`;

export const hideInfo = css({
visibility: 'hidden',
});

export const bannerStyling = css({
display: 'flex',
flexDirection: 'column-reverse',
width: '100%',
minHeight: '297px',
padding: '30px',
borderRadius: '20px',
backgroundColor: color.Neutral[800],
cursor: 'pointer',
});

export const bannerWrapper = css({
display: 'flex',
flexDirection: 'column',
gap: '6px',
});

export const bannerInfoWrapper = css({
display: 'flex',
flexDirection: 'column',
gap: '10px',
});

export const bannerTitle = css(typo.Heading_2, {
color: color.Neutral[50],
});

export const bannerSummary = css(typo.Body.Medium_1, {
color: color.Neutral[400],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

숫자 프로퍼티를 대괄호 표기법으로 접근할 때는 color.Neutral[400] 처럼 숫자로만 작성하는 것으로 통일하는게 어떨지 의견 여쭙고 싶습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 전에 올려주신 부분인데 제가 실수했네요.. 꼼꼼히 체크했어야 했는데🥲
말씀해 주신 대로 숫자로 통일하여 다시 커밋 올리겠습니다 !

whiteSpace: 'pre-line',
});
32 changes: 32 additions & 0 deletions src/components/pattern/TopBanner/TopBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable react/react-in-jsx-scope */
import { ReactNode } from 'react';
import Chips from '@/components/common/Chips/Chips';
import {
bannerStyling,
bannerWrapper,
bannerInfoWrapper,
bannerSummary,
bannerTitle,
loadingStyling,
hideInfo,
} from './TopBanner.style';

export interface TopBannerProps {
title?: ReactNode;
summary?: ReactNode;
isLoading?: boolean;
}

const TopBanner = ({ title, summary, isLoading = false }: TopBannerProps) => (
<div css={[bannerStyling, isLoading && loadingStyling]}>
<div css={[bannerWrapper, isLoading && hideInfo]}>
<Chips size="large">오늘의 톡픽</Chips>
<div css={bannerInfoWrapper}>
<div css={bannerTitle}>{title}</div>
<div css={bannerSummary}>{summary}</div>
</div>
</div>
</div>
);

export default TopBanner;
2 changes: 1 addition & 1 deletion src/stories/common/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { storyContainer, storyInnerContainer } from '@/stories/story.styles';

const meta = {
title: 'Button',
title: 'commons/Button',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

옮겨주셔서 감사합니다!😀

component: Button,
parameters: {
layout: 'centered',
Expand Down
49 changes: 49 additions & 0 deletions src/stories/common/Chips.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import Chips from '@/components/common/Chips/Chips';
import type { Meta, StoryObj } from '@storybook/react';
import { storyContainer, storyInnerContainer } from '@/stories/story.styles';

const meta = {
title: 'commons/Chips',
component: Chips,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
size: {
options: ['small', 'large'],
control: { type: 'radio' },
},
children: { control: { type: 'text' } },
},
args: {
size: 'large',
children: '오늘의 밸런스톡',
},
} satisfies Meta<typeof Chips>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
size: 'large',
},
};

export const All: Story = {
render: (args) => (
<ul css={storyContainer}>
<li css={storyInnerContainer}>
<h3>Size</h3>
<Chips {...args} size="small">
Small
</Chips>
<Chips {...args} size="large">
Large
</Chips>
</li>
</ul>
),
};
56 changes: 56 additions & 0 deletions src/stories/pattern/TopBanner.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';
import TopBanner from '@/components/pattern/TopBanner/TopBanner';
import type { Meta, StoryObj } from '@storybook/react';
import { storyContainer, storyInnerContainer } from '@/stories/story.styles';

const exampleBanner = {
title: '깻잎 논쟁 당신의 선택은?',
summary:
'1. 저녁 식사 중 남자친구가 친구에게 깻잎을 떼어주자 나는 불편한 감정을 느꼈다. \n2. 집에 돌아와 남자친구에게 솔직하게 말했고, 그는 미안해하며 이해해 주었다. \n3. 친구들과 이 문제를 논의했지만 결론은 나지 않았고, 사람마다 다르게 받아들일 수 있음을 깨달았다.',
};

const meta = {
title: 'patterns/TopBanner',
component: TopBanner,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
title: { control: { type: 'text' } },
summary: { control: { type: 'text' } },
isLoading: { control: { type: 'boolean' } },
},
args: {
title: exampleBanner.title,
summary: exampleBanner.summary,
},
} satisfies Meta<typeof TopBanner>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
title: exampleBanner.title,
summary: exampleBanner.summary,
isLoading: false,
},
};

export const All: Story = {
render: (args) => (
<ul css={storyContainer}>
<li css={storyInnerContainer}>
<h3>Default</h3>
<TopBanner
title={exampleBanner.title}
summary={exampleBanner.summary}
isLoading={false}
/>
<h3>Loading</h3>
<TopBanner {...args} isLoading />
</li>
</ul>
),
};
13 changes: 13 additions & 0 deletions src/styles/keyframes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { keyframes } from '@emotion/react';
import color from './color';

export const pulsate = keyframes({
'0%': {
Expand All @@ -11,3 +12,15 @@ export const pulsate = keyframes({
transform: 'scale(1.1)',
},
});

export const loadingStyle = keyframes({
'0%': {
backgroundColor: color.Neutral[800],
},
'50%': {
backgroundColor: color.Neutral[700],
},
'100%': {
backgroundColor: color.Neutral[800],
},
});
Loading