feat: create settings modal

This commit is contained in:
Sonny
2024-05-16 23:54:40 +02:00
committed by Sonny
parent 18b2eb2c5a
commit 53aa7bc22b
16 changed files with 205 additions and 19 deletions

View File

@@ -0,0 +1,12 @@
import styled from '@emotion/styled';
const ModalBody = styled.div({
width: '100%',
display: 'flex',
flex: 1,
alignItems: 'center',
flexDirection: 'column',
overflow: 'auto',
});
export default ModalBody;

View File

@@ -0,0 +1,23 @@
import styled from '@emotion/styled';
const ModalContainer = styled.div(({ theme }) => ({
minWidth: '500px',
background: theme.colors.secondary,
padding: '1em',
borderRadius: theme.border.radius,
marginTop: '6em',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
boxShadow: theme.colors.boxShadow,
[`@media (max-width: ${theme.media.mobile})`]: {
maxHeight: 'calc(100% - 2em)',
width: 'calc(100% - 2em)',
minWidth: 'unset',
marginTop: '1em',
},
}));
export default ModalContainer;

View File

@@ -0,0 +1,20 @@
import styled from '@emotion/styled';
const ModalHeader = styled.h3({
width: '100%',
marginBottom: '0.75em',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
});
const ModalCloseBtn = styled.button(({ theme }) => ({
cursor: 'pointer',
color: theme.colors.primary,
backgroundColor: 'transparent',
border: 0,
padding: 0,
margin: 0,
}));
export { ModalHeader, ModalCloseBtn };

View File

@@ -0,0 +1,18 @@
import styled from '@emotion/styled';
import { rgba } from '~/lib/color';
const ModalWrapper = styled.div(({ theme }) => ({
zIndex: 9999,
position: 'absolute',
top: 0,
left: 0,
height: '100%',
width: '100%',
background: rgba(theme.colors.black, 0.35),
backdropFilter: 'blur(0.25em)',
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
}));
export default ModalWrapper;

View File

@@ -0,0 +1,59 @@
import { Fragment, ReactNode, useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import { IoClose } from 'react-icons/io5';
import ModalBody from '~/components/common/modal/_modal_body';
import ModalContainer from '~/components/common/modal/_modal_container';
import {
ModalCloseBtn,
ModalHeader,
} from '~/components/common/modal/_modal_header';
import ModalWrapper from '~/components/common/modal/_modal_wrapper';
import TextEllipsis from '~/components/common/text_ellipsis';
import useClickOutside from '~/hooks/use_click_outside';
import useGlobalHotkeys from '~/hooks/use_global_hotkeys';
import useShortcut from '~/hooks/use_shortcut';
interface ModalProps {
title?: string;
children: ReactNode;
opened: boolean;
close: () => void;
}
export default function Modal({
title,
children,
opened = true,
close,
}: ModalProps) {
const modalRef = useRef<HTMLDivElement>(null);
const { setGlobalHotkeysEnabled } = useGlobalHotkeys();
useClickOutside(modalRef, close);
useShortcut('ESCAPE_KEY', close, { ignoreGlobalHotkeysStatus: true });
useEffect(() => setGlobalHotkeysEnabled(!opened), [opened]);
if (typeof window === 'undefined') {
return <Fragment />;
}
return (
opened &&
createPortal(
<ModalWrapper>
<ModalContainer ref={modalRef}>
<ModalHeader>
{title && <TextEllipsis>{title}</TextEllipsis>}
<ModalCloseBtn onClick={close}>
<IoClose size={20} />
</ModalCloseBtn>
</ModalHeader>
<ModalBody>{children}</ModalBody>
</ModalContainer>
</ModalWrapper>,
document.body
)
);
}