Skip to content

Commit

Permalink
Feat: Button, Input, Block, ProgressBar 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
myoungjinGo-FE committed Nov 16, 2024
1 parent a6c2824 commit b53053f
Show file tree
Hide file tree
Showing 11 changed files with 5,914 additions and 2,900 deletions.
Binary file added .yarn/install-state.gz
Binary file not shown.
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
138 changes: 138 additions & 0 deletions src/stories/components/CustomButton/CustomButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import type { Meta, StoryObj } from '@storybook/react';
import { CustomButton } from './CustomButton';

const meta = {
title: 'Components/CustomButton',
component: CustomButton,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
children: {
control: 'text',
description: '버튼 내부 텍스트',
},
size: {
control: 'select',
options: ['small', 'medium', 'large'],
description: '버튼 크기',
},
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline'],
description: '버튼 스타일',
},
disabled: {
control: 'boolean',
description: '비활성화 여부',
},
fullWidth: {
control: 'boolean',
description: '너비 100% 설정',
defaultValue: false,
},
},
} satisfies Meta<typeof CustomButton>;

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

export const Primary: Story = {
args: {
children: '시작하기',
variant: 'primary',
size: 'medium',
},
};

export const Secondary: Story = {
args: {
children: '취소',
variant: 'secondary',
size: 'medium',
},
};

export const Outline: Story = {
args: {
children: '더보기',
variant: 'outline',
size: 'medium',
},
};

export const Small: Story = {
args: {
children: '확인',
size: 'small',
variant: 'primary',
},
};

export const Large: Story = {
args: {
children: '계정 만들기',
size: 'large',
variant: 'primary',
},
};

export const Disabled: Story = {
args: {
children: '비활성화',
disabled: true,
variant: 'primary',
},
};

export const FullWidth: Story = {
args: {
children: '전체 너비 버튼',
fullWidth: true,
variant: 'primary',
},
parameters: {
layout: 'padded',
},
};

// Container를 활용한 FullWidth 버튼 예시
export const FullWidthContainer: Story = {
decorators: [
(Story) => (
<div style={{ width: '100%', maxWidth: '400px', padding: '16px' }}>
<Story />
</div>
),
],
args: {
children: '컨테이너 안의 전체 너비 버튼',
fullWidth: true,
variant: 'primary',
},
};

// 버튼 그룹 예시
export const ButtonGroup: Story = {
render: () => (
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<CustomButton variant="primary" size="medium">확인</CustomButton>
<CustomButton variant="secondary" size="medium">취소</CustomButton>
<CustomButton variant="outline" size="medium">더보기</CustomButton>
</div>
),
};

// 다양한 너비의 버튼 예시
export const VariousWidths: Story = {
render: () => (
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px', width: '100%', maxWidth: '600px' }}>
<CustomButton variant="primary">기본 버튼</CustomButton>
<CustomButton variant="primary" fullWidth>전체 너비 버튼</CustomButton>
<div style={{ width: '50%' }}>
<CustomButton variant="primary" fullWidth>50% 너비 버튼</CustomButton>
</div>
</div>
),
};
163 changes: 163 additions & 0 deletions src/stories/components/CustomButton/CustomButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// CustomButton.tsx
import React from 'react';
import styled, { css, keyframes } from 'styled-components';

interface CustomButtonProps {
/**
* 버튼 내부 텍스트
*/
children: React.ReactNode;
/**
* 버튼 크기 variant
*/
size?: 'small' | 'medium' | 'large';
/**
* 버튼 스타일 variant
*/
variant?: 'primary' | 'secondary' | 'outline';
/**
* 비활성화 여부
*/
disabled?: boolean;
/**
* 클릭 핸들러
*/
onClick?: () => void;
/**
* 너비를 100%로 설정
*/
fullWidth?: boolean;
}

const pressAnimation = keyframes`
0% {
transform: scale(1);
}
50% {
transform: scale(0.97);
}
100% {
transform: scale(1);
}
`;

const Button = styled.button<{
size: string;
variant: string;
$fullWidth: boolean;
}>`
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 20px;
font-weight: 500;
transition: all 0.2s ease-in-out;
cursor: pointer;
width: ${props => props.$fullWidth ? '100%' : 'auto'};
// 크기 설정
${props => {
switch (props.size) {
case 'small':
return css`
padding: 8px 16px;
font-size: 14px;
height: 32px;
`;
case 'large':
return css`
padding: 16px 32px;
font-size: 18px;
height: 48px;
`;
default: // medium
return css`
padding: 12px 24px;
font-size: 16px;
height: 40px;
`;
}
}}
// 스타일 variant 설정
${props => {
switch (props.variant) {
case 'secondary':
return css`
background-color: #EEF2FF;
color: #4F46E5;
border: none;
&:hover:not(:disabled) {
background-color: #E0E7FF;
}
&:active:not(:disabled) {
animation: ${pressAnimation} 0.2s ease-in-out;
}
`;
case 'outline':
return css`
background-color: transparent;
color: #4F46E5;
border: 2px solid #4F46E5;
&:hover:not(:disabled) {
background-color: #EEF2FF;
}
&:active:not(:disabled) {
animation: ${pressAnimation} 0.2s ease-in-out;
}
`;
default: // primary
return css`
background-color: #4F46E5;
color: white;
border: none;
box-shadow: 0 2px 4px rgba(79, 70, 229, 0.1);
&:hover:not(:disabled) {
background-color: #4338CA;
transform: translateY(-1px);
box-shadow: 0 4px 6px rgba(79, 70, 229, 0.2);
}
&:active:not(:disabled) {
animation: ${pressAnimation} 0.2s ease-in-out;
}
`;
}
}}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
&:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3);
}
`;

export const CustomButton: React.FC<CustomButtonProps> = ({
children,
size = 'medium',
variant = 'primary',
disabled = false,
onClick,
fullWidth = false,
}) => {
return (
<Button
size={size}
variant={variant}
disabled={disabled}
onClick={onClick}
$fullWidth={fullWidth}
>
{children}
</Button>
);
};
Loading

0 comments on commit b53053f

Please sign in to comment.