diff --git a/src/components/gauge/block-gauge.stories.tsx b/src/components/gauge/block-gauge.stories.tsx new file mode 100644 index 00000000..17e3439c --- /dev/null +++ b/src/components/gauge/block-gauge.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from "@storybook/nextjs"; +import { useState } from "react"; +import BlockGauge, { type GaugeLevel } from "./block-gauge"; + +const meta: Meta = { + title: "Components/BlockGauge", + component: BlockGauge, + parameters: { + layout: "centered", + docs: { + description: { + component: + "와인의 맛 강도를 시각적으로 표현하는 블록 게이지 컴포넌트입니다.", + }, + }, + }, + tags: ["autodocs"], + argTypes: { + level: { + control: { type: "number", min: 0, max: 6 }, + description: "게이지 레벨 (0-6)", + defaultValue: 3, + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +}; + +export default meta; + +type Story = StoryObj; + +export const ClickTest: Story = { + render: () => { + const [level, setLevel] = useState(3); + + return ( +
+

레벨: {level}

+ +
+ ); + }, +}; diff --git a/src/components/gauge/block-gauge.tsx b/src/components/gauge/block-gauge.tsx new file mode 100644 index 00000000..e7781104 --- /dev/null +++ b/src/components/gauge/block-gauge.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { cn } from "@/lib/utils"; + +type GaugeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6; + +interface BlockGaugeProps { + level: GaugeLevel; // 0-6 사이의 값 (0: 비어있음, 6: 가득 참) + color?: string; // 활성화된 블록 색상 (기본: bg-black) + onChange?: (newLevel: GaugeLevel) => void; // 클릭 시 호출될 함수 +} + +const BlockGauge = ({ + level, + color = "bg-black", + onChange, +}: BlockGaugeProps) => { + const handleClick = (clickedIndex: number) => { + if (!onChange) return; + + const newLevel = (clickedIndex + 1) as GaugeLevel; + onChange(newLevel === level ? 0 : newLevel); + }; + + return ( +
+ {Array.from({ length: 6 }).map((_, index) => ( +
+ ); +}; + +export default BlockGauge; + +export type { GaugeLevel }; diff --git a/src/components/taste/Taste.stories.tsx b/src/components/taste/Taste.stories.tsx new file mode 100644 index 00000000..17b7e672 --- /dev/null +++ b/src/components/taste/Taste.stories.tsx @@ -0,0 +1,157 @@ +import type { Meta, StoryObj } from "@storybook/nextjs"; +import { useState } from "react"; +import Taste from "./Taste"; +import { cn } from "@/lib/utils"; +import { GaugeLevel } from "../gauge/block-gauge"; + +const meta: Meta = { + title: "Components/Taste", + component: Taste, + parameters: { + layout: "centered", + docs: { + description: { + component: + "와인의 맛 특성과 강도를 표시하는 컴포넌트입니다. 모바일 : 343px, 태블릿과 PC : 480px", + }, + }, + }, + tags: ["autodocs"], + argTypes: { + type: { + control: "text", + description: "와인 맛의 종류", + defaultValue: "바디감", + }, + data: { + control: { type: "number", min: 0, max: 6 }, + description: "맛 강도 데이터 (0-6)", + defaultValue: 3, + }, + taste: { + control: "text", + description: "맛의 특징", + defaultValue: "진해요", + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +const ResponsiveTasteWrapper = ({ + children, +}: { + children: React.ReactNode; +}) => { + return ( +
+ {children} +
+ ); +}; + +export const InteractiveWineProfile: Story = { + render: () => { + const [bodyLevel, setBodyLevel] = useState(4); + const [tanninLevel, setTanninLevel] = useState(2); + const [sweetnessLevel, setSweetnessLevel] = useState(1); + const [acidityLevel, setAcidityLevel] = useState(3); + + return ( +
+
+ + + + + + + + + + + + + + + +
+ + {/* 현재 설정값 표시 */} +
+ 현재 와인 프로필: 바디감 {bodyLevel}, 탄닌{" "} + {tanninLevel}, 당도 {sweetnessLevel}, 산미 {acidityLevel} +
+
+ ); + }, + parameters: { + layout: "padded", + docs: { + description: { + story: + "블럭을 마우스로 클릭하면 게이지가 차오릅니다. 또한 어느 블럭이든 두 번 클릭하면 게이지가 0으로 됩니다.", + }, + }, + }, +}; diff --git a/src/components/taste/Taste.tsx b/src/components/taste/Taste.tsx new file mode 100644 index 00000000..02a68982 --- /dev/null +++ b/src/components/taste/Taste.tsx @@ -0,0 +1,55 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import BlockGauge, { type GaugeLevel } from "../gauge/block-gauge"; + +interface TasteProps { + type: string; + data: GaugeLevel; // 0-6 사이의 값 + taste: string; + onChange?: (newLevel: GaugeLevel) => void; +} + +const Taste = ({ type, data, taste, onChange }: TasteProps) => { + return ( +
+
+ {/* 왼쪽: type */} +
+ {type} +
+ + {/* 중간: 게이지 */} +
+ +
+ + {/* 오른쪽: taste - data가 0일 때 색상 변경 */} +
+ {taste} +
+
+
+ ); +}; + +export default Taste; diff --git a/tailwind.config.ts b/tailwind.config.ts index 93070bc2..07e25202 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -18,6 +18,8 @@ export default { gray600: "#8C8C8B", gray800: "#484746", primary: "#1A1918", + neutral200: "#F2F2F2", + neutral400: "#BABABA", }, screens: { mobile: { max: "743px" },