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 (
+
+
+
e.stopPropagation()}
+ >
+
+ {title && (
+
+ {title}
+
+ )}
+ {description && (
+
+ {description}
+
+ )}
+
+
+ {children &&
{children}
}
+
+ {buttons && (
+
+ {buttons}
+
+ )}
+
+
+
+
+ );
+}
+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;
+ }
+}