Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: "\U0001F41E 버그 리포트 템플릿"
about: 프로젝트에서 발생하는 버그에 대해 명세합니다.
title: "[Bug] Issue title"
labels: "\U0001F41E BugFix"
assignees: ""
---

## 💬 버그 설명

문제가 생긴 상황을 간단히 설명해주세요.

## 🔁 재현 방법

문제가 어떻게 발생했는지 순서대로 작성해주세요.

## ⚙️ 기대 동작

정상적으로 어떤 동작을 기대했는지 설명해주세요.

## 📸 스크린샷 (선택사항)

## 📄 추가 정보

기타 참고할만한 정보나 자료가 있다면 자유롭게 작성해주세요.
7 changes: 5 additions & 2 deletions .github/ISSUE_TEMPLATE/🐞-버그-리포트-템플릿.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ name: "\U0001F41E 버그 리포트 템플릿"
about: 프로젝트에서 발생하는 버그에 대해 명세합니다.
title: "[Bug] Issue title"
labels: "\U0001F41E BugFix"
assignees: ''

assignees: ""
---

## 💬 버그 설명

문제가 생긴 상황을 간단히 설명해주세요.

## 🔁 재현 방법

문제가 어떻게 발생했는지 순서대로 작성해주세요.

## ⚙️ 기대 동작

정상적으로 어떤 동작을 기대했는지 설명해주세요.

## 📸 스크린샷 (선택사항)

## 📄 추가 정보

기타 참고할만한 정보나 자료가 있다면 자유롭게 작성해주세요.
3 changes: 3 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { StorybookConfig } from "@storybook/nextjs";

const config: StorybookConfig = {
stories: ["../src/**/*.stories.@(js|jsx|mdc|ts|tsx)"],
addons: ["@storybook/addon-a11y", "@storybook/addon-docs"],
Expand All @@ -20,5 +21,7 @@ const config: StorybookConfig = {
prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
},
},
staticDirs: ["../public"],
};

export default config;
Binary file added public/images/aroma-apple.jpg
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/images/aroma-berry.jpg
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/images/aroma-cherry.jpg
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/images/aroma-chocolate.jpg
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/images/aroma-citrus.jpg
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/images/aroma-coconut.jpg
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/images/aroma-flower.jpg
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/images/aroma-grass.jpg
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/images/aroma-herb.jpg
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/images/aroma-mineral.jpg
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/images/aroma-no-image.jpg
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/images/aroma-oak-cask.jpg
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/images/aroma-peach.jpg
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/images/aroma-toast.jpg
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/images/aroma-tropical.jpg
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/images/aroma-wet-soil.jpg
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/images/test/test_chip.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 35 additions & 2 deletions src/app/example/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,48 @@
import Header from "@/components/header/Header";
import { Chip, DropdownMenu, Flavor, Header } from "@/components";
import React from "react";

const Page = () => {
return (
<div>
<div className="flex-col-center gap-4">
<Header
review="5,446"
title="Sentinel Carbernet Sauvignon 2016"
description="Western Cape, South Africa"
price="64,990"
/>
<div className="flex-center gap-4">
<DropdownMenu />
</div>
<div className="flex-center gap-4">
<Chip label="후추" />
<Chip label="후추" img="/images/test/test_chip.jpg" />
</div>
<div>
<Flavor
count={5}
items={[
"CHERRY",
"OAK",
"VANILLA",
"PEPPER",
"BAKING",
"GRASS",
"APPLE",
"PEACH",
"CITRUS",
"TROPICAL",
"MINERAL",
"FLOWER",
"TOBACCO",
"EARTH",
"CHOCOLATE",
"SPICE",
"CARAMEL",
"LEATHER",
"EMPTY",
]}
/>
</div>
</div>
);
};
Expand Down
10 changes: 10 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,13 @@ body {
@apply flex flex-col items-center justify-center;
}
}

/* 스크롤바 숨기기 */
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}

.scrollbar-hide::-webkit-scrollbar {
display: none;
}
41 changes: 41 additions & 0 deletions src/components/chip/Chip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Meta, StoryObj } from "@storybook/nextjs";
import Chip from "./Chip";

const meta: Meta<typeof Chip> = {
title: "Components/Chip",
parameters: {
layout: "centered",
},
component: Chip,
tags: ["autodocs"],
decorators: [
(Story) => (
<div className="w-[66px]">
<Story />
</div>
),
],
};

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
label: "후추",
},
};

export const WithImage: Story = {
args: {
label: "후추",
img: "/images/test/test_chip.jpg",
},
decorators: [
(Story) => (
<div className="w-[100px]">
<Story />
</div>
),
],
};
43 changes: 43 additions & 0 deletions src/components/chip/Chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client";

import { cn } from "@/lib/utils";
import Image from "next/image";
import { useState } from "react";

interface ChipProps {
img?: string;
label: string;
}

