diff --git a/src/LecueNote/page/LeceuNotePage/index.tsx b/src/LecueNote/page/LeceuNotePage/index.tsx
index ed6e4301..603f71a6 100644
--- a/src/LecueNote/page/LeceuNotePage/index.tsx
+++ b/src/LecueNote/page/LeceuNotePage/index.tsx
@@ -6,7 +6,7 @@ import * as S from './LecueNotePage.style';
function LecueNotePage() {
return (
-
+
diff --git a/src/assets/img/img_modal_ex.svg b/src/assets/img/img_modal_ex.svg
new file mode 100644
index 00000000..35a1efca
--- /dev/null
+++ b/src/assets/img/img_modal_ex.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/assets/index.ts b/src/assets/index.ts
index f5968f3a..21e013ed 100644
--- a/src/assets/index.ts
+++ b/src/assets/index.ts
@@ -1,5 +1,4 @@
///
-
import BtnFloatingList from './button/btn_floating_list.svg?react';
import BtnFloatingPostit from './button/btn_floating_postit.svg?react';
import BtnFloatingSticker from './button/btn_floating_sticker.svg?react';
@@ -27,6 +26,7 @@ import ImgKakaoStarOrange from './img/img_kakao_star_orange.svg?react';
import ImgKakaoStarWhite from './img/img_kakao_star_white.svg?react';
import ImgLe from './img/img_le.svg?react';
import ImgLogoLecue from './img/img_logo_lecue.svg?react';
+import ImgModalEx from './img/img_modal_ex.svg?react';
import ImgSplashLogo from './img/img_splash_logo.svg?react';
import ImgStarOrangeLine from './img/img_star_orangeline.svg?react';
import ImgStarPosit from './img/img_star_postit.svg?react';
@@ -60,8 +60,9 @@ export {
ImgKakaoStarWhite,
ImgLe,
ImgLogoLecue,
+ ImgModalEx,
+ ImgSplashLogo,
ImgStarOrangeLine,
ImgStarPosit,
ImgSticker,
- ImgSplashLogo,
};
diff --git a/src/components/common/Modal/CommonModal.tsx b/src/components/common/Modal/CommonModal.tsx
new file mode 100644
index 00000000..bd5f9ea3
--- /dev/null
+++ b/src/components/common/Modal/CommonModal.tsx
@@ -0,0 +1,17 @@
+import CommonModalForm from './CommonModalForm';
+import ModalPortal from './ModalPortal';
+
+interface CommonModal {
+ setModalOn: React.Dispatch>;
+ category: string;
+}
+
+function CommonModal({ setModalOn, category }: CommonModal) {
+ return (
+
+ setModalOn(false)} category={category} />
+
+ );
+}
+
+export default CommonModal;
diff --git a/src/components/common/Modal/CommonModalForm/CommonModalForm.style.ts b/src/components/common/Modal/CommonModalForm/CommonModalForm.style.ts
new file mode 100644
index 00000000..ab8d7439
--- /dev/null
+++ b/src/components/common/Modal/CommonModalForm/CommonModalForm.style.ts
@@ -0,0 +1,81 @@
+import { css } from '@emotion/react';
+import styled from '@emotion/styled';
+
+export const Wrapper = styled.section`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 9;
+
+ width: 100%;
+ height: 100dvh;
+
+ background: ${({ theme }) => theme.colors.Modal};
+`;
+
+export const Contents = styled.article`
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ z-index: 10;
+
+ margin: 17.4rem 4.4rem;
+
+ border-radius: 0.4rem;
+ background-color: ${({ theme }) => theme.colors.background};
+`;
+
+export const ImgWrapper = styled.div`
+ margin: 1.1rem;
+`;
+
+export const Title = styled.p`
+ margin-top: 0.2rem;
+ margin-bottom: 1.3rem;
+
+ color: ${({ theme }) => theme.colors.black};
+ ${({ theme }) => theme.fonts.Title1_SB_16};
+`;
+
+export const SubTitleWrapper = styled.div`
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+
+ margin-bottom: 3.7rem;
+`;
+
+export const SubTitle = styled.p`
+ color: ${({ theme }) => theme.colors.key};
+ ${({ theme }) => theme.fonts.Body2_M_14};
+`;
+
+export const BtnWrapper = styled.div`
+ display: flex;
+ gap: 1rem;
+ justify-content: space-between;
+
+ width: calc(100% - 3rem);
+ margin: 0 1.5rem 1.4rem;
+`;
+
+export const Button = styled.button<{ variant: string }>`
+ width: 100%;
+ padding: 1.5rem 0;
+
+ border-radius: 0.4rem;
+ ${({ theme }) => theme.fonts.Title1_SB_16};
+ ${({ variant, theme }) =>
+ variant === 'stop'
+ ? css`
+ background-color: ${theme.colors.LG};
+ color: ${theme.colors.DG};
+ `
+ : css`
+ background-color: ${theme.colors.black};
+ color: ${theme.colors.white};
+ `};
+`;
diff --git a/src/components/common/Modal/CommonModalForm/index.tsx b/src/components/common/Modal/CommonModalForm/index.tsx
new file mode 100644
index 00000000..2b5331fe
--- /dev/null
+++ b/src/components/common/Modal/CommonModalForm/index.tsx
@@ -0,0 +1,59 @@
+import { useEffect, useState } from 'react';
+
+import { MODAL_CONTETNS } from '../constants/ModalContents';
+import * as S from './CommonModalForm.style';
+
+interface CommonModalFormProps {
+ onClose: () => void;
+ category: string;
+}
+
+function CommonModalForm({ onClose, category }: CommonModalFormProps) {
+ const [idx, setIdx] = useState(0);
+ useEffect(() => {
+ switch (category) {
+ case 'note_complete':
+ return setIdx(0);
+ case 'note_escape':
+ return setIdx(1);
+ case 'book_escape':
+ return setIdx(2);
+ case 'book_create':
+ return setIdx(3);
+ case 'book_delete':
+ return setIdx(4);
+ case 'login':
+ return setIdx(5);
+ default:
+ return;
+ }
+ }, []);
+
+ return (
+
+
+ {MODAL_CONTETNS[idx].img}
+
+ {MODAL_CONTETNS[idx].title}
+
+ {MODAL_CONTETNS[idx].subTitle1}
+ {MODAL_CONTETNS[idx].subTitle2}
+
+
+
+ {idx !== 5 && (
+
+ {MODAL_CONTETNS[idx].leftBtn}
+
+ )}
+
+
+ {MODAL_CONTETNS[idx].rightBtn}
+
+
+
+
+ );
+}
+
+export default CommonModalForm;
diff --git a/src/components/common/Modal/ModalPortal.tsx b/src/components/common/Modal/ModalPortal.tsx
new file mode 100644
index 00000000..8fe44c37
--- /dev/null
+++ b/src/components/common/Modal/ModalPortal.tsx
@@ -0,0 +1,12 @@
+import ReactDOM from 'react-dom';
+
+interface ModalPortalProps {
+ children: React.ReactNode;
+}
+
+const ModalPortal = ({ children }: ModalPortalProps) => {
+ const el: HTMLElement | null = document.getElementById('lecuenote-modal');
+ return ReactDOM.createPortal(children, el as Element | DocumentFragment);
+};
+
+export default ModalPortal;
diff --git a/src/components/common/Modal/constants/ModalContents.tsx b/src/components/common/Modal/constants/ModalContents.tsx
new file mode 100644
index 00000000..97103054
--- /dev/null
+++ b/src/components/common/Modal/constants/ModalContents.tsx
@@ -0,0 +1,55 @@
+import { ImgModalEx } from '../../../../assets';
+
+export const MODAL_CONTETNS = [
+ {
+ id: 'note_complete',
+ img: ,
+ title: '레큐노트 작성을 완료하셨나요?',
+ subTitle1: '완료 후 수정/삭제 할 수 없습니다.',
+ subTitle2: '신중하게 결정해주세요!',
+ leftBtn: '돌아가기',
+ rightBtn: '작성완료',
+ },
+ {
+ id: 'note_escape',
+ img: ,
+ title: '레큐노트 작성을 그만두시나요?',
+ subTitle1: '작성한 내용은 모두 사라집니다.',
+ subTitle2: '신중하게 결정해주세요!',
+ leftBtn: '그만두기',
+ rightBtn: '계속 작성',
+ },
+ {
+ id: 'book_escape',
+ img: ,
+ title: '레큐북 제작을 완료하셨나요?',
+ subTitle1: '작성한 내용은 모두 사라집니다.',
+ subTitle2: '신중하게 결정해주세요!',
+ leftBtn: '그만두기',
+ rightBtn: '계속 제작',
+ },
+ {
+ id: 'book_create',
+ img: ,
+ title: '레큐북을 제작할까요?',
+ subTitle1: '제작 후 수정/삭제할 수 없습니다.',
+ subTitle2: '신중하게 결정해주세요!',
+ leftBtn: '돌아가기',
+ rightBtn: '제작하기',
+ },
+ {
+ id: 'book_delete',
+ img: ,
+ title: '해당 레큐북을 삭제하시겠어요?',
+ subTitle1: '삭제 후 되돌릴 수 없습니다.',
+ subTitle2: '신중하게 결정해주세요!',
+ leftBtn: '돌아가기',
+ rightBtn: '삭제하기',
+ },
+ {
+ id: 'login',
+ img: ,
+ title: '로그인 후 이용해주세요',
+ rightBtn: '로그인하기',
+ },
+];