diff --git a/packages/grafnode-components/src/components/Modal/StyledWrapper.js b/packages/grafnode-components/src/components/Modal/StyledWrapper.js
new file mode 100644
index 000000000..407f6abb1
--- /dev/null
+++ b/packages/grafnode-components/src/components/Modal/StyledWrapper.js
@@ -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;
diff --git a/packages/grafnode-components/src/components/Modal/index.js b/packages/grafnode-components/src/components/Modal/index.js
new file mode 100644
index 000000000..8ec49898b
--- /dev/null
+++ b/packages/grafnode-components/src/components/Modal/index.js
@@ -0,0 +1,94 @@
+import React, {useState, useEffect} from 'react';
+import StyledWrapper from './StyledWrapper';
+
+const ModalHeader = ({title, handleCancel}) => (
+
+ {title ?
{title}
: null}
+ {handleCancel ? (
+
handleCancel() : null}>
+ ×
+
+ ) : null}
+
+);
+
+const ModalContent = ({children}) => (
+
+ {children}
+
+);
+
+const ModalFooter = ({confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled}) => {
+ confirmText = confirmText || 'Save';
+ cancelText = cancelText || 'Cancel';
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+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 (
+
+
+ closeModal()} />
+ {children}
+ closeModal()}
+ handleSubmit={handleConfirm}
+ confirmDisabled={confirmDisabled}
+ />
+
+ closeModal()} />
+
+ );
+};
+
+export default ConfirmModal;
diff --git a/packages/grafnode-components/src/components/Sidebar/index.js b/packages/grafnode-components/src/components/Sidebar/index.js
index da2ca3e0f..df4d04efe 100644
--- a/packages/grafnode-components/src/components/Sidebar/index.js
+++ b/packages/grafnode-components/src/components/Sidebar/index.js
@@ -1,11 +1,14 @@
-import React, { forwardRef, useRef } from 'react';
+import React, { useState, forwardRef, useRef } from 'react';
import Collections from './Collections';
+import Modal from '../Modal';
import Navbar from '../Navbar';
import Dropdown from '../Dropdown';
import { IconBox, IconSearch, IconDots } from '@tabler/icons';
import StyledWrapper from './StyledWrapper';
const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => {
+ const [modalOpen, setModalOpen] = useState(true);
+
const menuDropdownTippyRef = useRef();
const onMenuDropdownCreate = (ref) => menuDropdownTippyRef.current = 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 (
+ {modalOpen && (
+
+ Hello
+
+ )}
+
@@ -28,6 +50,7 @@ const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => {
{
menuDropdownTippyRef.current.hide();
+ setModalOpen(true);
}}>
Create Collection
diff --git a/packages/grafnode-run/src/globalStyles.js b/packages/grafnode-run/src/globalStyles.js
new file mode 100644
index 000000000..273713efd
--- /dev/null
+++ b/packages/grafnode-run/src/globalStyles.js
@@ -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;
\ No newline at end of file
diff --git a/packages/grafnode-run/src/pages/index.js b/packages/grafnode-run/src/pages/index.js
index 413ef924b..bdc18b8f7 100644
--- a/packages/grafnode-run/src/pages/index.js
+++ b/packages/grafnode-run/src/pages/index.js
@@ -1,5 +1,6 @@
import Head from 'next/head';
import Main from 'pageComponents/Main';
+import GlobalStyle from '../globalStyles';
export default function Home() {
return (
@@ -9,6 +10,8 @@ export default function Home() {
+
+