Skip to content
Merged
1,066 changes: 936 additions & 130 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
"axios": "^1.10.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"embla-carousel-react": "^8.6.0",
"lucide-react": "^0.525.0",
"next": "13.5.11",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.59.0",
Expand All @@ -50,14 +50,15 @@
"@typescript-eslint/parser": "^6.21.0",
"autoprefixer": "^10",
"eslint": "^8.57.1",
"eslint-config-next": "13.5.11",
"eslint-config-next": "^13.5.11",
"eslint-config-prettier": "^10.1.5",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"husky": "^9.1.7",
"lint-staged": "^16.1.2",
"next": "^13.5.11",
"tailwindcss": "^3.4.4",
"typescript": "~5.3.0"
},
Expand Down
14 changes: 14 additions & 0 deletions public/images/image1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions public/images/image2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions public/images/image3.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions public/images/image4.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/Next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/SearchButton.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/Star.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions src/components/common/winelist/WineCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';

import Link from 'next/link';

import StarIcon from '@/assets/icons/Star.svg';
import { ImageCard } from '@/components/common/card/ImageCard';
import { cn } from '@/lib/utils';

interface WineCardProps {
id: number;
image: string;
name: string;
rating: number;
}

export default function WineCard({ id, image, name, rating }: WineCardProps) {
return (
<Link href={`/wines/${id}`} key={id} className='no-underline'>
<div
className={cn(
'flex h-[160px] bg-white p-2 border border-gray-200 ',
'rounded-[12px]',
'shadow-[0px_2px_20px_0px_rgba(0,0,0,0.04)]',
'md:w-[232px] md:h-[185px]',
)}
>
{/* μ™Όμͺ½: 이미지 μΉ΄λ“œ */}
<div className='flex-shrink-0'>
<ImageCard
imageSrc={image}
className='p-0 border-none bg-transparent w-[80px] h-[112px]'
imageClassName='w-[38px] h-[136px] ml-[10px] rounded-md object-cover mt-[14px] md:w-[44px] md:h-[155px] md:mt-[20px] md:ml-[20px]'
/>
</div>

{/* 였λ₯Έμͺ½: 평점 + 별점 + 이름 */}
<div className='w-[80px] h-[97px] flex flex-col justify-start mt-[10px] ml-[5px] md:w-[100px] md:h-[125px] md:ml-[20px]'>
<div className='text-[28px] font-extrabold leading-100% text-gray-800 md:text-[36px] '>
{rating.toFixed(1)}
</div>
<div className='flex gap-[4px] w-[60px] h-[12px] -mt-[2px] md:w-[90px] md:h-[18px]'>
{Array.from({ length: 5 }).map((_, i) => (
<StarIcon
key={i}
className={cn(
rating >= i + 1 ? 'fill-purpleDark' : 'fill-gray-300',
'w-[12px] h-[12px] md:w-[18px] md:h-[18px]',
)}
/>
))}
</div>
<p className='text-[10px] leading-[140%] text-gray-500 mt-[10px] md:custom-text-xs-regular'>
{name}
</p>
</div>
</div>
</Link>
);
}
120 changes: 120 additions & 0 deletions src/components/common/winelist/WineFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import SearchButton from '@/assets/icons/SearchButton.svg';
import WineTypeFilter from '@/components/common/Filter/WineTypeFilter';
import Input from '@/components/common/Input';
import WineListCard from '@/components/common/winelist/WineListCard';
import { Button } from '@/components/ui/button';

export default function WineFilter() {
// const [isFilterOpen, setIsFilterOpen] = useState(false);

return (
<div className='w-full max-w-[1140px] mx-auto'>
{/* PC: ν•„ν„° + 검색창 + 등둝 λ²„νŠΌ */}
<div className='hidden xl:flex max-w-[1140px] mx-auto mt-[30px] gap-[24px]'>
<div className='flex-shrink-0 w-[260px] h-auto flex flex-col gap-[50px] ml-[-28px]'>
<div className='pt-[70px] '>
<WineTypeFilter className='h-[450px]' />
</div>
<Button
variant='purpleDark'
size='md'
width={null}
className='ml-[30px] mb-[200px] w-[284px]'
>
와인 λ“±λ‘ν•˜κΈ°
</Button>
</div>

<div className='flex-1 flex flex-col items-end gap-[18px] text-gray-500 [&_label]:top-[10px] md:[&_label]:top-[14px] xl:[&_label]:top-[14px]'>
<Input
id='wine-search'
type='text'
placeholder='와인을 검색해 λ³΄μ„Έμš”'
variant='search'
className='
xl:w-[800px] h-[48px] px-[20px] py-[14px] pl-[55px]
border border-gray-300 rounded-full
'
/>
{/* WineListCard PCμ—μ„œλ§Œ λ…ΈμΆœ */}
<div className='hidden xl:flex pt-[20px]'>
<WineListCard />
</div>
</div>
</div>

{/* Tablet: ν•„ν„° λ²„νŠΌ + 검색창 + 등둝 λ²„νŠΌ */}
<div className='hidden md:flex xl:hidden flex-row items-center px-[20px] mt-[24px] md:mt-[50px] md:mb-[80px]'>
<Button
// onClick={() => setIsFilterOpen(true)}
variant='white'
size={null}
width={null}
className='flex items-center justify-center border border-gray-300 w-[48px] h-[48px] rounded-[8px] p-0'
>
<SearchButton className='w-[20px] h-[20px] text-gray-500' />
</Button>

<div className='flex-grow ml-[24px] text-gray-500 [&_label]:top-[14px]'>
<Input
id='wine-search'
type='text'
placeholder='와인을 검색해 λ³΄μ„Έμš”'
variant='search'
className='
md:w-full w-full
h-[48px] px-[20px] py-[14px] pl-[55px]
border border-gray-300 rounded-full
'
/>
</div>

<Button
variant='purpleDark'
size={null}
width={null}
className='w-[220px] h-[48px] rounded-[16px] flex-shrink-0 ml-[16px]'
>
와인 λ“±λ‘ν•˜κΈ°
</Button>
</div>

{/* Mobile: 검색창 + ν•„ν„° λ²„νŠΌ */}
<div className='flex flex-col md:hidden gap-[8px] px-[16px] mt-[24px]'>
<div className='text-gray-500 [&_label]:top-[10px]'>
<Input
id='wine-search'
type='text'
placeholder='와인을 검색해 λ³΄μ„Έμš”'
variant='search'
className='w-full h-[38px] px-[15px] py-[14px] pl-[55px] border border-gray-300 rounded-full'
/>
</div>

<div className='w-fit mt-[15px] mb-[20px]'>
<Button
// onClick={() => setIsFilterOpen(true)}
variant='white'
size='sm'
width='xs'
className='flex items-center justify-center border border-gray-300 w-[38px] h-[38px] p-0'
>
<SearchButton className='w-[20px] h-[20px] text-gray-500' />
</Button>
</div>
</div>

{/* Mobile: ν•˜λ‹¨ κ³ μ • 등둝 λ²„νŠΌ */}
<div className='fixed bottom-[20px] left-0 right-0 z-10 px-[16px] md:hidden'>
<Button
variant='purpleDark'
size='sm'
width='full'
className='w-full h-[48px] rounded-[12px] text-sm'
>
와인 λ“±λ‘ν•˜κΈ°
</Button>
</div>
</div>
);
}
Loading