Skip to content

Commit

Permalink
[#410] [북카이브] 북카이브 페이지 (비회원) (#425)
Browse files Browse the repository at this point in the history
* feat: 책장 컴포넌트 작성

* feat: 책장에 있는 책 컴포넌트 작성

* feat: 책장 컴포넌트 스토리 작성

* fix: 책장 컴포넌트에서 CLS 현상이 발생하지 않도록 수정

* feat: 책장에 있는 책 그림자 추가

* fix: remove icon wrapper element

* feat: Add a bookshelf shortcut icon

* feat: '인기 책장' 문구 추가

* fix: 책장 local image 사용하도록 수정

* Update src/ui/BookArchive/BookArchiveForUnAuth.tsx

Co-authored-by: kyuran kim <[email protected]>

---------

Co-authored-by: gxxrxn <[email protected]>
Co-authored-by: kyuran kim <[email protected]>
  • Loading branch information
3 people committed Jun 17, 2024
1 parent cbb032a commit 08c919d
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 20 deletions.
2 changes: 1 addition & 1 deletion public/icons/arrow-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions src/stories/Base/Bookshelf/Bookshelf.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Bookshelf from '@/ui/Bookshelf';
import { Meta, StoryObj } from '@storybook/react';

const meta: Meta<typeof Bookshelf> = {
title: 'Bookshelf/Bookshelf',
component: Bookshelf,
tags: ['autodocs'],
};

export default meta;

type Story = StoryObj<typeof Bookshelf>;

// TODO: 스토리북에서 이미지를 불러올 때 발생하는 CORS 이슈 해결
export const Default: Story = {
args: {
bookshelfId: 9,
bookshelfName: '백민종님의 책장',
books: [
{
bookId: 3,
title: '리액트를 다루는 기술',
imageUrl: '/images/book-cover/book1.jpeg',
},
{
bookId: 11,
title: '모던 자바스크립트 Deep Dive',
imageUrl: '/images/book-cover/book2.jpeg',
},
{
bookId: 22,
title: '이펙티브 타입스크립트',
imageUrl: '/images/book-cover/book3.jpeg',
},
{
bookId: 23,
title: '리팩터링 2판',
imageUrl: '/images/book-cover/book4.jpeg',
},
],
likeCount: 3,
},
};
25 changes: 10 additions & 15 deletions src/ui/BookArchive/BookArchiveForUnAuth.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import useUnAuthRecommendedBookshelfQuery from '@/queries/recommend/useUnAuthRecommendedBookshelfQuery';
import { Flex, Skeleton, VStack } from '@chakra-ui/react';
import { RecommendedBookshelf } from '../Recommended';
import { Skeleton, VStack } from '@chakra-ui/react';
import Bookshelf from '../Bookshelf';

const BookArchiveForUnAuth = () => {
const { data, isSuccess, isLoading } = useUnAuthRecommendedBookshelfQuery();
Expand All @@ -17,19 +17,14 @@ const BookArchiveForUnAuth = () => {
if (!isSuccess) return null;

return (
<Flex direction="column" width="100%" gap="3rem">
{data.bookshelfResponses.map(
({ bookshelfId, bookshelfName, books, likeCount }) => (
<RecommendedBookshelf
key={bookshelfId}
bookshelfId={bookshelfId}
bookshelfName={bookshelfName}
books={books}
likeCount={likeCount}
/>
)
)}
</Flex>
<div className="flex flex-col gap-[1.5rem] w-full">
<div className="text-md font-bold">🔥 인기 책장</div>
<div className="flex w-full flex-col gap-[3rem]">
{data.bookshelfResponses.map(bookshelf => (
<Bookshelf key={bookshelf.bookshelfId} {...bookshelf} />
))}
</div>
</div>
);
};

Expand Down
67 changes: 67 additions & 0 deletions src/ui/Bookshelf/Book.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use client';

import { APIBook } from '@/types/book';
import ColorThief from 'colorthief';
import Image from 'next/image';
import Link from 'next/link';
import { useState } from 'react';

const BookInBookshelf = ({
imageUrl,
bookId,
}: Pick<APIBook, 'bookId' | 'title' | 'imageUrl'>) => {
const [bookSpineColor, setBookSpineColor] = useState<string>();

const handleOnLoadImage = (image: HTMLImageElement) => {
const colorThief = new ColorThief();
const colorHex = colorThief
.getPalette(image, 2)[0]
.map(x => x.toString(16).padStart(2, '0'))
.join('');
setBookSpineColor(`#${colorHex}`);
};

return (
<div
className="relative flex"
style={{
visibility: bookSpineColor ? 'visible' : 'hidden',
transformStyle: 'preserve-3d',
transform: 'perspective(140px)',
}}
>
<div
className="h-full w-[1.5rem]"
style={{
backgroundColor: bookSpineColor,
transform: 'rotateY(320deg) translateX(1rem) translateZ(0.4rem)',
}}
/>
<div
className="absolute bottom-0 h-2 w-[calc(100%-1.5rem)] shadow-[1px_4px_10px_4px_#b1b1b1]"
style={{
transform: 'rotateY(20deg) translateX(1.25rem) translateZ(-0.5rem)',
}}
/>
<Link
className="relative"
href={`/book/${bookId}`}
style={{
transform: 'rotateY(22deg) translateZ(0.3rem)',
}}
>
<Image
className="h-auto w-auto"
src={imageUrl}
width={120}
height={110}
alt="book cover"
onLoadingComplete={handleOnLoadImage}
quality={100}
/>
</Link>
</div>
);
};

export default BookInBookshelf;
44 changes: 44 additions & 0 deletions src/ui/Bookshelf/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { APIBookshelf } from '@/types/bookshelf';
import { IconArrowRight, IconHeart } from '@public/icons';
import Link from 'next/link';
import Badge from '../Base/Badge';
import BookInBookshelf from './Book';

const Bookshelf = ({
bookshelfId,
bookshelfName,
books,
likeCount,
}: APIBookshelf) => {
return (
<div className="relative rounded-[2rem] pb-[2.5rem] pt-[2rem] shadow-[0px_0px_10px_0px_#D1D1D1]">
<div className="absolute bottom-0 w-full">
<div className="h-[3rem] bg-[#F2ECDF] shadow-[0px_-3px_8px_0px_#F1F1F1_inset]" />
<div className="h-[1rem] rounded-b-[2rem] bg-[#F6F3EC] shadow-[0px_-1px_8px_-4.5px_#494949]" />
</div>
<div className="flex flex-col gap-[2.6rem] bg-white px-[2rem]">
<div className="flex flex-col gap-[1rem]">
<div className="flex items-center justify-between">
<div className="text-md font-bold">{bookshelfName}</div>
<Link href={`/bookshelf/${bookshelfId}`}>
<IconArrowRight width="1.8rem" height="1.8rem" />
</Link>
</div>
<Badge colorScheme="red" fontWeight="bold" size="small">
<div className="flex items-center gap-[0.4rem]">
<IconHeart fill="white" height="1.3rem" w="1.3rem" />
<div className="bold text-xs">{likeCount}</div>
</div>
</Badge>
</div>
<div className="flex justify-between px-[0.5rem]">
{books.map(book => (
<BookInBookshelf key={book.bookId} {...book} />
))}
</div>
</div>
</div>
);
};

export default Bookshelf;
8 changes: 4 additions & 4 deletions src/ui/InteractiveBook/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const InteractiveBook = ({ imageUrl, bookId }: InteractiveBookProps) => {
cursor={bookId ? 'pointer' : 'auto'}
>
<Box
w="8.5rem"
w="8.0rem"
h="11rem"
transform="rotateY(30deg) translateX(1rem)"
boxSizing="border-box"
Expand All @@ -61,7 +61,7 @@ const InteractiveBook = ({ imageUrl, bookId }: InteractiveBookProps) => {
h="1rem"
pos="absolute"
bottom={0}
transform={`translateZ(-3rem)`}
transform={`translateZ(-2.5rem)`}
boxShadow="1px -4px 20px 3px"
/>
<Image
Expand All @@ -73,10 +73,10 @@ const InteractiveBook = ({ imageUrl, bookId }: InteractiveBookProps) => {
quality={100}
/>
<Box
w="3rem"
w="2.5rem"
h="100%"
bgColor={bookSpineColor}
transform="rotateY(-90deg) translateX(-1.49rem) translateZ(1.5rem)"
transform="rotateY(-90deg) translateX(-1.49rem) translateZ(1.15rem)"
/>
</Box>
</Flex>
Expand Down

0 comments on commit 08c919d

Please sign in to comment.