mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-10 15:35:35 +00:00
feat: create settings modal
This commit is contained in:
12
inertia/components/common/modal/_modal_body.tsx
Normal file
12
inertia/components/common/modal/_modal_body.tsx
Normal 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;
|
||||
23
inertia/components/common/modal/_modal_container.tsx
Normal file
23
inertia/components/common/modal/_modal_container.tsx
Normal 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;
|
||||
20
inertia/components/common/modal/_modal_header.tsx
Normal file
20
inertia/components/common/modal/_modal_header.tsx
Normal 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 };
|
||||
18
inertia/components/common/modal/_modal_wrapper.tsx
Normal file
18
inertia/components/common/modal/_modal_wrapper.tsx
Normal 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;
|
||||
59
inertia/components/common/modal/modal.tsx
Normal file
59
inertia/components/common/modal/modal.tsx
Normal 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
|
||||
)
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user