feat: modal

This commit is contained in:
Anoop M D 2022-01-04 02:07:46 +05:30
parent 81f9668375
commit 1f1e8a602e
5 changed files with 292 additions and 1 deletions

View File

@ -0,0 +1,122 @@
import styled from 'styled-components';
const Wrapper = styled.div`
&.modal--animate-out{
animation: fade-out 0.5s forwards cubic-bezier(.19,1,.22,1);
.grafnode-modal-card {
animation: fade-and-slide-out-from-top .50s forwards cubic-bezier(.19,1,.22,1);
}
}
&.grafnode-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: flex-start;
justify-content: center;
overflow-y: auto;
z-index: 1003;
}
.grafnode-modal-card {
animation-duration: .85s;
animation-delay: .1s;
background: var(--color-background-top);
border-radius: var(--border-radius);
position: relative;
z-index: 1003;
max-width: calc(100% - var(--spacing-base-unit));
box-shadow: var(--box-shadow-base);
display: flex;
flex-direction: column;
will-change: opacity,transform;
flex-grow: 0;
margin: 3vh 10vw;
margin-top: 50px;
&.modal-sm {
min-width: 300px;
}
&.modal-md {
min-width: 500px;
}
&.modal-lg {
min-width: 800px;
}
&.modal-xl {
min-width: 1140px;
}
animation: fade-and-slide-in-from-top .50s forwards cubic-bezier(.19,1,.22,1);
}
.grafnode-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
text-transform: uppercase;
color: rgb(86 86 86);
background-color: #f1f1f1;
font-size: 0.75rem;
padding: 12px;
font-weight: 600;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
.close {
font-size: 1.3rem;
line-height: 1;
color: #000;
text-shadow: 0 1px 0 #fff;
opacity: 0.5;
margin-top: -2px;
&:hover {
opacity: 0.8;
}
}
}
.grafnode-modal-content {
flex-grow: 1;
background-color: #fff;
}
.grafnode-modal-backdrop {
height: 100%;
width: 100%;
left: 0;
top: 0;
position: fixed;
will-change: opacity;
background: transparent;
&:before{
content: "";
height: 100%;
width: 100%;
left: 0;
opacity: .4;
top: 0;
background: black;
position: fixed;
}
animation: fade-in .1s forwards cubic-bezier(.19,1,.22,1);
}
.grafnode-modal-footer {
background-color: white;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
`;
export default Wrapper;

View File

@ -0,0 +1,94 @@
import React, {useState, useEffect} from 'react';
import StyledWrapper from './StyledWrapper';
const ModalHeader = ({title, handleCancel}) => (
<div className="grafnode-modal-header">
{title ? <div className="grafnode-modal-heade-title">{title}</div> : null}
{handleCancel ? (
<div className="close cursor-pointer" onClick={handleCancel ? () => handleCancel() : null}>
×
</div>
) : null}
</div>
);
const ModalContent = ({children}) => (
<div className="grafnode-modal-content px-4 py-6">
{children}
</div>
);
const ModalFooter = ({confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled}) => {
confirmText = confirmText || 'Save';
cancelText = cancelText || 'Cancel';
return (
<div className="flex justify-end p-4 grafnode-modal-footer">
<span className="mr-2">
<button type="button" onClick={handleCancel} className="btn btn-sm btn-close">
{cancelText}
</button>
</span>
<span className="">
<button type="submit" className="submit btn btn-sm btn-secondary" disabled={confirmDisabled} onClick={handleSubmit} >
{confirmText}
</button>
</span>
</div>
);
}
const ConfirmModal = ({
size,
title,
confirmText,
cancelText,
handleCancel,
handleConfirm,
children,
confirmDisabled
}) => {
const [isClosing, setIsClosing] = useState(false);
const escFunction = (event) => {
const escKeyCode = 27;
if (event.keyCode === escKeyCode) {
closeModal();
}
};
const closeModal = () => {
setIsClosing(true);
setTimeout(() => handleCancel(), 500);
}
useEffect(() => {
document.addEventListener('keydown', escFunction, false);
return () => {
document.removeEventListener('keydown', escFunction, false);
}
}, []);
let classes = 'grafnode-modal';
if (isClosing) {
classes += ' modal--animate-out';
}
return (
<StyledWrapper className={classes}>
<div className={`grafnode-modal-card modal-${size}`}>
<ModalHeader title={title} handleCancel={() => closeModal()} />
<ModalContent>{children}</ModalContent>
<ModalFooter
confirmText={confirmText}
cancelText={cancelText}
handleCancel={() => closeModal()}
handleSubmit={handleConfirm}
confirmDisabled={confirmDisabled}
/>
</div>
<div className="grafnode-modal-backdrop" onClick={() => closeModal()} />
</StyledWrapper>
);
};
export default ConfirmModal;

