diff --git a/apps/admin/src/pages/HomePage/HomePage.tsx b/apps/admin/src/pages/HomePage/HomePage.tsx
index 7be8e9e5..0deeaf67 100644
--- a/apps/admin/src/pages/HomePage/HomePage.tsx
+++ b/apps/admin/src/pages/HomePage/HomePage.tsx
@@ -3,9 +3,11 @@ import Header from '../../components/Header/Header';
import Layout from '../../components/Layout/Layout';
import { PATH } from '../../constants/routes';
import Styled from './HomePage.styles';
+import { Dialog, useDialogState } from '@boolti/ui';
const HomePage = () => {
const toast = useToast();
+ const { open, openDialog, closeDialog } = useDialogState();
return (
{
정보 제공 토스트 띄우기
+
+
);
};
diff --git a/packages/ui/src/components/Dialog/CloseIcon.tsx b/packages/ui/src/components/Dialog/CloseIcon.tsx
new file mode 100644
index 00000000..710ea599
--- /dev/null
+++ b/packages/ui/src/components/Dialog/CloseIcon.tsx
@@ -0,0 +1,27 @@
+const CloseIcon = () => (
+
+);
+
+export default CloseIcon;
diff --git a/packages/ui/src/components/Dialog/Dialog.styles.ts b/packages/ui/src/components/Dialog/Dialog.styles.ts
new file mode 100644
index 00000000..4a778e86
--- /dev/null
+++ b/packages/ui/src/components/Dialog/Dialog.styles.ts
@@ -0,0 +1,54 @@
+import styled from '@emotion/styled';
+
+const DIALOG_WIDTH = '450px';
+
+const DimmedArea = styled.div`
+ position: fixed;
+ inset: 0;
+ background-color: rgba(86, 86, 86, 0.25);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+`;
+
+const Dialog = styled.div`
+ width: ${DIALOG_WIDTH};
+ border-radius: 8px;
+ background-color: ${({ theme }) => theme.palette.grey.w};
+`;
+
+const DialogHeader = styled.div`
+ padding: 16px 32px;
+ border-bottom: 1px solid ${({ theme }) => theme.palette.grey.g30};
+ position: relative;
+`;
+
+const DialogTitle = styled.h2`
+ ${({ theme }) => theme.typo.sh2};
+ color: ${({ theme }) => theme.palette.grey.g70};
+`;
+
+const DialogCloseButton = styled.button`
+ position: absolute;
+ top: 17px;
+ right: 32px;
+ width: 24px;
+ height: 24px;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+`;
+
+const DialogContent = styled.div`
+ padding: 32px;
+`;
+
+export default {
+ DimmedArea,
+ Dialog,
+ DialogHeader,
+ DialogTitle,
+ DialogCloseButton,
+ DialogContent,
+};
diff --git a/packages/ui/src/components/Dialog/index.tsx b/packages/ui/src/components/Dialog/index.tsx
new file mode 100644
index 00000000..3c506377
--- /dev/null
+++ b/packages/ui/src/components/Dialog/index.tsx
@@ -0,0 +1,32 @@
+import Portal from '../Portal';
+import CloseIcon from './CloseIcon';
+import Styled from './Dialog.styles';
+
+interface DialogProps {
+ open: boolean;
+ children: React.ReactNode;
+ title?: string;
+ onClose?: () => void;
+}
+
+const Dialog = ({ open, children, title, onClose }: DialogProps) => {
+ if (!open) return null;
+
+ return (
+
+
+
+
+ {title}
+
+
+
+
+ {children}
+
+
+
+ );
+};
+
+export default Dialog;
diff --git a/packages/ui/src/components/Portal/index.tsx b/packages/ui/src/components/Portal/index.tsx
new file mode 100644
index 00000000..e33d0d45
--- /dev/null
+++ b/packages/ui/src/components/Portal/index.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+interface PortalProps {
+ children: React.ReactNode;
+}
+
+const Portal = ({ children }: PortalProps) => ReactDOM.createPortal(children, document.body);
+
+export default Portal;
diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts
index 644c62ed..dca2bd9e 100644
--- a/packages/ui/src/components/index.ts
+++ b/packages/ui/src/components/index.ts
@@ -2,5 +2,6 @@ import ThemeProvider from './ThemeProvider';
import Button from './Button';
import TextButton from './TextButton';
import Badge from './Badge';
+import Dialog from './Dialog';
-export { ThemeProvider, Button, TextButton, Badge };
+export { ThemeProvider, Button, TextButton, Badge, Dialog };
diff --git a/packages/ui/src/hooks/index.ts b/packages/ui/src/hooks/index.ts
index bacab629..77cb1424 100644
--- a/packages/ui/src/hooks/index.ts
+++ b/packages/ui/src/hooks/index.ts
@@ -1,3 +1,4 @@
import useToast from './useToast';
+import useDialogState from './useDialogState';
-export { useToast };
+export { useToast, useDialogState };
diff --git a/packages/ui/src/hooks/useDialogState.ts b/packages/ui/src/hooks/useDialogState.ts
new file mode 100644
index 00000000..3d2cbe82
--- /dev/null
+++ b/packages/ui/src/hooks/useDialogState.ts
@@ -0,0 +1,25 @@
+import { useCallback, useState } from 'react';
+
+interface UseDialogParams {
+ defaultOpen?: boolean;
+}
+
+const useDialogState = (params?: UseDialogParams) => {
+ const [open, setOpen] = useState(params?.defaultOpen ?? false);
+
+ const openDialog = useCallback(() => {
+ setOpen(true);
+ }, []);
+
+ const closeDialog = useCallback(() => {
+ setOpen(false);
+ }, []);
+
+ return {
+ open,
+ openDialog,
+ closeDialog,
+ };
+};
+
+export default useDialogState;