Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/modal #10

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
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
42 changes: 42 additions & 0 deletions src/app/(routes)/test/modal/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"use client"
import { useModalStore } from "@/store/modal"
import ConfirmModal from "@/components/modal/ConfirmModal"
import Button from "@/components/Button"
import CollectionModal from "@/components/modal/CollectionModal/CollectionModal"

export default function Home() {
const { openModal, closeModal } = useModalStore()

const openLogoutModal = () => {
openModal(
<ConfirmModal onConfirm={() => {}} onCancel={closeModal}>
<p className="text-xl font-medium text-white">로그아웃 하시겠습니까?</p>
</ConfirmModal>
)
}
const openDeleteAccount = () => {
openModal(
<ConfirmModal onConfirm={() => {}} onCancel={closeModal}>
<p className="text-xl font-medium text-white">탈퇴하면 모든 정보가 사라집니다.</p>
<p className="text-xl font-medium text-white">탈퇴하시겠습니까?</p>
</ConfirmModal>
)
}
const openCollenctionModal = () => {
openModal(<CollectionModal onCancel={closeModal} />)
}

return (
<div className="flex min-h-screen items-center justify-center gap-10 bg-gray-100">
<Button className="text-white" onClick={openLogoutModal}>
로그아웃 모달 열기
</Button>
<Button className="text-white" onClick={openDeleteAccount}>
탈퇴 모달 열기
</Button>
<Button className="text-white" onClick={openCollenctionModal}>
컬렉션 모달 열기
</Button>
</div>
)
}
6 changes: 4 additions & 2 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Modal from "@/components/modal/Modal"
import Toast from "@/components/Toast"
import { Pretendard } from "@/fonts"
import "@/styles/globals.css"
Expand All @@ -6,8 +7,8 @@ import { cn } from "@/utils/cn"
import type { Metadata } from "next"

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app"
title: "Memez",
description: "welcome to memez party"
}

export default function RootLayout({
Expand All @@ -20,6 +21,7 @@ export default function RootLayout({
<body className={cn(Pretendard.variable)}>
{children}
<Toast />
<Modal />
</body>
</html>
)
Expand Down
18 changes: 18 additions & 0 deletions src/components/modal/CollectionModal/CollectionCreate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Button from "@/components/Button"
import Textarea from "@/components/Textarea"

export default function CollectionCreate() {
return (
<>
<div className="flex flex-col gap-[16px]">
<p>컬렉션 이름</p>
<Textarea placeholder="컬렉션 이름을 입력해주세요" rows={1}></Textarea>
</div>
<div className="flex items-center justify-end">
<Button className="h-[40px] w-[148px] bg-gray-scale-700 p-0">
<p className="text-h1-m text-gray-scale-100">완료</p>
</Button>
</div>
</>
)
}
38 changes: 38 additions & 0 deletions src/components/modal/CollectionModal/CollectionList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Button from "@/components/Button"
import { Plus } from "lucide-react"
const Collections = ["컬렉션1", "컬렉션2", "컬렉션3", "컬렉션4"]
type Props = {
onCreate: () => void
}

export default function CollectionList({ onCreate }: Props) {
return (
<>
<div className="mt-[28px] flex flex-col gap-[40px]">
<div className="flex items-center gap-[8px]">
<Button className="bg-gray-scale-700 px-[20px] py-[10px] text-primary-300">
<div className="flex items-center gap-[20px] text-h3-sb" onClick={onCreate}>
<p>컬랙션 추가</p>
<Plus fontSize={"14px"} stroke="3" />
</div>
</Button>
<p className="text-xs text-gray-scale-400">현재 “컬렉션 1”에 수록되어 있어요!</p>
</div>
<div>
<div className="border-b-[1px] border-gray-scale-700 p-[8px]">기본</div>
{Collections.map((collection, idx) => (
<div className="border-b-[1px] border-gray-scale-700 p-[8px] py-[16px]" key={idx}>
<p className="">{collection}</p>
</div>
))}
</div>
</div>
<div className="flex items-center justify-end gap-[24px]">
<p className="text-h2-sb text-primary-300">메모 추가</p>
<Button className="h-[40px] w-[148px] bg-primary-400 p-0">
<p className="text-h1-m text-gray-100">완료</p>
</Button>
</div>
</>
)
}
32 changes: 32 additions & 0 deletions src/components/modal/CollectionModal/CollectionModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import CollectionList from "./CollectionList"
import { useState } from "react"
import CollectionCreate from "./CollectionCreate"
import { ArrowLeft, X } from "lucide-react"
type Props = {
onCancel: () => void
}

export default function CollectionModal({ onCancel }: Props) {
const [isCreateMode, setIsCreateMode] = useState(false)

return (
<div className="flex min-h-[600px] w-[720px] flex-col gap-[32px] rounded-[12px] border-[0.5px] border-primary-300 bg-gray-scale-800 px-[24px] py-[36px]">
<div className="flex justify-between">
<div onClick={() => setIsCreateMode(false)} className="cursor-pointer">
{/* <IoIosArrowBack /> */}
<ArrowLeft />
</div>
<div>컬렉션 추가</div>
<div onClick={() => onCancel()} className="cursor-pointer">
<X />
</div>
</div>
<div className="flex flex-1 gap-[25px]">
<div className="w-[266px] flex-1 rounded-xl bg-black"></div>
<div className="flex flex-1 flex-col justify-between">
{isCreateMode ? <CollectionCreate /> : <CollectionList onCreate={() => setIsCreateMode(true)} />}
</div>
</div>
</div>
)
}
27 changes: 27 additions & 0 deletions src/components/modal/ConfirmModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ReactNode } from "react"
import Button from "../Button"

type Props = {
children: ReactNode
onConfirm: () => void
onCancel: () => void
}

export default function ConfirmModal({ children, onCancel, onConfirm }: Props) {
return (
<div className="flex flex-col gap-[56px] rounded-[12px] border-[0.5px] border-primary-300 bg-gray-scale-800 px-[38px] py-[44px] text-center">
<div>{children}</div>
<div className="flex justify-center gap-[24px]">
<Button
className="h-[48px] w-[148px] bg-gray-scale-700 text-h1-m text-gray-scale-500"
onClick={() => onConfirm()}
>
</Button>
<Button className="h-[48px] w-[148px] text-h1-m text-white" onClick={() => onCancel()}>
아니요
</Button>
</div>
</div>
)
}
29 changes: 29 additions & 0 deletions src/components/modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use client"
import React from "react"
import ReactDOM from "react-dom"
import { motion } from "framer-motion"
import { useModalStore } from "@/store/modal"

export default function Modal() {
const { isOpen, closeModal, content } = useModalStore()

if (!isOpen) return null

return ReactDOM.createPortal(
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-gray-scale-900 backdrop-blur-2xl"
onClick={closeModal}
>
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
className="relative"
onClick={(e) => e.stopPropagation()}
>
{content}
</motion.div>
</div>,
document.body
)
}
16 changes: 16 additions & 0 deletions src/store/modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { create } from "zustand"
import { ReactNode } from "react"

interface ModalState {
isOpen: boolean
content: ReactNode | null
openModal: (content: ReactNode) => void
closeModal: () => void
}

export const useModalStore = create<ModalState>((set) => ({
isOpen: false,
content: null,
openModal: (content) => set({ isOpen: true, content }),
closeModal: () => set({ isOpen: false, content: null })
}))