Move actions into context menu, add support for deleting a backup
This commit is contained in:
parent
2eb6ab4d63
commit
9ba6aaebde
10 changed files with 344 additions and 66 deletions
87
resources/scripts/components/elements/DropdownMenu.tsx
Normal file
87
resources/scripts/components/elements/DropdownMenu.tsx
Normal file
|
@ -0,0 +1,87 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { CSSTransition } from 'react-transition-group';
|
||||
import styled from 'styled-components';
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
renderToggle: (onClick: (e: React.MouseEvent<any, MouseEvent>) => void) => React.ReactChild;
|
||||
}
|
||||
|
||||
export const DropdownButtonRow = styled.button<{ danger?: boolean }>`
|
||||
${tw`p-2 flex items-center rounded w-full text-neutral-500`};
|
||||
transition: 150ms all ease;
|
||||
|
||||
&:hover {
|
||||
${props => props.danger
|
||||
? tw`text-red-700 bg-red-100`
|
||||
: tw`text-neutral-700 bg-neutral-100`
|
||||
};
|
||||
}
|
||||
`;
|
||||
|
||||
const DropdownMenu = ({ renderToggle, children }: Props) => {
|
||||
const menu = useRef<HTMLDivElement>(null);
|
||||
const [ posX, setPosX ] = useState(0);
|
||||
const [ visible, setVisible ] = useState(false);
|
||||
|
||||
const onClickHandler = (e: React.MouseEvent<any, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
|
||||
!visible && setPosX(e.clientX);
|
||||
setVisible(s => !s);
|
||||
};
|
||||
|
||||
const windowListener = (e: MouseEvent) => {
|
||||
if (e.button === 2 || !visible || !menu.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target === menu.current || menu.current.contains(e.target as Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target !== menu.current && !menu.current.contains(e.target as Node)) {
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!visible || !menu.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.addEventListener('click', windowListener);
|
||||
menu.current.setAttribute(
|
||||
'style', `left: ${Math.round(posX - menu.current.clientWidth)}px`,
|
||||
);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', windowListener);
|
||||
}
|
||||
}, [ visible ]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{renderToggle(onClickHandler)}
|
||||
<CSSTransition
|
||||
timeout={250}
|
||||
in={visible}
|
||||
unmountOnExit={true}
|
||||
classNames={'fade'}
|
||||
>
|
||||
<div
|
||||
ref={menu}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setVisible(false);
|
||||
}}
|
||||
className={'absolute bg-white p-2 rounded border border-neutral-700 shadow-lg text-neutral-500 min-w-48'}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownMenu;
|
Reference in a new issue