Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
31c6320
feat: [wineid]ui๊ตฌํ˜„+๋ฆฌ๋ทฐ์นด๋“œ ์ˆ˜์น˜์กฐ์ •
626-ju Jul 22, 2025
61a4e6e
fix: gnb z์ธ๋ฑ์Šค ์œ„์น˜ ์ˆ˜์ •
626-ju Jul 22, 2025
d36663d
feat: shadcn progress์ถ”๊ฐ€
626-ju Jul 22, 2025
97cfb38
feat:ํ”„๋กœ๊ทธ๋ ˆ์Šค ui์ถ”๊ฐ€
626-ju Jul 22, 2025
2e45e7d
refactor: WineRating.tsx ๋ฐฐ์น˜ ๊ฐœ์„ 
626-ju Jul 23, 2025
6996733
Merge branch 'dev' into feature/wineid
626-ju Jul 23, 2025
c904f73
feat:ํ‰๊ท ๋ณ„์  ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€ + ๋ณ„์  ๋ฑƒ์ง€ ๋‚ด๋ถ€๊ฐ„๊ฒฉ ์†Œํญ ์กฐ์ •
626-ju Jul 23, 2025
275c726
Merge branch 'dev' into feature/wineid
626-ju Jul 23, 2025
6a07a20
feat: FlavorSliderList ์ถ”๊ฐ€+์ผ€๋ฐฅ+์ข‹์•„์š”๋ฒ„ํŠผ ์ถ”๊ฐ€
626-ju Jul 23, 2025
b6d0cd7
feat: ReviewCard์ปดํฌ๋„ŒํŠธ์— useClickToggle ํ›… ์ถ”๊ฐ€ํ•˜๊ธฐ
626-ju Jul 23, 2025
e769a1b
feat: ์นด๋“œ ์—ด๊ณ  ๋‹ซ๊ณ  ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€
626-ju Jul 23, 2025
f8b1e8d
style: ํฌ๋งทํŒ…
626-ju Jul 23, 2025
e9fe01b
refactor: ํ…Œ์ŠคํŠธ์šฉ ๋”๋ฏธ ํŒŒ์ผ ๋ถ„๋ฆฌ
626-ju Jul 24, 2025
813f3e5
refactor: 1์ฐจ qa ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜
626-ju Jul 24, 2025
4c0cbe9
build: svgํŒŒ์ผ๋“ค ํด๋” ๋ณ€๊ฒฝ์— ๋”ฐ๋ฅธ ์ž„ํฌํŠธ ๊ฒฝ๋กœ ์ˆ˜์ •
626-ju Jul 24, 2025
dca39e1
Merge branch 'dev' into feature/wineid
626-ju Jul 24, 2025
91064d0
chore: ๋ถˆํ•„์š”ํ•œ ์ฃผ์„ ์ œ๊ฑฐ
626-ju Jul 24, 2025
fc5f8c1
feat: ์ผ€๋ฐฅ์— ์ถ”๊ฐ€ ๋“œ๋ž๋‹ค์šด ์ถ”๊ฐ€+์ถ”ํ›„ ์œ ์ง„๋‹˜ ๊ป„๋กœ ๊ต์ฒด
626-ju Jul 24, 2025
e4007fc
feat: og ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
626-ju Jul 24, 2025
49419ad
fix: env๋“ค์–ด๊ฐ„ ๊ฑฐ ๋นผ๊ธฐ
626-ju Jul 24, 2025
16d5e45
fix:og์ด๋ฏธ์ง€ ๋ˆ„๋ฝ ์ˆ˜์ •
626-ju Jul 24, 2025
60ab8e4
refactor(mentor): hidden->sr-only
626-ju Jul 24, 2025
a04e9a4
refactor(mentor): ๋ฆฌ๋ทฐ์นด๋“œ -> ์ฃผ์Šคํƒ„๋“œ๊ธฐ๋ฐ˜ ํ•ฉ์„ฑ์ปดํฌ๋„ŒํŠธ
626-ju Jul 24, 2025
d62a492
fix: ํ…์ŠคํŠธ์— ์ ์šฉ๋˜๋Š” ํŠธ๋žœ์ง€์…˜ ์ œ๊ฑฐ
626-ju Jul 24, 2025
4b8c7bd
chore: ์„ค๋ช… ์ฃผ์„ ์ถ”๊ฐ€
626-ju Jul 25, 2025
2e26ed2
chore: ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” useClickToggle.tsx์‚ญ์ œ(hooksํด๋”๋„ ๊ฐ™์ด)
626-ju Jul 25, 2025
8f8152a
chore:์Šคํ…Œ์ด์ง• ๋ˆ„๋ฝ๋œ ํŒŒ์ผ ์ถ”๊ฐ€
626-ju Jul 25, 2025
ee8b03d
Merge branch 'dev' into feature/wineid
626-ju Jul 25, 2025
26d2e5c
refactor:wineid ์ด๋ฏธ์ง€ ์นด๋“œ ๊ทธ๋ผ๋ฐ์ด์…˜ ์ถ”๊ฐ€+์ฒ˜์Œ ๋ฆฌ๋ทฐ๋Š” ์—ด๋ฆฌ๊ฒŒ
626-ju Jul 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-radio-group": "^1.3.7",
"@radix-ui/react-slider": "^1.3.5",
"@radix-ui/react-slot": "^1.2.3",
Expand All @@ -33,6 +34,7 @@
"react-hook-form": "^7.59.0",
"tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"use-sync-external-store": "^1.5.0",
"zod": "^4.0.5",
"zustand": "^5.0.5"
},
Expand Down
Binary file added public/og-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/wineImg.png
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/fullLike.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/kebab.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/like.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
3 changes: 3 additions & 0 deletions src/assets/icons/showMoreBtn.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.
4 changes: 2 additions & 2 deletions src/components/common/Gnb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import UserDefaultImg from './UserDefaultImg';
function Gnb() {
return (
//inset-x-0 -> x์ถ•:left,right๋‘˜ ๋‹ค 0
<header className='fixed top-0 inset-x-0 mx-auto px-[16px] md:px-[20px] xl:px-0 max-w-[1140px] min-w-[343px]'>
<nav className=' z-50 flex justify-between items-center bg-black w-full h-[50px] md:h-[70px] rounded-[12px] md:rounded-[16px] mt-[16px] md:mt-[24px] px-[20px] md:px-[60px]'>
<header className='z-50 fixed top-0 inset-x-0 mx-auto px-[16px] md:px-[20px] xl:px-0 max-w-[1140px] min-w-[343px]'>
<nav className='flex justify-between items-center bg-black w-full h-[50px] md:h-[70px] rounded-[12px] md:rounded-[16px] mt-[16px] md:mt-[24px] px-[20px] md:px-[60px]'>
<Logo />
<AuthMenu />
</nav>
Expand Down
5 changes: 2 additions & 3 deletions src/components/common/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// ์ƒค๋“œcn์€ ์•„๋‹Œ๋ฐ ์กฐํ•ฉํ•ด์„œ ์“ธ ๊ฒƒ ๊ฐ™์•„์„œ components/ui์— ๋„ฃ์–ด๋’€์Šต๋‹ˆ๋‹ค.
import React, { forwardRef, InputHTMLAttributes } from 'react';

// import { FieldValues, UseFormReturn } from 'react-hook-form';
import SearchIcon from '@/assets/search.svg';
import SearchIcon from '@/assets/icons/search.svg';
import { cn } from '@/lib/utils';

interface Props extends React.ComponentProps<'input'> {
Expand Down Expand Up @@ -63,7 +62,7 @@ Input.displayName = 'Input';

//md 768์ด์ƒ xl 1280์ด์ƒ
const variantStyles = {
base: ' rounded-[16px] bg-white border border-gray-300 outline-none active:border-gray-500 focus:border-gray-500 font-sans',
base: 'rounded-[16px] bg-white border border-gray-300 outline-none active:border-gray-500 focus:border-gray-500 font-sans',
default: 'px-[20px] py-[11px] w-[303px] md:w-[400px]',
search: 'w-[210px] py-[7px] px-[45px] rounded-[50px] md:w-[400px]',
name: 'px-[20px] py-[11px] w-full',
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import Link from 'next/link';

import LogoIcon from '@/assets/logo.svg';
import LogoIcon from '@/assets/icons/logo.svg';
import { cn } from '@/lib/utils';

interface Props {
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/UserDefaultImg.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import DefaultImg from '@/assets/userDefaultImg.svg';
import DefaultImg from '@/assets/icons/userDefaultImg.svg';
import { cn } from '@/lib/utils';

interface Props {
Expand All @@ -9,7 +9,7 @@ interface Props {

function UserDefaultImg({ className }: Props) {
return (
<div className={cn('text-white w-[20px] md:w-[45px] h-[20px] md:h-[45px]', className)}>
<div className={cn('text-gray-100 w-[20px] md:w-[45px] h-[20px] md:h-[45px]', className)}>
<DefaultImg />
</div>
);
Expand Down
156 changes: 100 additions & 56 deletions src/components/common/card/ReviewCard.tsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,114 @@
import React from 'react';

import ShowMoreBtn from '@/assets/icons/showMoreBtn.svg';
import Star from '@/assets/icons/star.svg';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import useReviewCardStore from '@/stores/reviewCardStore';

import {
ReviewCardProps,
UserHeaderProps,
TagAndRatingProps,
ReviewBodyProps,
ToggleButtonProps,
} from './ReviewCardTypes';

interface ReviewCardProps {
userIcon: React.ReactNode; // ์œ ์ € ์•„์ด์ฝ˜
username: string; // ์œ ์ € ์ด๋ฆ„
timeAgo: string; // ์ž‘์„ฑ ์‹œ๊ฐ„
tags: string[]; // ํƒœ๊ทธ ๋ชฉ๋ก
rating: React.ReactNode; // ๋ณ„์  ์˜์—ญ slot
likeSlot: React.ReactNode; // ์ข‹์•„์š” ๋ฒ„ํŠผ slot
menuSlot: React.ReactNode; // ๋ฉ”๋‰ด ๋ฒ„ํŠผ slot
reviewText?: string; // ๋ฆฌ๋ทฐ ๋ชฉ๋ก
flavorSliderSlot?: React.ReactNode; // ์Šฌ๋ผ์ด๋”
className?: string; // ์ปจํ…Œ์ด๋„ˆ ํด๋ž˜์Šค
/*
์—ฌ๊ธฐ ์ € ํ˜ผ์ž๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™์•„์„œ
์ œ๊ฐ€ ์ž„์˜๋กœ ๊ฑด๋“œ๋ ธ์Šต๋‹ˆ๋‹ค.
ํ˜น์‹œ ๋‹ค๋ฅธ ๋ถ„๋“ค๋„ ์“ฐ๊ฒŒ ๋œ๋‹ค๋ฉด ๋ง์”€ํ•ด์ฃผ์„ธ์š”
*/
export function ReviewCard({ children }: ReviewCardProps) {
return (
<div className='rounded-xl bg-white p-4 md:p-8 xl:p-4 xl:px-6 shadow-sm border border-gray-300 md:pb-6 xl:pb-5 w-full xl:w-[800px]'>
{children}
</div>
);
}

export function ReviewCard({
userIcon,
username,
timeAgo,
tags,
rating,
likeSlot,
menuSlot,
reviewText,
flavorSliderSlot,
className,
}: ReviewCardProps) {
ReviewCard.UserHeader = function UserHeader({ userIcon, reviewId, children }: UserHeaderProps) {
const username = useReviewCardStore((state) => state.allReviews[reviewId]?.user.name);
const timeAgo = useReviewCardStore((state) => state.allReviews[reviewId]?.updatedAt);

return (
<div
className={cn('w-full rounded-xl bg-white p-4 shadow-sm border border-gray-300', className)}
>
{/* ์ƒ๋‹จ: ์œ ์ € ์ •๋ณด & ์šฐ์ธก slot */}
<div className='flex justify-between items-start'>
<div className='flex items-center gap-3'>
<div className='w-8 h-8 rounded-full bg-gray-200 overflow-hidden'>{userIcon}</div>
<div className='flex flex-col'>
<span className='text-sm font-medium text-gray-900'>{username}</span>
<span className='text-xs text-gray-500'>{timeAgo}</span>
</div>
<div className='flex justify-between items-start'>
<div className='flex items-center gap-4'>
<div className='w-10 h-10 md:w-16 md:h-16 rounded-full bg-gray-200 overflow-hidden'>
{userIcon}
</div>

{/* ์ข‹์•„์š” & ๋ฉ”๋‰ด */}
<div className='flex items-center gap-2'>
{likeSlot}
{menuSlot}
<div className='flex flex-col'>
<span className='custom-text-lg-semibold text-gray-900'>{username}</span>
<span className='custom-text-md-regular text-gray-500'>{timeAgo}</span>
</div>
</div>

{/* ํƒœ๊ทธ & ๋ณ„์  */}
<div className='mt-3 flex justify-between items-center'>
<div className='flex flex-wrap gap-2'>
{tags.map((tag, idx) => (
<span key={idx} className='rounded-full bg-gray-100 px-3 py-1 text-xs text-gray-700'>
{tag}
</span>
))}
</div>
{rating}
{/* ์ข‹์•„์š” & ๋ฉ”๋‰ด */}
<div className='flex items-center gap-2'>{children}</div>
</div>
);
};

ReviewCard.TagAndRating = function TagAndRating({ reviewId }: TagAndRatingProps) {
const tags = useReviewCardStore((state) => state.allReviews[reviewId]?.aroma ?? []);
const rating = useReviewCardStore((state) => state.allReviews[reviewId]?.rating);
return (
<div className='mt-3 flex justify-between items-center'>
<div className='flex flex-wrap gap-2'>
{tags.map((tag) => (
<Badge
key={tag}
className='mt-4 rounded-full bg-white border-gray-300 px-[10px] py-[6px] md:px-[15px] md:py-2 custom-text-lg-regular text-gray-700'
variant='flavor'
>
{tag}
</Badge>
))}
</div>
<Badge variant='star' className='inline-flex gap-1 items-center'>
<Star className='size-3 md:size-4 md:mt-[-2px]' /> {rating}
</Badge>
</div>
);
};

{/* ๋ฆฌ๋ทฐ ํ…์ŠคํŠธ */}
{reviewText && <p className='mt-3 text-sm text-gray-800 leading-relaxed'>{reviewText}</p>}
ReviewCard.ReviewBody = function ReviewBody({ reviewId, flavorSliderSlot }: ReviewBodyProps) {
const reviewText = useReviewCardStore((state) => state.allReviews[reviewId]?.content);
const isOpen = useReviewCardStore((state) => state.allReviews[reviewId]?.isOpen);

{/* ์Šฌ๋ผ์ด๋” */}
{flavorSliderSlot && <div className='mt-4'>{flavorSliderSlot}</div>}
const cardTransition = cn('overflow-hidden transition-all duration-500 ease-in-out', {
'opacity-100 translate-y-0 max-h-[1000px]': isOpen,
'opacity-0 -translate-y-4 max-h-0': !isOpen,
});

if (!reviewText && !flavorSliderSlot) null;

return (
<div className={cardTransition}>
<p className='mt-9 text-[14px] md:text-[16px] leading-6 md:leading-[26px] text-gray-800'>
{reviewText}
</p>
<div className='mt-4 md:mt-6 xl:mt-5'>{flavorSliderSlot}</div>
</div>
);
}
};

ReviewCard.ToggleButton = function TogleButton({ reviewId }: ToggleButtonProps) {
const isOpen = useReviewCardStore((state) => state.allReviews[reviewId]?.isOpen);
const toggleReviewOpen = useReviewCardStore((state) => state.toggleReviewOpen);
return (
<Button
size={null} //๋ฒ„ํŠผ ๋””ํดํŠธ ๋ฎ์–ด์”Œ์šฐ๊ธฐ
width={null}
variant='onlyCancel'
onClick={() => toggleReviewOpen(reviewId)}
className={cn(
'border-0 mx-auto [&_svg]:w-[30px] [&_svg]:h-[30px] block transition-all duration-500 ease-in-out',
{
'scale-y-[-1] mt-0': isOpen,
},
)}
>
<ShowMoreBtn />
</Button>
);
};
32 changes: 32 additions & 0 deletions src/components/common/card/ReviewCardTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ReactNode } from 'react';

interface ReviewCardProps {
children: ReactNode;
}

interface UserHeaderProps {
userIcon: ReactNode;
reviewId: string;
children: ReactNode;
}

interface TagAndRatingProps {
reviewId: string;
}

interface ReviewBodyProps {
reviewId: string;
flavorSliderSlot: ReactNode;
}

interface ToggleButtonProps {
reviewId: string;
}

export type {
ReviewCardProps,
UserHeaderProps,
TagAndRatingProps,
ReviewBodyProps,
ToggleButtonProps,
};
24 changes: 24 additions & 0 deletions src/components/ui/progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from 'react';

import * as ProgressPrimitive from '@radix-ui/react-progress';

import { cn } from '@/lib/utils';

const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
>(({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root
ref={ref}
className={cn('relative h-2 w-full overflow-hidden rounded-full bg-primary/20', className)}
{...props}
>
<ProgressPrimitive.Indicator
className='h-full w-full flex-1 bg-primary transition-all'
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>
));
Progress.displayName = ProgressPrimitive.Root.displayName;

export { Progress };
Loading