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

[FEAT] ButtonBar 컴포넌트 퍼블리싱 #79

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
30 changes: 30 additions & 0 deletions src/assets/svgs/icn_flower_gray.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions src/assets/svgs/icn_flower_pink.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/svgs/icn_reset.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/svgs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import IcnCloseLargeGray from './icn_close_large_gray.svg';
import IcnCloseSmallGray from './icn_close_small_gray.svg';
import IcnDivder from './icn_divider.svg';
import IcnFilter from './icn_filter.svg';
import IcnFlowerGray from './icn_flower_gray.svg';
import IcnFlowerPink from './icn_flower_pink.svg';
import IcnHome from './icn_home.svg';
import IcnInsta from './icn_insta.svg';
import IcnLargeHeartPink from './icn_large_heart_pink.svg';
Expand Down Expand Up @@ -53,6 +55,8 @@ const Icon = {
IcnWish,
IcnX,
IcnBackBlackLeft,
IcnFlowerPink,
IcnFlowerGray,
IcnDivder,
};

Expand Down
40 changes: 40 additions & 0 deletions src/components/common/button/buttonBar/ButtonBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import buttonBarContainer from '@components/common/button/buttonBar/buttonBar.css';
import FlowerBtn from '@components/common/button/flowerBtn/FlowerBtn';
import PageBottomBtn from '@components/common/button/pageBottom/PageBottomBtn';
import TextBtn from '@components/common/button/textBtn/TextBtn';
import { useState } from 'react';

interface ButtonBarProps {
type: 'reset' | 'wish';
label: string;
}

const ButtonBar = ({ type, label }: ButtonBarProps) => {
const [isActive, setIsActive] = useState(false);

const onClickLefthBtn = () => {
setIsActive((prev) => !prev);
};

const renderLeftButton = () =>
type === 'wish' ? (
<FlowerBtn label="찜하기" isActive={isActive} isLeftIcn onClick={onClickLefthBtn} />
) : (
<TextBtn
text="초기화"
onClick={onClickLefthBtn}
leftIcon="IcnReset"
size="medium"
clicked={isActive}
/>
);

return (
<div className={buttonBarContainer}>
{renderLeftButton()}
<PageBottomBtn btnText={label} size="small" onClick={() => {}} />
</div>
);
};

export default ButtonBar;
15 changes: 15 additions & 0 deletions src/components/common/button/buttonBar/buttonBar.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { style } from '@vanilla-extract/css';

const buttonBarContainer = style({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '37.5rem',
height: '7.2rem',
padding: '1rem 2rem',
boxSizing: 'border-box',

boxShadow: `0px -4px 16px 0px rgba(0, 0, 0, 0.05)`,
});

export default buttonBarContainer;
29 changes: 29 additions & 0 deletions src/components/common/button/flowerBtn/FlowerBtn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import FlowerIcon from '@components/common/icon/FlowerIcon';

import * as styles from './flowerBtn.css';

interface FlowerBtnProps {
isRightIcn?: boolean;
isLeftIcn?: boolean;
label: string;
isActive: boolean;
onClick: () => void;
}

const FlowerBtn = ({
isRightIcn = false,
isLeftIcn = false,
label,
isActive,
onClick,
}: FlowerBtnProps) => {
return (
<button className={styles.FlowerBtnStyle} onClick={onClick}>
{isLeftIcn && <FlowerIcon isActive={isActive} />}
<p className={styles.textStyle({ active: isActive ? true : false })}>{label}</p>
{isRightIcn && <FlowerIcon isActive={isActive} />}
</button>
);
};

export default FlowerBtn;
30 changes: 30 additions & 0 deletions src/components/common/button/flowerBtn/flowerBtn.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import theme from '@styles/theme.css';
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

export const FlowerBtnStyle = style({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '4.4rem',
gap: '0.3rem',

padding: '0 0.3rem',
boxSizing: 'border-box',
});

export const textStyle = recipe({
base: {
...theme.FONTS.b8M15,
color: theme.COLORS.gray7,
},

variants: {
active: {
false: {},
true: {
color: theme.COLORS.gray10,
},
},
},
});
4 changes: 2 additions & 2 deletions src/components/common/button/pageBottom/PageBottomBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import bottomBtnStyle from './pageBottomBtn.css';
interface PageBottomBtnProps {
btnText: string;
size: 'small' | 'large';
isDisabled: boolean;
isDisabled?: boolean;
onClick: () => void;
}

