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 ( { 정보 제공 토스트 띄우기 + + { + closeDialog(); + }} + > +

Dialog Content

+
); }; 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;