const Chip = ({ img, label }: ChipProps) => {
const [selected, setSelected] = useState(false);

return (
<div
data-selected={selected}
className={cn(
"flex-center h-[38px] cursor-pointer rounded-full border text-body-sm tracking-[-0.02em]",
"transition-colors duration-150 ease-in-out hover:bg-gray100 hover:text-black",
"data-[selected=true]:bg-gray800 data-[selected=true]:text-white data-[selected=true]:hover:bg-gray800 data-[selected=true]:hover:text-white",
"pc:h-[48px] pc:text-body-md",
img
? "gap-2 pl-2 pr-4 mobile:gap-[6px] mobile:pr-3"
: "px-[18px] mobile:px-3"
)}
onClick={() => setSelected(!selected)}
>
Comment on lines 12 to 29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 버튼 컴포넌트가 없어 임시로 작업해두신걸까요? 클릭 가능한 요소라면 접근성 개선을 위해 <button> 태그로 개선해도 좋을 것 같습니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다 반영했습니다!

{img && (
<Image
src={img}
alt={`${label} 이미지`}
width={32}
height={32}
className="h-8 w-8 rounded-full mobile:h-6 mobile:w-6"
/>
)}
<span>{label}</span>
</div>
);
};

export default Chip;
19 changes: 19 additions & 0 deletions src/components/dropdown-menu/DropdownMenu.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Meta, StoryObj } from "@storybook/nextjs";
import DropdownMenu from "./DropdownMenu";

const meta: Meta<typeof DropdownMenu> = {
title: "Components/DropdownMenu",
component: DropdownMenu,
tags: ["autodocs"],
parameters: {
layout: "centered",
},
};

export default meta;

type Story = StoryObj<typeof DropdownMenu>;

export const Default: Story = {
args: {},
};
53 changes: 53 additions & 0 deletions src/components/dropdown-menu/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils";

const style = {
itemBase:
"flex-center h-full w-full rounded-md text-[16px] leading-[26px] text-gray800 transition-colors hover:bg-whiteHover active:bg-gray200",
};

function DropdownMenu() {
const pathname = usePathname();

const isActive = (href?: string) => Boolean(href && pathname === href);

const items: { label: string; href?: string; onClick?: () => void }[] = [
{ label: "마이페이지", href: "/my-page" },
{ label: "로그아웃", onClick: () => console.log("logout") },
];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 드롭다운은 마이페이지와 로그아웃을 표출하는 부분에서만 사용가능할 것 같습니다.
수정하기, 삭제하기 버튼이 있는 드롭다운도 같이 사용할 수 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피그마 컴포넌트에선 마이페이지, 로그아웃만 나와있어서 고려하지 못했습니다.
해당 부분 수정해서 PR 업데이트 하겠습니다!


return (
<div
className={cn(
"flex-col-center rounded-[4px] border border-gray300 p-[3px] shadow-md",
"h-[92px] w-[101px]",
"tablet:h-[90px] tablet:w-[126px]",
"pc:h-[90px] pc:w-[126px]"
)}
>
{items.map(({ label, href, onClick }) =>
href ? (
<Link
key={label}
href={href}
className={cn(
style.itemBase,
isActive(href) && "bg-gray800 text-white"
)}
>
{label}
</Link>
) : (
<button key={label} onClick={onClick} className={style.itemBase}>
{label}
</button>
)
)}
</div>
);
}

export default DropdownMenu;
45 changes: 45 additions & 0 deletions src/components/flavor/Flavor.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Meta, StoryObj } from "@storybook/nextjs";
import Flavor from "./Flavor";
import { AromaKey } from "@/types/AromaType";

const meta: Meta<typeof Flavor> = {
title: "Components/Flavor",
component: Flavor,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
argTypes: {
count: { control: "number", description: "참여 인원 수 표시" },
items: {
control: "object",
description: "향 아이템 키 목록 (AromaKey[])",
},
},
};

export default meta;
type Story = StoryObj<typeof Flavor>;

const ITEMS: AromaKey[] = ["CHERRY", "PEPPER", "EMPTY"];

export const Default: Story = {
args: {
count: 12,
items: ITEMS.slice(0, 1),
},
};

export const ThreeItems: Story = {
args: {
count: 3,
items: ITEMS,
},
};

export const Empty: Story = {
args: {
count: 0,
items: [],
},
};
53 changes: 53 additions & 0 deletions src/components/flavor/Flavor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { AromaKey } from "@/types/AromaType";
import Image from "next/image";
import { aromaMap } from "./aroma-map";

interface FlavorItemProps {
aroma: AromaKey;
}

const FlavorItem = ({ aroma }: FlavorItemProps) => {
const { img, label } = aromaMap[aroma];
return (
<div className="flex shrink-0 flex-col items-center gap-[14px] tablet:w-[100px] pc:w-[100px]">
<Image
src={img}
alt={label}
width={90}
height={90}
className="rounded-4 h-[90px] w-full tablet:h-[100px] pc:h-[100px]"
/>
<span className="text-body-md tracking-[-0.02em]">{label}</span>
</div>
);
};

interface FlavorProps {
count: number;
items: AromaKey[];
}

const Flavor = ({ count, items }: FlavorProps) => {
return (
<div className="flex min-h-[197px] w-full flex-col items-start justify-between gap-[17px]">
<div>
<h2 className="text-heading-lg tracking-[-0.48px] text-[#31302F]">
어떤 향이 있나요?
</h2>
<span className="text-body-sm tracking-[-0.28px] text-[#BABABA]">
(<span>{count}</span>명 참여)
</span>
</div>

<div className="scrollbar-hide w-[calc(3*90px+2*14px+16px)] overflow-x-auto tablet:w-[calc(4*100px+2*14px+2*16px)] pc:w-[calc(4*100px+2*14px+2*16px)]">
<div className="flex flex-nowrap gap-4">
{items.map((item, index) => (
<FlavorItem aroma={item} key={index} />
))}
</div>
</div>
</div>
);
};

export default Flavor;
Loading