-
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.
feat: 내 정보 페이지 스크롤 케이스 & 스켈레톤 구현 (#41)
* 카드 추가 모달 구현 * type 명 변경 * feat: 카드 조회 api 연동 * CustomDialog * 카드 추가하기 기능 구현 * 카드삭제 기능 구현 * 터치버튼 * http * 쿼리키 분리 * 카드 추가 후 에디터로 이동 * ui 일부 수정 * 제목 색상 변경 * delete * scroll * button * skeleton * api 변경사항 반영
- Loading branch information
Showing
8 changed files
with
156 additions
and
67 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
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
35 changes: 35 additions & 0 deletions
35
src/app/(sidebar)/(my-info)/components/InfoCardSkeleton.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,35 @@ | ||
import { motion } from 'framer-motion'; | ||
import { match } from 'ts-pattern'; | ||
|
||
interface InfoCardSkeletonProps { | ||
count: number; | ||
} | ||
|
||
export function InfoCardSkeleton({ count }: InfoCardSkeletonProps) { | ||
return ( | ||
<motion.div | ||
variants={{ | ||
show: { | ||
transition: { | ||
staggerChildren: 0.1, | ||
}, | ||
}, | ||
}} | ||
initial="hide" | ||
animate="show" | ||
className="grid grid-cols-[repeat(auto-fill,minmax(343px,1fr))] gap-[16px]"> | ||
{Array(count) | ||
.fill(0) | ||
.map((_, index) => ( | ||
<motion.div | ||
key={index} | ||
variants={{ | ||
hide: { opacity: 0.1, scale: 1 }, | ||
show: { opacity: 1, scale: 0.98, transition: { repeat: Infinity, repeatType: 'reverse', duration: 0.5 } }, | ||
}} | ||
className="h-[140px] p-[24px] rounded-[16px] bg-neutral-3" | ||
/> | ||
))} | ||
</motion.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 |
---|---|---|
@@ -1,19 +1,118 @@ | ||
'use client'; | ||
|
||
import { Icon } from '@/system/components'; | ||
import { Dropdown, Icon } from '@/system/components'; | ||
import { InfoCardList } from './components/InfoCardList'; | ||
import { Suspense, useEffect, useRef, useState } from 'react'; | ||
import { AddInfoCardDialog } from './components/AddInfoCardDialog'; | ||
import { TouchButton } from '@/components/TouchButton'; | ||
import { INFO_TYPES, InfoType } from '@/types'; | ||
import { useScroll } from '@/hooks/useScroll'; | ||
import { cn } from '@/utils/tailwind-util'; | ||
import { useGetCardTypeCount } from './apis/useGetCardTypeCount'; | ||
import { If } from '@/system/utils/If'; | ||
import { motion } from 'framer-motion'; | ||
import { InfoCardSkeleton } from './components/InfoCardSkeleton'; | ||
import { AsyncBoundaryWithQuery } from '@/lib'; | ||
|
||
export default function MyInfo() { | ||
const [showHeader, setShowHeader] = useState(false); | ||
const headerRef = useRef<HTMLDivElement>(null); | ||
|
||
const [currentCardType, setCurrentCardType] = useState<InfoType>('경험_정리'); | ||
|
||
const { data: cardCount } = useGetCardTypeCount(); | ||
|
||
useScroll(headerRef, (y) => setShowHeader(y > 192)); | ||
|
||
return ( | ||
<div className="max-w-[1700px] py-[64px] px-[80px] mx-auto bg-neutral-1"> | ||
<div className="mb-[72px] flex justify-between"> | ||
<h1 className="text-[28px] font-bold">내 정보</h1> | ||
<button className="flex gap-[24px] p-[16px] border rounded-[8px] border-neutral-5 bg-white"> | ||
<div className="text-[16px] font-semibold">김뽀각님의 기본정보</div> | ||
<Icon name="down" color="#878A93" /> | ||
</button> | ||
<div ref={headerRef} className="max-h-[100vh] w-full overflow-auto"> | ||
<div className="mx-auto max-w-[1700px] py-[64px] px-[80px] bg-neutral-1"> | ||
<div className="mb-[48px] flex justify-between"> | ||
<h1 className="text-[28px] font-bold">내 정보</h1> | ||
</div> | ||
<div className="sticky top-0 bg-neutral-1"> | ||
<div className="flex justify-between py-[24px]"> | ||
<If condition={showHeader}> | ||
<div className="flex gap-12 items-center"> | ||
<motion.h1 initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="text-heading1 font-bold"> | ||
내 정보 | ||
</motion.h1> | ||
<Dropdown> | ||
<Dropdown.Trigger> | ||
<TouchButton layout> | ||
<motion.div | ||
initial={{ opacity: 0 }} | ||
animate={{ opacity: 1 }} | ||
className="flex items-center gap-4 rounded-6 border bg-white px-12 py-6"> | ||
<span className="text-label1 font-semibold text-neutral-95"> | ||
{currentCardType.replaceAll('_', ' ')} | ||
</span> | ||
<Dropdown.TriggerArrow /> | ||
</motion.div> | ||
</TouchButton> | ||
</Dropdown.Trigger> | ||
<Dropdown.Content align="end"> | ||
{INFO_TYPES.map((type) => ( | ||
<Dropdown.CheckedItem | ||
key={type} | ||
checked={type === currentCardType} | ||
className={type === currentCardType ? 'text-neutral-30' : ''} | ||
onClick={() => setCurrentCardType(type)}> | ||
{type.replace('_', ' ')} | ||
</Dropdown.CheckedItem> | ||
))} | ||
</Dropdown.Content> | ||
</Dropdown> | ||
</div> | ||
</If> | ||
<If condition={!showHeader}> | ||
<div className="flex gap-[24px]"> | ||
{INFO_TYPES.map((type) => ( | ||
<TouchButton | ||
key={type} | ||
className="flex gap-[6px] items-center cursor-pointer" | ||
onClick={() => setCurrentCardType(type)}> | ||
<div | ||
className={cn( | ||
'text-[18px] text-neutral-10 font-semibold', | ||
currentCardType === type && 'text-neutral-80', | ||
)}> | ||
{type.replaceAll('_', ' ')} | ||
</div> | ||
<div | ||
className={cn( | ||
'px-[8px] py-[2px] bg-neutral-10 rounded-[6px] text-neutral-1 text-[14px] font-semibold', | ||
currentCardType === type && 'bg-neutral-80', | ||
)}> | ||
{cardCount?.[type] || 0} | ||
</div> | ||
</TouchButton> | ||
))} | ||
</div> | ||
</If> | ||
<AddInfoCardDialog> | ||
<TouchButton layout> | ||
<motion.div | ||
initial={{ padding: '8px 16px' }} | ||
variants={{ longPadding: { padding: '8px 16px' }, shortPadding: { padding: '8px 8px' } }} | ||
animate={showHeader ? 'shortPadding' : 'longPadding'} | ||
className="bg-neutral-95 flex items-center gap-[4px] rounded-[6px]"> | ||
<Icon name="add" size={20} color="#20E79D" /> | ||
{!showHeader && <span className="text-label1 text-white font-semibold">카드 추가</span>} | ||
</motion.div> | ||
</TouchButton> | ||
</AddInfoCardDialog> | ||
</div> | ||
<If condition={showHeader}> | ||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="mx-[-80px] bg-neutral-5 h-[1px]" /> | ||
</If> | ||
</div> | ||
<AsyncBoundaryWithQuery | ||
errorFallback={<InfoCardSkeleton count={4} />} | ||
pendingFallback={<InfoCardSkeleton count={4} />}> | ||
<InfoCardList cardType={currentCardType} /> | ||
</AsyncBoundaryWithQuery> | ||
</div> | ||
<InfoCardList /> | ||
</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
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