Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -11,6 +12,7 @@ const config: StorybookConfig = {
},
},
},
staticDirs: ["../public"],
typescript: {
check: false,
reactDocgen: "react-docgen-typescript",
Expand All @@ -36,4 +38,5 @@ const config: StorybookConfig = {
return config;
},
};

export default config;
Binary file added public/images/aroma/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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.
61 changes: 58 additions & 3 deletions src/app/example/page.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,76 @@
"use client";

import { SelectType } from "@/components";
import Header from "@/components/header/Header";
import { Chip, DropdownMenu, Flavor, Header, SelectType } from "@/components";
import React, { ChangeEvent } from "react";

const Page = () => {
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value);
};
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
items={[
{ label: "마이페이지", href: "/my-page" },
{ label: "로그아웃", onClick: () => console.log("로그아웃") },
]}
/>
<DropdownMenu
items={[
{ label: "example", href: "/example" },
{ label: "임시", onClick: () => console.log("임시") },
]}
/>
<DropdownMenu
items={[
{ label: "수정하기", onClick: () => console.log("수정하기") },
{ label: "삭제하기", onClick: () => console.log("삭제하기") },
]}
/>
<DropdownMenu
items={[
{ label: "메인페이지", href: "/" },
{ label: "버튼클릭", onClick: () => console.log("버튼클릭") },
]}
/>
</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>

<section>
<SelectType isError={false} onChange={handleChange} />
Expand Down
10 changes: 10 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,13 @@ body {
/* stroke: currentColor; */
}
}

/* 스크롤바 숨기기 */
.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>
),
],
};
44 changes: 44 additions & 0 deletions src/components/chip/Chip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"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 (
<button
data-selected={selected}
aria-pressed={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-gray-100 hover:text-black",
"data-[selected=true]:bg-gray-800 data-[selected=true]:text-white data-[selected=true]:hover:bg-gray-800 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)}
>
{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>
</button>
);
};

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

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

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
items: [
{ label: "마이페이지", href: "/my-page" },
{ label: "로그아웃", onClick: () => console.log("로그아웃") },
],
},
};

export const EditDelete: Story = {
parameters: { nextjs: { navigation: { pathname: "/write" } } },
args: {
items: [
{ label: "수정하기", onClick: () => console.log("수정하기") },
{ label: "삭제하기", onClick: () => console.log("삭제하기") },
],
},
};
52 changes: 52 additions & 0 deletions src/components/dropdown-menu/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client";

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

interface DropdownMenuProps {
items: { label: string; href?: string; onClick?: () => void }[];
}

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

function DropdownMenu({ items }: DropdownMenuProps) {
const pathname = usePathname();

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

return (
<div
className={cn(
"flex-col-center rounded-[4px] border border-gray-300 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-gray-800 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: [],
},
};
Loading