mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-25 01:14:23 +01:00
feat: modal
This commit is contained in:
parent
81f9668375
commit
1f1e8a602e
@ -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;
|
94
packages/grafnode-components/src/components/Modal/index.js
Normal file
94
packages/grafnode-components/src/components/Modal/index.js
Normal 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;
|
@ -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>
|
||||||
|
49
packages/grafnode-run/src/globalStyles.js
Normal file
49
packages/grafnode-run/src/globalStyles.js
Normal 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;
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user