-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
design: 모바일 Modal 관련 컴포넌트 구현 및 스토리북 작성
- Loading branch information
Showing
25 changed files
with
643 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { css } from '@emotion/react'; | ||
import color from '@/styles/color'; | ||
import type { ModalProps } from './Modal'; | ||
|
||
export const modalStyling = css({ | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
position: 'relative', | ||
width: '335px', | ||
backgroundColor: color.WT, | ||
borderRadius: '12px', | ||
boxShadow: '1px 2px 30px rgba(0, 0, 0, 0.15)', | ||
}); | ||
|
||
export const getModalSize = (action: Required<ModalProps>['action']) => { | ||
const style = { | ||
share: css({ | ||
paddingTop: '24px', | ||
paddingLeft: '20px', | ||
paddingRight: '20px', | ||
paddingBottom: '26px', | ||
}), | ||
tag: css({ | ||
paddingTop: '24px', | ||
paddingLeft: '20px', | ||
paddingRight: '20px', | ||
paddingBottom: '30px', | ||
}), | ||
tempGame: css({ | ||
paddingTop: '24px', | ||
paddingLeft: '20px', | ||
paddingRight: '20px', | ||
paddingBottom: '24px', | ||
}), | ||
}; | ||
|
||
return style[action as keyof typeof style]; | ||
}; | ||
|
||
export const modalCloseStyling = css({ | ||
position: 'absolute', | ||
top: '24px', | ||
right: '20px', | ||
cursor: 'pointer', | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* eslint-disable react-hooks/exhaustive-deps */ | ||
import React, { useRef, ReactNode } from 'react'; | ||
import { MobileModalClose } from '@/assets'; | ||
import useOutsideClick from '@/hooks/common/useOutsideClick'; | ||
import * as S from './Modal.style'; | ||
|
||
export interface ModalProps { | ||
action?: 'share' | 'tag' | 'tempGame'; | ||
isOpen?: boolean; | ||
onClose?: () => void; | ||
hasCloseButton?: boolean; | ||
children?: ReactNode; | ||
} | ||
|
||
const Modal = ({ | ||
isOpen, | ||
onClose, | ||
action = 'share', | ||
hasCloseButton = true, | ||
children, | ||
}: ModalProps) => { | ||
const modalRef = useRef<HTMLDivElement>(null); | ||
|
||
useOutsideClick(modalRef, () => onClose?.()); | ||
|
||
return ( | ||
<div> | ||
{isOpen && ( | ||
<div ref={modalRef} css={[S.modalStyling, S.getModalSize(action)]}> | ||
{hasCloseButton && ( | ||
<MobileModalClose css={S.modalCloseStyling} onClick={onClose} /> | ||
)} | ||
{children} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Modal; |
35 changes: 35 additions & 0 deletions
35
src/components/mobile/atoms/TempGameButton/TempGameButton.style.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import color from '@/styles/color'; | ||
import typo from '@/styles/typo'; | ||
import { css } from '@emotion/react'; | ||
|
||
export const tempGameButtonStyling = css({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
justifyContent: 'flex-end', | ||
padding: '10px', | ||
width: '142px', | ||
height: '136px', | ||
backgroundColor: color.WT, | ||
borderRadius: '10px', | ||
border: `1px solid ${color.GY[3]}`, | ||
boxShadow: '1px 2px 15px rgba(0, 0, 0, 0.05)', | ||
cursor: 'pointer', | ||
}); | ||
|
||
export const itemWrapper = css({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
justifyContent: 'space-between', | ||
height: '95px', | ||
}); | ||
|
||
export const buttonStyling = css(typo.Mobile.Text.SemiBold_14, { | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
width: '122px', | ||
height: '34px', | ||
borderRadius: '8px', | ||
backgroundColor: color.WT_VIOLET, | ||
color: color.MAIN, | ||
}); |
24 changes: 24 additions & 0 deletions
24
src/components/mobile/atoms/TempGameButton/TempGameButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React, { forwardRef } from 'react'; | ||
import type { ComponentPropsWithRef, ForwardedRef } from 'react'; | ||
import { MobileFolder, MobileFolderCheck } from '@/assets'; | ||
import * as S from './TempGameButton.style'; | ||
|
||
export interface ButtonProps extends ComponentPropsWithRef<'button'> { | ||
action?: 'save' | 'get'; | ||
} | ||
|
||
const TempGameButton = ( | ||
{ action = 'save', ...attributes }: ButtonProps, | ||
ref: ForwardedRef<HTMLButtonElement>, | ||
) => ( | ||
<button type="button" ref={ref} css={S.tempGameButtonStyling} {...attributes}> | ||
<div css={S.itemWrapper}> | ||
<div>{action === 'save' ? <MobileFolderCheck /> : <MobileFolder />}</div> | ||
<div css={S.buttonStyling}> | ||
{action === 'save' ? '임시저장하기' : '임시저장 불러오기'} | ||
</div> | ||
</div> | ||
</button> | ||
); | ||
|
||
export default forwardRef(TempGameButton); |
81 changes: 81 additions & 0 deletions
81
src/components/mobile/molecules/GameTagModal/GameTagModal.style.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { css } from '@emotion/react'; | ||
import color from '@/styles/color'; | ||
import typo from '@/styles/typo'; | ||
|
||
export const contentWrapper = css({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
alignItems: 'center', | ||
gap: '20px', | ||
}); | ||
|
||
export const textBox = css({ | ||
display: 'flex', | ||
flexDirection: 'row', | ||
alignItems: 'center', | ||
gap: '3px', | ||
}); | ||
|
||
export const textStyling = css(typo.Main.SemiBold, { | ||
color: color.BK, | ||
}); | ||
|
||
export const tagTextStyling = css(typo.Mobile.Text.SemiBold_14, { | ||
color: color.GY[1], | ||
}); | ||
|
||
export const markStyling = css(typo.Mobile.Text.SemiBold_14, { | ||
color: color.MAIN, | ||
}); | ||
|
||
export const tagWrapper = css({ | ||
width: '100%', | ||
display: 'flex', | ||
flexDirection: 'column', | ||
gap: '6px', | ||
}); | ||
|
||
export const buttonWrapper = css({ | ||
display: 'flex', | ||
gap: '8px', | ||
}); | ||
|
||
export const inputStyling = css(typo.Mobile.Text.Medium_12, { | ||
fontSize: '14px', | ||
width: '295px', | ||
height: '42px', | ||
padding: '10px 20px', | ||
border: `1px solid ${color.GY[4]}`, | ||
borderRadius: '6px', | ||
}); | ||
|
||
export const customButtonStyle = (isDisabled: boolean) => | ||
css({ | ||
cursor: isDisabled ? 'not-allowed' : 'pointer', | ||
}); | ||
|
||
export const customDisabledBtnStyle = css({ | ||
color: color.WT, | ||
backgroundColor: color.GY[2], | ||
outline: '1px solid transparent', | ||
pointerEvents: 'none', | ||
':hover': { | ||
backgroundColor: color.GY[2], | ||
}, | ||
}); | ||
|
||
export const getButtonStyling = (isSelected: boolean) => { | ||
return css({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
width: '64px', | ||
height: '34px', | ||
borderRadius: '6px', | ||
border: isSelected ? 'null' : `1px solid ${color.GY[4]}`, | ||
backgroundColor: isSelected ? color.MAIN : color.GY[5], | ||
color: isSelected ? color.WT : color.GY[1], | ||
cursor: 'pointer', | ||
}); | ||
}; |
85 changes: 85 additions & 0 deletions
85
src/components/mobile/molecules/GameTagModal/GameTagModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import React, { useState } from 'react'; | ||
import { MobileCheckIcon } from '@/assets'; | ||
import Modal from '@/components/mobile/atoms/Modal/Modal'; | ||
import Button from '@/components/mobile/atoms/Button/Button'; | ||
import Divider from '@/components/atoms/Divider/Divider'; | ||
import * as S from './GameTagModal.style'; | ||
|
||
interface GameTagModalProps { | ||
isOpen?: boolean; | ||
onClose?: () => void; | ||
onTagSubmit: (mainTag: string, subTag: string) => void; | ||
} | ||
|
||
const GameTagModal = ({ isOpen, onClose, onTagSubmit }: GameTagModalProps) => { | ||
const [mainTag, setMainTag] = useState<string | null>(null); | ||
const [subTag, setSubTag] = useState<string>(''); | ||
|
||
const handleTagSubmit = () => { | ||
if (mainTag) { | ||
onTagSubmit(mainTag, subTag); | ||
onClose?.(); | ||
} | ||
}; | ||
|
||
return ( | ||
<Modal isOpen={isOpen} onClose={onClose} action="tag"> | ||
<div css={S.contentWrapper}> | ||
<MobileCheckIcon /> | ||
<div css={S.textStyling}>밸런스게임 태그를 선택해주세요!</div> | ||
<Divider orientation="width" length={50} /> | ||
<div css={S.tagWrapper}> | ||
<div css={S.textBox}> | ||
<span css={S.tagTextStyling}>메인태그</span> | ||
<span css={S.markStyling}>*</span> | ||
</div> | ||
<div css={S.buttonWrapper}> | ||
<button | ||
type="button" | ||
css={S.getButtonStyling(mainTag === '커플')} | ||
onClick={() => setMainTag('커플')} | ||
> | ||
커플 | ||
</button> | ||
<button | ||
type="button" | ||
css={S.getButtonStyling(mainTag === '취향')} | ||
onClick={() => setMainTag('취향')} | ||
> | ||
취향 | ||
</button> | ||
<button | ||
type="button" | ||
css={S.getButtonStyling(mainTag === '기타')} | ||
onClick={() => setMainTag('기타')} | ||
> | ||
기타 | ||
</button> | ||
</div> | ||
</div> | ||
<div css={S.tagWrapper}> | ||
<div css={S.textBox}> | ||
<span css={S.tagTextStyling}>서브태그</span> | ||
</div> | ||
<input | ||
css={S.inputStyling} | ||
placeholder="ex) 아이돌, 연애..." | ||
value={subTag} | ||
onChange={(e) => setSubTag(e.target.value)} | ||
/> | ||
</div> | ||
<Button | ||
size="large" | ||
variant="roundPrimary" | ||
onClick={handleTagSubmit} | ||
disabled={!mainTag} | ||
css={S.customButtonStyle(!mainTag)} | ||
> | ||
등록하기 | ||
</Button> | ||
</div> | ||
</Modal> | ||
); | ||
}; | ||
|
||
export default GameTagModal; |
19 changes: 19 additions & 0 deletions
19
src/components/mobile/molecules/ShareModal/ShareModal.style.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { css } from '@emotion/react'; | ||
import color from '@/styles/color'; | ||
import typo from '@/styles/typo'; | ||
|
||
export const shareModalStyling = css({ | ||
display: 'flex', | ||
flexDirection: 'column', | ||
alignItems: 'center', | ||
}); | ||
|
||
export const textStyling = css(typo.Comment.SemiBold, { | ||
marginTop: '24px', | ||
marginBottom: '23px', | ||
color: color.BK, | ||
}); | ||
|
||
export const shareTextStyling = css(typo.Comment.SemiBold, { | ||
color: color.MAIN, | ||
}); |
Oops, something went wrong.