-
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.
* fix: svg width, height 속성 제거 * feat: BookGroupInfo 컴포넌트 작성 * feat: BookGroupInfo 컴포넌트 스토리 작성 * chore: 공백 제거 * chore: 불필요한 로그 제거 * chore: BookGroupInfo 스토리 파일 위치 변경 * refactor: avatar size 수정 및 svgr wrapper 태그 제거 - 3.5rem -> 3.2rem 으로 통일 * feat: next/image placeholder 속성 적용 * style: 책 이미지 shadow 및 크기 수정 * feat: BookCover 컴포넌트 작성 * refactor: Dday 컴포넌트 -> BookGroupStatus로 파일 분리 * feat: BookGroupStatus 스토리북 작성
- Loading branch information
Showing
10 changed files
with
331 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export const DATA_URL = { | ||
placeholder: | ||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdjWL9+/X8ABysDDapsaG4AAAAASUVORK5CYII=', // data url for placeholder color (#AFAFAF) | ||
}; |
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 BookGroupStatus from '@/ui/bookgroup/BookGroupStatus'; | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
|
||
const meta: Meta<typeof BookGroupStatus> = { | ||
title: 'bookgroup/BookGroupStatus', | ||
component: BookGroupStatus, | ||
tags: ['autodocs'], | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof BookGroupStatus>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
start: '2023-12-31', | ||
end: '2024-01-08', | ||
}, | ||
}; |
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 @@ | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import BookGroupInfo from '@/ui/bookgroup/detail/BookGroupInfo'; | ||
|
||
const meta: Meta<typeof BookGroupInfo> = { | ||
title: 'bookgroup/detail/BookGroupInfo', | ||
component: BookGroupInfo, | ||
tags: ['autodocs'], | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof BookGroupInfo>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
title: '프롱이 리팩터링 스터디', | ||
description: | ||
'제 1차 프롱이 기수연합 독서 스터디 입니다. 마틴 파울러의 저서 ‘리팩터링 2판’과 함께 진행합니다.', | ||
book: { | ||
title: '리팩터링 2판', | ||
author: '마틴 파울러', | ||
bookImageSrc: 'https://image.yes24.com/goods/89649360/XL', | ||
}, | ||
date: { | ||
start: '2023-10-31', | ||
end: '2023-11-27', | ||
}, | ||
memberCount: { | ||
current: 3, | ||
max: 20, | ||
}, | ||
owner: { | ||
isMe: true, | ||
name: '소피아', | ||
profileImageSrc: '/icons/logo.svg', | ||
}, | ||
isPublic: false, | ||
}, | ||
}; |
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 type DdayStatus = 'before' | 'dday' | 'ongoing' | 'end'; |
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,61 @@ | ||
import { ComponentPropsWithoutRef } from 'react'; | ||
import Image from 'next/image'; | ||
|
||
import { DATA_URL } from '@/constants/dataUrl'; | ||
|
||
type BookCoverSize = | ||
| 'xsmall' | ||
| 'small' | ||
| 'medium' | ||
| 'large' | ||
| 'xlarge' | ||
| '2xlarge'; | ||
|
||
type BookCoverProps = Required< | ||
Pick<ComponentPropsWithoutRef<typeof Image>, 'src'> | ||
> & { | ||
title: string; | ||
size?: BookCoverSize; | ||
}; | ||
|
||
const getCoverSizeClasses = (size: BookCoverSize) => { | ||
switch (size) { | ||
case 'xsmall': { | ||
return 'w-[6.5rem] h-[9.1rem]'; | ||
} | ||
case 'small': { | ||
return 'w-[7.0rem] h-[9.8rem]'; | ||
} | ||
case 'medium': { | ||
return 'w-[7.5rem] h-[10.5rem]'; | ||
} | ||
case 'large': { | ||
return 'w-[9.0rem] h-[12.6rem]'; | ||
} | ||
case 'xlarge': { | ||
return 'w-[11.0rem] h-[15.4rem]'; | ||
} | ||
case '2xlarge': { | ||
return 'w-[18.0rem] h-[25.2rem]'; | ||
} | ||
} | ||
}; | ||
|
||
const BookCover = ({ src, title, size = 'medium' }: BookCoverProps) => { | ||
const sizeClasses = getCoverSizeClasses(size); | ||
|
||
return ( | ||
<span className={`relative ${sizeClasses}`}> | ||
<Image | ||
src={src} | ||
alt={title} | ||
placeholder="blur" | ||
blurDataURL={DATA_URL['placeholder']} | ||
className="object-fit rounded-[0.5rem] shadow-bookcover" | ||
fill | ||
/> | ||
</span> | ||
); | ||
}; | ||
|
||
export default BookCover; |
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,57 @@ | ||
import { DdayStatus } from '@/types/dday'; | ||
|
||
import Badge from '@/ui/Base/Badge'; | ||
import { getDdayCount } from '@/utils/date'; | ||
|
||
const getDdayStatus = (ddayByStart: number, ddayByEnd: number) => { | ||
if (ddayByStart > 0) { | ||
return 'before' as const; | ||
} else if (ddayByStart === 0 && ddayByEnd > 0) { | ||
return 'dday' as const; | ||
} else if (ddayByStart < 0 && ddayByEnd >= 0) { | ||
return 'ongoing' as const; | ||
} else { | ||
return 'end' as const; | ||
} | ||
}; | ||
|
||
const getBadgeProps = (status: DdayStatus, ddayCount: number) => { | ||
switch (status) { | ||
case 'before': | ||
return { | ||
colorScheme: 'main' as const, | ||
isFilled: true, | ||
text: `D-${ddayCount}`, | ||
}; | ||
case 'dday': | ||
return { | ||
colorScheme: 'main' as const, | ||
isFilled: false, | ||
text: 'D-day', | ||
}; | ||
case 'ongoing': | ||
return { | ||
colorScheme: 'main' as const, | ||
isFilled: true, | ||
text: '진행중', | ||
}; | ||
case 'end': | ||
return { | ||
colorScheme: 'grey' as const, | ||
isFilled: true, | ||
text: '모임종료', | ||
}; | ||
} | ||
}; | ||
|
||
const BookGroupStatus = ({ start, end }: { start: string; end: string }) => { | ||
const ddayByStart = getDdayCount(new Date(start)); | ||
const ddayByEnd = getDdayCount(new Date(end)); | ||
const ddayStatus = getDdayStatus(ddayByStart, ddayByEnd); | ||
|
||
const { text, ...badgeProps } = getBadgeProps(ddayStatus, ddayByStart); | ||
|
||
return <Badge {...badgeProps}>{text}</Badge>; | ||
}; | ||
|
||
export default BookGroupStatus; |
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,139 @@ | ||
import Image from 'next/image'; | ||
|
||
import Badge from '@/ui/Base/Badge'; | ||
import BookCover from '@/ui/book/BookCover'; | ||
import BookGroupStatus from '@/ui/bookgroup/BookGroupStatus'; | ||
import { IconArrowLeft, IconCalendar, IconMembers } from '@public/icons'; | ||
import { DATA_URL } from '@/constants/dataUrl'; | ||
|
||
interface BookGroupInfoProps { | ||
title: string; | ||
description: string; | ||
book: { title: string; author: string; bookImageSrc: string }; | ||
date: { start: string; end: string }; | ||
memberCount: { current: number; max: number }; | ||
owner: { isMe: boolean; name: string; profileImageSrc: string }; | ||
isPublic: boolean; | ||
} | ||
|
||
const BookGroupInfo = ({ | ||
title, | ||
description, | ||
book, | ||
date, | ||
memberCount, | ||
owner, | ||
isPublic, | ||
}: BookGroupInfoProps) => { | ||
return ( | ||
<div className="flex flex-col gap-[1rem]"> | ||
<div className="flex gap-[0.5rem]"> | ||
<BookGroupStatus start={date.start} end={date.end} /> | ||
<Public isPublic={isPublic} /> | ||
</div> | ||
<Owner | ||
name={owner.name} | ||
isMe={owner.isMe} | ||
profileImageSrc={owner.profileImageSrc} | ||
/> | ||
<Title title={title} /> | ||
<BookInfoCard | ||
title={book.title} | ||
bookImageSrc={book.bookImageSrc} | ||
author={book.author} | ||
/> | ||
<div className="flex flex-col gap-[0.3rem]"> | ||
<Duration start={date.start} end={date.end} /> | ||
<MemberCapacity current={memberCount.current} max={memberCount.max} /> | ||
</div> | ||
<Description content={description} /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default BookGroupInfo; | ||
|
||
const Public = ({ isPublic }: { isPublic: boolean }) => ( | ||
<Badge colorScheme="grey">{isPublic ? '공개' : '비공개'}</Badge> | ||
); | ||
|
||
const Owner = ({ | ||
profileImageSrc, | ||
name, | ||
isMe, | ||
}: { | ||
profileImageSrc: string; | ||
name: string; | ||
isMe: boolean; | ||
}) => { | ||
return ( | ||
<div className="flex items-center gap-[1rem]"> | ||
{/** FIXME: Avatar 컴포넌트로 변경 */} | ||
<Image | ||
width={32} | ||
height={32} | ||
alt={name} | ||
src={profileImageSrc} | ||
className="rounded-full" | ||
placeholder="blur" | ||
blurDataURL={DATA_URL['placeholder']} | ||
/> | ||
<span className="text-center text-sm font-bold"> | ||
{name} {isMe && ' 👑'} | ||
</span> | ||
</div> | ||
); | ||
}; | ||
|
||
const Title = ({ title }: { title: string }) => { | ||
return <p className="text-xl font-bold">{title}</p>; | ||
}; | ||
|
||
const BookInfoCard = ({ | ||
bookImageSrc, | ||
title, | ||
author, | ||
}: { | ||
bookImageSrc: string; | ||
title: string; | ||
author: string; | ||
}) => { | ||
return ( | ||
<div className="flex min-h-[10rem] w-full cursor-pointer gap-[2.4rem] rounded-[0.5rem] border-[0.05rem] border-cancel px-[2.2rem] py-[1.8rem]"> | ||
<BookCover size="xsmall" src={bookImageSrc} title={title} /> | ||
<div className="flex flex-grow flex-col"> | ||
<span className="text-sm font-bold">{title}</span> | ||
<span className="text-xs text-placeholder">{author}</span> | ||
</div> | ||
{/** 왼쪽 방향의 화살표를 180도 회전하여 사용 */} | ||
<IconArrowLeft className="h-[1.5rem] w-[1.5rem] rotate-180" /> | ||
</div> | ||
); | ||
}; | ||
|
||
const Duration = ({ start, end }: { start: string; end: string }) => { | ||
return ( | ||
<div className="flex items-center gap-[1rem]"> | ||
<IconCalendar className="h-auto w-[1.6rem] fill-placeholder" /> | ||
<span className="text-sm text-placeholder"> | ||
{start} - {end} | ||
</span> | ||
</div> | ||
); | ||
}; | ||
|
||
const MemberCapacity = ({ current, max }: { current: number; max: number }) => { | ||
return ( | ||
<div className="flex items-center gap-[1rem]"> | ||
<IconMembers className="h-auto w-[1.6rem] fill-placeholder" /> | ||
<span className="text-sm text-placeholder"> | ||
<span className="text-main-900">{current}</span> | ||
{` / ${max}명`} | ||
</span> | ||
</div> | ||
); | ||
}; | ||
|
||
const Description = ({ content }: { content: string }) => { | ||
return <p className="text-md leading-snug">{content}</p>; | ||
}; |
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,5 @@ | ||
export const toDayFromMillseconds = (value: number) => | ||
Math.ceil(value / (1000 * 60 * 60 * 24)); | ||
|
||
export const getDdayCount = (target: Date) => | ||
toDayFromMillseconds(target.getTime() - new Date().getTime()); |
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