const PageBottomBtn = ({ btnText, size, isDisabled, onClick }: PageBottomBtnProps) => {
const PageBottomBtn = ({ btnText, size, isDisabled = false, onClick }: PageBottomBtnProps) => {
const className = bottomBtnStyle({
size,
isDisabled,
Expand Down
9 changes: 4 additions & 5 deletions src/components/common/button/textBtn/TextBtn.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Icon from '@assets/svgs';
import React from 'react';

import textBtnStyle, { iconStyle } from './textBtn.css';
import * as styles from './textBtn.css';

interface TextBtnProps {
clicked?: boolean;
Expand All @@ -24,10 +23,10 @@ const TextBtn = ({
const RightIconComponent = rightIcon ? Icon[rightIcon] : null;

return (
<button className={textBtnStyle({ clicked, size })} onClick={onClick}>
{LeftIconComponent && <LeftIconComponent className={iconStyle} />}
<button className={styles.textBtnStyle({ clicked, size })} onClick={onClick}>
{LeftIconComponent && <LeftIconComponent className={styles.iconStyle({ size })} />}
<span>{text}</span>
{RightIconComponent && <RightIconComponent className={iconStyle} />}
{RightIconComponent && <RightIconComponent className={styles.iconStyle({ size })} />}
</button>
);
};
Expand Down
57 changes: 43 additions & 14 deletions src/components/common/button/textBtn/textBtn.css.ts
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 파일에 초기화 버튼 클릭시에 색이 어두워지도록 적용하면 좋을 것 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

reset버튼일 경우에는 &:active 해당 효과 추가해서 클릭할때마다 텍스트 색상이 변경될 수 있도록 수정하였습니다! 해당 부분에 대해서 생각하지 못했었는데 좋은 리뷰 감사합니다

Original file line number Diff line number Diff line change
@@ -1,35 +1,64 @@
import theme from '@styles/theme.css';
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

export const iconStyle = style({
width: '1.3rem',
height: '1.3rem',
color: 'currentColor',
export const iconStyle = recipe({
base: {
color: 'currentColor',
},
variants: {
size: {
small: {
width: '1.3rem',
height: '1.3rem',
},
medium: {
width: '2rem',
height: '2rem',
},
},
},
});

const textBtnStyle = recipe({
export const textBtnStyle = recipe({
base: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
gap: '0.3rem',
...theme.FONTS.c6R13,
color: theme.COLORS.gray5,
},

variants: {
clicked: {
false: {},
true: {
color: theme.COLORS.gray9,
},
true: {},
},

size: {
small: { height: '3.3rem' },
medium: { height: '4.4rem' },
small: { height: '3.3rem', color: theme.COLORS.gray5, ...theme.FONTS.c6R13 },
medium: {
height: '4.4rem',
color: theme.COLORS.gray7,
padding: '0 0.8rem',
...theme.FONTS.b8M15,
selectors: {
'&:active': {
color: theme.COLORS.gray10,
},
},
},
},
},
});

export default textBtnStyle;
compoundVariants: [
{
variants: {
clicked: true,
size: 'small',
},
style: {
color: theme.COLORS.gray9,
},
},
],
});
11 changes: 11 additions & 0 deletions src/components/common/icon/FlowerIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Icon from '@assets/svgs';

interface FlowerIconProps {
isActive?: boolean;
}

const FlowerIcon = ({ isActive = false }: FlowerIconProps) => {
return <>{isActive ? <Icon.IcnFlowerPink /> : <Icon.IcnFlowerGray />}</>;
};

export default FlowerIcon;
27 changes: 27 additions & 0 deletions src/stories/ButtonBar.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import ButtonBar from '@components/common/button/buttonBar/ButtonBar';
import type { Meta, StoryObj } from '@storybook/react';

const meta = {
title: 'Common/Button/ButtonBar',
component: ButtonBar,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
type: {
control: { type: 'select' },
options: ['reset', 'wish'],
},
},
args: {
type: 'wish',
label: '예약하기',
},
} satisfies Meta<typeof ButtonBar>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {};
38 changes: 38 additions & 0 deletions src/stories/FlowerBtn.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import FlowerBtn from '@components/common/button/flowerBtn/FlowerBtn';
import type { Meta, StoryObj } from '@storybook/react';

const meta = {
title: 'Common/Button/FlowerBtn',
component: FlowerBtn,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
label: {
control: { type: 'text' },
},
isRightIcn: {
control: { type: 'boolean' },
},
isLeftIcn: {
control: { type: 'boolean' },
},
isActive: {
control: { type: 'boolean' },
},
},
args: {
label: '찜하기',
isRightIcn: true,
isLeftIcn: true,
isActive: false,
onClick: () => {},
},
} satisfies Meta<typeof FlowerBtn>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {};
Loading