View File

@ -1,11 +1,14 @@
import React, { forwardRef, useRef } from 'react'; import React, { useState, forwardRef, useRef } from 'react';
import Collections from './Collections'; import Collections from './Collections';
import Modal from '../Modal';
import Navbar from '../Navbar'; import Navbar from '../Navbar';
import Dropdown from '../Dropdown'; import Dropdown from '../Dropdown';
import { IconBox, IconSearch, IconDots } from '@tabler/icons'; import { IconBox, IconSearch, IconDots } from '@tabler/icons';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => { const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => {
const [modalOpen, setModalOpen] = useState(true);
const menuDropdownTippyRef = useRef(); const menuDropdownTippyRef = useRef();
const onMenuDropdownCreate = (ref) => menuDropdownTippyRef.current = ref; const onMenuDropdownCreate = (ref) => menuDropdownTippyRef.current = ref;
const MenuIcon = forwardRef((props, ref) => { const MenuIcon = forwardRef((props, ref) => {
@ -16,8 +19,27 @@ const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => {
); );
}); });
const handleCancel = () => {
setModalOpen(false);
};
const handleConfirm = () => {
setModalOpen(false);
};
return ( return (
<StyledWrapper> <StyledWrapper>
{modalOpen && (
<Modal
size="md"
title='Create Collection'
handleCancel={handleCancel}
handleConfirm={handleConfirm}
>
Hello
</Modal>
)}
<Navbar /> <Navbar />
<div className="mt-4 px-2 py-1 flex collection-title"> <div className="mt-4 px-2 py-1 flex collection-title">
@ -28,6 +50,7 @@ const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => {
<div> <div>
<div className="dropdown-item" onClick={(e) => { <div className="dropdown-item" onClick={(e) => {
menuDropdownTippyRef.current.hide(); menuDropdownTippyRef.current.hide();
setModalOpen(true);
}}> }}>
Create Collection Create Collection
</div> </div>

View File

@ -0,0 +1,49 @@
import { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes fade-and-slide-in-from-top {
from {
opacity: 0;
-webkit-transform: translateY(-30px);
transform: translateY(-30px);
}
to {
opacity: 1;
-webkit-transform: none;
transform: none;
}
}
@keyframes fade-and-slide-out-from-top {
from {
opacity: 1;
-webkit-transform: none;
transform: none;
}
to {
opacity: 2;
-webkit-transform: translateY(-30px);
transform: translateY(-30px);
}
}
`;
export default GlobalStyle;

View File

@ -1,5 +1,6 @@
import Head from 'next/head'; import Head from 'next/head';
import Main from 'pageComponents/Main'; import Main from 'pageComponents/Main';
import GlobalStyle from '../globalStyles';
export default function Home() { export default function Home() {
return ( return (
@ -9,6 +10,8 @@ export default function Home() {
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
</Head> </Head>
<GlobalStyle />
<main> <main>
<Main /> <Main />
</main> </main>