-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: 유저 페이지 모달 연결 및 툴팁 컴포넌트 구현 (#32)
* feat: blue color 추가 * design: Dimmed z-index 부여 * feat: AddMenu 컴포넌트 구현 * design: Modal z-index 부여 * refactor: hook export * feat: useModals hook 추가 여러 모달들의 state를 관리 * feat: FilmAddModal 추가 * feat: 필름제목수정 모달 추가 * feat: useSafeContext hook 추가 * feat: arrow down svg 추가 * feat: Select 컴포넌트 구현 * design: Select item 커서 포인터 추가 * feat: FilmSelectModal 추가 * feat: 유저 페이지 모달 연결 * feat: pencil 아이콘 추가 * refactor: hook 이름 수정 * chore: eslint rule 수정 * feat: ModalProvider 생성 * feat: 유저페이지 ModalProvider wrapping * feat: Drawer 회원가입, 로그인 링킹 * feat: 필름 제목 edit 모달 연결 * design: modal min height 설정 * design: input full width 추가 * fix: camera svg size를 조절할 수 없던 문제 해결 * feat: 유저페이지 프로필모달 연결 * feat: isString type util 추가 * feat: Close 아이콘 추가 * feat: tooltip 컴포넌트 추가 * feat: 유저페이지 tooltip 컴포넌트 적용 * feat: add페이지 title query 적용
- Loading branch information
Showing
33 changed files
with
599 additions
and
68 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.
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.
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
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
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,82 @@ | ||
import type { MouseEventHandler, PropsWithChildren } from 'react'; | ||
import { createContext, useState } from 'react'; | ||
import { useSafeContext } from '@/hooks'; | ||
import { Icon } from '@/components/shared/Icon'; | ||
import { cn } from '@/utils/cn'; | ||
|
||
interface SelectProps { | ||
isExpanded?: boolean; | ||
selected: string; | ||
onSelect: (option: string) => void; | ||
} | ||
|
||
interface SelectItemProps { | ||
children: string; | ||
} | ||
|
||
interface SelectContextType { | ||
selected: string; | ||
closeSelect: () => void; | ||
onSelect: (option: string) => void; | ||
} | ||
const SelectContext = createContext<SelectContextType | null>(null); | ||
|
||
export function Select({ | ||
children, | ||
isExpanded: isExpandedFromProps = false, | ||
selected, | ||
onSelect, | ||
}: PropsWithChildren<SelectProps>) { | ||
const [isExpanded, setIsExpanded] = useState(isExpandedFromProps); | ||
|
||
const handleToggleSelect: MouseEventHandler<SVGSVGElement> = () => { | ||
setIsExpanded((prev) => !prev); | ||
}; | ||
|
||
const closeSelect = () => { | ||
setIsExpanded(false); | ||
}; | ||
|
||
return ( | ||
<div className='rounded tw-flex tw-w-full tw-flex-col tw-overflow-hidden tw-border tw-border-grayscale-300'> | ||
<div className='tw-flex tw-h-12 tw-w-full tw-items-center tw-justify-between tw-pl-2.5 tw-pr-3'> | ||
<span className='tw-text-body2-accent tw-text-grayscale-700'>{selected}</span> | ||
<Icon | ||
iconType='ArrowDown' | ||
className={cn('tw-top-1/2 tw-cursor-pointer', isExpanded && '-tw-rotate-180')} | ||
onClick={handleToggleSelect} | ||
/> | ||
</div> | ||
<div className={cn('tw-h-0 tw-w-full', isExpanded && 'tw-h-fit')}> | ||
<ul className='tw-w-full'> | ||
<SelectContext.Provider value={{ selected, closeSelect, onSelect }}>{children}</SelectContext.Provider> | ||
</ul> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
function SelectItem({ children }: SelectItemProps) { | ||
const { selected, closeSelect, onSelect } = useSafeContext(SelectContext); | ||
|
||
const handleSelect = | ||
(option: string): MouseEventHandler<HTMLLIElement> => | ||
() => { | ||
onSelect(option); | ||
closeSelect(); | ||
}; | ||
|
||
return ( | ||
<li | ||
className={cn( | ||
'tw-flex-justify-between tw-text-body2 tw-flex tw-h-12 tw-w-full tw-cursor-pointer tw-items-center tw-border-t tw-border-grayscale-300 tw-bg-grayscale-100 tw-p-2.5 tw-text-grayscale-400', | ||
selected === children && 'tw-hidden', | ||
)} | ||
onClick={handleSelect(children)} | ||
> | ||
{children} | ||
</li> | ||
); | ||
} | ||
|
||
Select.Item = SelectItem; |
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 @@ | ||
export * from './Select'; |
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,27 @@ | ||
import { type HTMLAttributes, type MouseEventHandler, type PropsWithChildren, useState } from 'react'; | ||
import { Icon } from '@/components/shared/Icon'; | ||
|
||
interface Props extends HTMLAttributes<HTMLDivElement> { | ||
isOpen?: boolean; | ||
text: string; | ||
} | ||
|
||
export function Tooltip({ children, isOpen: isOpenFromProps = true, text, ...restProps }: PropsWithChildren<Props>) { | ||
const [isOpen, setIsOpen] = useState(isOpenFromProps); | ||
|
||
const handleClickClose: MouseEventHandler<SVGSVGElement> = () => { | ||
setIsOpen(false); | ||
}; | ||
|
||
return ( | ||
<div className='tw-relative' {...restProps}> | ||
{children} | ||
{isOpen && ( | ||
<div className='tw-text-body2-accent tw-absolute tw-right-full tw-top-1/2 tw-flex tw-w-[200px] -tw-translate-x-1 -tw-translate-y-1/2 tw-items-center tw-justify-between tw-gap-1 tw-rounded tw-bg-nudge tw-px-2 tw-py-1 after:tw-absolute after:tw-right-0 after:tw-h-2.5 after:tw-w-2.5 after:tw-translate-x-1/2 after:tw-rotate-45 after:tw-bg-nudge after:tw-content-[""]'> | ||
<p className='tw-shrink-0'>{text}</p> | ||
<Icon iconType='Close' className='tw-cursor-pointer tw-fill-grayscale-700' onClick={handleClickClose} /> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} |
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 @@ | ||
export * from './Tooltip' |
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,31 @@ | ||
import { MouseEventHandler } from 'react'; | ||
import { Dimmed, Portal } from '@/components/shared'; | ||
import { cn } from '@/utils/cn'; | ||
|
||
interface Props { | ||
isOpen: boolean; | ||
onClose: MouseEventHandler<HTMLDivElement>; | ||
onAddFilm: MouseEventHandler<HTMLDivElement>; | ||
onUploadPhoto: MouseEventHandler<HTMLDivElement>; | ||
} | ||
|
||
const menuStyle = | ||
'tw-w-full tw-cursor-pointer tw-py-[22px] tw-text-blue tw-flex tw-justify-center tw-items-center hover:tw-bg-grayscale-100'; | ||
|
||
export function AddMenu({ isOpen, onClose, onAddFilm, onUploadPhoto }: Props) { | ||
if (!isOpen) return null; | ||
|
||
return ( | ||
<Portal> | ||
<Dimmed onClick={onClose} /> | ||
<div className='tw-fixed tw-left-1/2 tw-top-1/2 tw-z-10 tw-w-[335px] -tw-translate-x-1/2 -tw-translate-y-1/2 tw-overflow-hidden tw-rounded tw-bg-white'> | ||
<div className={cn(menuStyle, 'tw-border-b')} onClick={onAddFilm}> | ||
새로운 필름 추가 | ||
</div> | ||
<div className={menuStyle} onClick={onUploadPhoto}> | ||
포토컷 올리기 | ||
</div> | ||
</div> | ||
</Portal> | ||
); | ||
} |
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,23 @@ | ||
import { type ComponentProps, type MouseEventHandler, useState } from 'react'; | ||
import { Input, Modal } from '@/components/shared'; | ||
|
||
type Props = Omit<ComponentProps<typeof Modal>, 'title' | 'children'>; | ||
|
||
export function FilmAddModal({ onCancel, ...restProps }: Props) { | ||
const [input, setInput] = useState(''); | ||
|
||
const handleValueChange = (value: string) => { | ||
setInput(value); | ||
}; | ||
|
||
const handleSave: MouseEventHandler<HTMLButtonElement> = (e) => { | ||
// TODO: 필름 추가 API 연결 | ||
if (onCancel) onCancel(e); | ||
}; | ||
|
||
return ( | ||
<Modal title='새로운 필름 추가' onCancel={onCancel} onSave={handleSave} {...restProps}> | ||
<Input label='필름 제목' placeholder='필름 제목을 입력하세요' value={input} onValueChange={handleValueChange} /> | ||
</Modal> | ||
); | ||
} |
Oops, something went wrong.