From 7361d66d365baba5bf5bf64ea8f2e982099c3c06 Mon Sep 17 00:00:00 2001 From: leedohyun Date: Sat, 29 Jun 2024 11:32:21 +0900 Subject: [PATCH] =?UTF-8?q?feat=20:=20Grid,=20Container=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.old.md | 4 +-- src/stories/Container.css | 5 +++ src/stories/Container.stories.tsx | 41 +++++++++++++++++++++ src/stories/Container.tsx | 30 ++++++++++++++++ src/stories/Grid.css | 5 +++ src/stories/Grid.stories.tsx | 60 +++++++++++++++++++++++++++++++ src/stories/Grid.tsx | 33 +++++++++++++++++ 7 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 src/stories/Container.css create mode 100644 src/stories/Container.stories.tsx create mode 100644 src/stories/Container.tsx create mode 100644 src/stories/Grid.css create mode 100644 src/stories/Grid.stories.tsx create mode 100644 src/stories/Grid.tsx diff --git a/README.old.md b/README.old.md index 3923295c8..3e3f86f97 100644 --- a/README.old.md +++ b/README.old.md @@ -32,8 +32,8 @@ FE 카카오 선물하기 1주차 과제: React 기초 - [o] radius props에 따라 모서리 둥글게 적용 - [o] image Element 기본 속성 모두 사용 - GoodsItem 컴포넌트 구현 - - [] default 형태와 ranking 형태 컴포넌트 구현 - - [] Ranking 컴포넌트 랭킹 지정 + - [o] default 형태와 ranking 형태 컴포넌트 구현 + - [o] Ranking 컴포넌트 랭킹 지정 - Grid, Container 컴포넌트 구현 ## 요구 사항 diff --git a/src/stories/Container.css b/src/stories/Container.css new file mode 100644 index 000000000..ca62e57dd --- /dev/null +++ b/src/stories/Container.css @@ -0,0 +1,5 @@ +.container { + margin: 0 auto; + padding: 1rem; + } + \ No newline at end of file diff --git a/src/stories/Container.stories.tsx b/src/stories/Container.stories.tsx new file mode 100644 index 000000000..b2076af05 --- /dev/null +++ b/src/stories/Container.stories.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { Meta, StoryFn } from '@storybook/react'; +import Container from './Container'; + +export default { + title: 'Layout/Container', + component: Container, + argTypes: { + maxWidth: { control: 'text' }, + children: { control: 'text' }, + flexDirection: { control: 'radio', options: ['row', 'column'] }, + justifyContent: { + control: 'radio', + options: ['center', 'flex-start', 'flex-end', 'space-between', 'space-around'], + }, + alignItems: { + control: 'radio', + options: ['center', 'flex-start', 'flex-end', 'baseline', 'stretch'], + }, + }, +} as Meta; + +const Template: StoryFn = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + maxWidth: '100%', + children: 'Hello, world!', + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', +}; + +export const FullScreen = Template.bind({}); +FullScreen.args = { + maxWidth: '100%', + children: 'Hello, world!', + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', +}; diff --git a/src/stories/Container.tsx b/src/stories/Container.tsx new file mode 100644 index 000000000..fe2afa596 --- /dev/null +++ b/src/stories/Container.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import './Container.css'; + +interface ContainerProps { + maxWidth?: string; + children: React.ReactNode; + flexDirection?: 'row' | 'column'; + justifyContent?: 'center' | 'flex-start' | 'flex-end' | 'space-between' | 'space-around'; + alignItems?: 'center' | 'flex-start' | 'flex-end' | 'baseline' | 'stretch'; +} + +const Container: React.FC = ({ + maxWidth, + children, + flexDirection = 'row', + justifyContent = 'flex-start', + alignItems = 'stretch', +}) => { + const style = { + maxWidth, + display: 'flex', + flexDirection, + justifyContent, + alignItems, + }; + + return
{children}
; +}; + +export default Container; diff --git a/src/stories/Grid.css b/src/stories/Grid.css new file mode 100644 index 000000000..10af1e64b --- /dev/null +++ b/src/stories/Grid.css @@ -0,0 +1,5 @@ +.grid { + display: grid; + gap: var(--gap); + } + \ No newline at end of file diff --git a/src/stories/Grid.stories.tsx b/src/stories/Grid.stories.tsx new file mode 100644 index 000000000..e7194e6c7 --- /dev/null +++ b/src/stories/Grid.stories.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { Meta, StoryFn } from '@storybook/react'; +import Grid from './Grid'; + +export default { + title: 'Layout/Grid', + component: Grid, + argTypes: { + gap: { control: 'text' }, + columns: { + control: 'object', + defaultValue: { initial: 1, sm: 2, md: 3, lg: 4 }, + }, + children: { control: 'text' }, + }, +} as Meta; + +const Template: StoryFn = (args) => ; + +export const NumberColumns = Template.bind({}); +NumberColumns.args = { + columns: 3, + gap: '10px', + children: ( + <> +
1
+
2
+
3
+
4
+
5
+
6
+ + ), +}; + +export const ResponsiveColumns = Template.bind({}); +ResponsiveColumns.args = { + columns: { initial: 1, sm: 2, md: 3, lg: 4 }, + gap: '10px', + children: ( + <> +
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+ + ), +}; diff --git a/src/stories/Grid.tsx b/src/stories/Grid.tsx new file mode 100644 index 000000000..fe763bfba --- /dev/null +++ b/src/stories/Grid.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import './Grid.css'; + +interface GridProps { + columns: number | { initial: number; sm?: number; md?: number; lg?: number }; + gap?: string; + children: React.ReactNode; +} + +const Grid: React.FC = ({ columns, gap = '0', children }) => { + const getGridTemplateColumns = () => { + if (typeof columns === 'number') { + return `repeat(${columns}, 1fr)`; + } else { + return ` + repeat(${columns.initial}, 1fr); + @media (min-width: 600px) { grid-template-columns: repeat(${columns.sm || columns.initial}, 1fr); } + @media (min-width: 768px) { grid-template-columns: repeat(${columns.md || columns.initial}, 1fr); } + @media (min-width: 1024px) { grid-template-columns: repeat(${columns.lg || columns.initial}, 1fr); } + `; + } + }; + + const style = { + display: 'grid', + gap, + gridTemplateColumns: getGridTemplateColumns(), + }; + + return
{children}
; +}; + +export default Grid;