diff --git a/public/images/wine-type/red.jpg b/public/images/wine-type/red.jpg new file mode 100644 index 00000000..d542027d Binary files /dev/null and b/public/images/wine-type/red.jpg differ diff --git a/public/images/wine-type/sparkling.jpg b/public/images/wine-type/sparkling.jpg new file mode 100644 index 00000000..5a78c31b Binary files /dev/null and b/public/images/wine-type/sparkling.jpg differ diff --git a/public/images/wine-type/white.jpg b/public/images/wine-type/white.jpg new file mode 100644 index 00000000..461ac82d Binary files /dev/null and b/public/images/wine-type/white.jpg differ diff --git a/src/app/example/page.tsx b/src/app/example/page.tsx index 7788dd01..89ae8e82 100644 --- a/src/app/example/page.tsx +++ b/src/app/example/page.tsx @@ -1,7 +1,13 @@ +"use client"; + +import { SelectType } from "@/components"; import Header from "@/components/header/Header"; -import React from "react"; +import React, { ChangeEvent } from "react"; const Page = () => { + const handleChange = (e: ChangeEvent) => { + console.log(e.target.value); + }; return (
{ description="Western Cape, South Africa" price="64,990" /> + +
+ +
+ +
); }; diff --git a/src/components/index.ts b/src/components/index.ts index eff89347..3cffee1d 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,2 +1,4 @@ export { default as Gnb } from "./gnb/Gnb"; export { default as Header } from "./header/Header"; +export { TextInput, ModalTextInput } from "./text-input/text-input"; +export { default as SelectType } from "./select-type/select-type"; diff --git a/src/components/select-type/select-type.stories.tsx b/src/components/select-type/select-type.stories.tsx new file mode 100644 index 00000000..b57c4338 --- /dev/null +++ b/src/components/select-type/select-type.stories.tsx @@ -0,0 +1,25 @@ +import { Meta, StoryObj } from "@storybook/nextjs"; +import SelectType from "./select-type"; + +const meta: Meta = { + title: "Components/type-select", + component: SelectType, + parameters: { + layout: "centered", + }, + argTypes: {}, +}; + +export default meta; + +type Story = StoryObj; + +export const WineTypeSelect: Story = { + args: {}, +}; + +export const WineTypeSelectError: Story = { + args: { + isError: true, + }, +}; diff --git a/src/components/select-type/select-type.tsx b/src/components/select-type/select-type.tsx new file mode 100644 index 00000000..1be83f09 --- /dev/null +++ b/src/components/select-type/select-type.tsx @@ -0,0 +1,87 @@ +import { cn } from "@/lib/utils"; +import Image from "next/image"; +import redWine from "../../../public/images/wine-type/red.jpg"; +import whiteWine from "../../../public/images/wine-type/white.jpg"; +import sparklingWine from "../../../public/images/wine-type/sparkling.jpg"; +import { ComponentProps } from "react"; + +const imgMap = { + RED: redWine, + WHITE: whiteWine, + SPARKLING: sparklingWine, +} as const; + +type WineType = keyof typeof imgMap; + +interface SelectTypeValue extends ComponentProps<"input"> { + isError: boolean; +} + +const TypeInput = ({ name }: { name: WineType }) => { + const imgSrc = imgMap[name] || ""; + const typeName = name.slice(0, 1) + name.slice(1).toLowerCase(); + + return ( +
+ + +
+ ); +}; + +const SelectType = ({ isError, ...props }: SelectTypeValue) => { + return ( +
+
+

타입

+ {isError && ( +

+ 와인 타입은 필수 입력이에요 +

+ )} +
+
+ + + +
+
+ ); +}; + +export default SelectType; diff --git a/src/components/text-input/text-input.stories.tsx b/src/components/text-input/text-input.stories.tsx new file mode 100644 index 00000000..755b1a32 --- /dev/null +++ b/src/components/text-input/text-input.stories.tsx @@ -0,0 +1,49 @@ +import { Meta, StoryObj } from "@storybook/nextjs"; +import { ModalTextInput, TextInput } from "./text-input"; + +const meta: Meta = { + title: "Components/text-input", + component: TextInput, + parameters: { + layout: "centered", + }, + argTypes: { + title: { control: { type: "text" } }, + placeholder: { control: { type: "text" } }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const NoContent: Story = { + args: { + title: "", + placeholder: "", + }, +}; + +export const InputError: Story = { + args: { + title: "", + placeholder: "", + errorMsg: "에러가 발생했습니다", + }, +}; + +export const LongText: Story = { + args: { + title: + "여긴 긴 제목이 들어가는 곳 입니다. 여긴 긴 제목이 들어가는 곳 입니다. 여긴 긴 제목이 들어가는 곳 입니다.", + placeholder: + "긴 placeholder를 입력해주세요 긴 placeholder를 입력해주세요 긴 placeholder를 입력해주세요", + }, +}; + +export const ModalInputError: Story = { + render: (args) => , + args: { + errorMsg: "에러가 발생했습니다", + }, +}; diff --git a/src/components/text-input/text-input.tsx b/src/components/text-input/text-input.tsx new file mode 100644 index 00000000..53d11eab --- /dev/null +++ b/src/components/text-input/text-input.tsx @@ -0,0 +1,83 @@ +import { cn } from "@/lib/utils"; + +interface InputValue { + placeholder: string; + errorMsg: string; +} + +interface TextInputValue extends InputValue { + title: string; +} + +/** + * 기본 Input + * @param placeholder input의 placeholder + * @param errorMsg 표출할 에러 메시지 + * @returns + */ +const Input = ({ placeholder, errorMsg }: InputValue) => { + { + /* TODO(휘태): 에러 아이콘 넣기 */ + } + return ( + + ); +}; + +/** + * 기본 입력 창 + * @param title 제목 + * @param placeholder input의 placeholder + * @param errorMsg 표출할 에러 메시지 + * @returns input + */ +const TextInput = ({ title, placeholder, errorMsg }: TextInputValue) => { + return ( + <> +
+

+ {title ? title : "제목"} +

+ +
+ {errorMsg &&

{errorMsg}

} + + ); +}; + +/** + * 모달 창에서 사용할 입력 창 + * @param title + * @param placeholder + * @param errorMsg + * @returns modal input + */ +const ModalTextInput = ({ title, placeholder, errorMsg }: TextInputValue) => { + return ( +
+
+

+ {title ? title : "제목"} +

+ {errorMsg &&

{errorMsg}

} +
+ +
+ ); +}; + +export { TextInput, ModalTextInput };