diff --git a/next.config.ts b/next.config.ts index a30e0a7..dc0c020 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,16 +1,13 @@ import { NextConfig } from "next"; const nextConfig: NextConfig = { - // TurboPack 설정 - experimental: { - turbo: { - rules: { - '*.svg': { - loaders: ['@svgr/webpack'], - as: '*.js', - }, + turbopack: { + rules: { + '*.svg': { + loaders: ['@svgr/webpack'], + as: '*.js', }, - }, + } }, } diff --git a/src/app/design-system/page.tsx b/src/app/design-system/page.tsx index 1172825..5609c23 100644 --- a/src/app/design-system/page.tsx +++ b/src/app/design-system/page.tsx @@ -1,6 +1,14 @@ +'use client'; + import Button from '@/shared/components/Button'; +import ConfirmPop from '@/shared/components/ModalPop/ConfirmPop'; +import ModalLayout from '@/shared/components/ModalPop/ModalLayout'; +import { useState } from 'react'; function Page() { + const [isModalOpen, setModalOpen] = useState(false); + const [isConfirmOpen, setConfirmOpen] = useState(false); + return (
{/* 페이지 제목 */} @@ -54,7 +62,36 @@ function Page() {

popup

- {/* 여기 컴포넌트 삽입 */} + {/* 모달 열기 버튼 */} + + + + setModalOpen(false)} + title="제목" + description="설명" + buttons={<>{/* 여기다가 버튼 컴포넌트 넣으면 됨 */}} + > +
모달팝업 내용
+
+ + setConfirmOpen(false)} + title="Confirm제목" + description="설명" + />
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a6070a3..5c1116a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -12,7 +12,10 @@ export default function RootLayout({ }>) { return ( - {children} + + {children} + + ); } diff --git a/src/shared/assets/icons/close_20.svg b/src/shared/assets/icons/close_20.svg deleted file mode 100644 index 3e4bcd0..0000000 --- a/src/shared/assets/icons/close_20.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/shared/assets/icons/close_32.svg b/src/shared/assets/icons/close_32.svg new file mode 100644 index 0000000..ae82cbd --- /dev/null +++ b/src/shared/assets/icons/close_32.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/shared/components/ModalPop/ConfirmPop.tsx b/src/shared/components/ModalPop/ConfirmPop.tsx new file mode 100644 index 0000000..50ac0dc --- /dev/null +++ b/src/shared/components/ModalPop/ConfirmPop.tsx @@ -0,0 +1,31 @@ +import ModalLayout from './ModalLayout'; + +interface Props { + ref?: React.Ref; + open: boolean; + onClose: () => void; + title?: string; + description?: React.ReactNode; + children?: React.ReactNode; +} +function ConfirmPop({ ref, open, onClose, title, description, children }: Props) { + return ( + + + + + } + > + {children} + + ); +} +export default ConfirmPop; diff --git a/src/shared/components/ModalPop/ModalLayout.tsx b/src/shared/components/ModalPop/ModalLayout.tsx new file mode 100644 index 0000000..1a9ea8bf --- /dev/null +++ b/src/shared/components/ModalPop/ModalLayout.tsx @@ -0,0 +1,90 @@ +'use client'; + +import Close from '@/shared/assets/icons/close_32.svg'; +import Portal from './Portal'; +import tw from '@/shared/utills/tw'; +import { useEffect } from 'react'; + +interface Props { + ref?: React.Ref; + size?: 'sm' | 'md'; + open: boolean; + onClose: () => void; + title?: string; + description?: React.ReactNode; + children?: React.ReactNode; + buttons?: React.ReactNode; +} + +function ModalLayout({ + ref, + size = 'md', + open, + onClose, + title, + description, + children, + buttons, +}: Props) { + // ESC키 모달 닫기 + useEffect(() => { + if (!open) return; + + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose(); + }; + + document.addEventListener('keydown', handleKeyDown); + + return () => document.removeEventListener('keydown', handleKeyDown); + }, [open, onClose]); + + if (!open) return null; + + return ( + + + + ); +} +export default ModalLayout; diff --git a/src/shared/components/ModalPop/Portal.tsx b/src/shared/components/ModalPop/Portal.tsx new file mode 100644 index 0000000..c8ad8e6 --- /dev/null +++ b/src/shared/components/ModalPop/Portal.tsx @@ -0,0 +1,19 @@ +'use client'; +import { ReactNode, useEffect, useState } from 'react'; +import { createPortal } from 'react-dom'; + +interface Props { + children: ReactNode; +} + +export default function Portal({ children }: Props) { + const [target, setTarget] = useState(null); + + useEffect(() => { + const el = document.getElementById('modal-root'); + setTarget(el); + }, []); + + if (!target) return null; + return createPortal(children, target); +} diff --git a/src/shared/styles/_base.css b/src/shared/styles/_base.css index 97fca66..a953b48 100644 --- a/src/shared/styles/_base.css +++ b/src/shared/styles/_base.css @@ -1,2 +1,5 @@ -@layer base; - +@layer base { + button { + cursor: pointer; + } +}