slate/components/core/Upload/Popup.js

127 lines
3.7 KiB
JavaScript

import * as React from "react";
import * as System from "~/components/system";
import * as Styles from "~/common/styles";
import * as Strings from "~/common/strings";
import * as FileUtilities from "~/common/file-utilities";
import { css } from "@emotion/react";
import { AnimatePresence, motion } from "framer-motion";
import { Show } from "~/components/utility/Show";
import FilePlaceholder from "~/components/core/ObjectPreview/placeholders/File";
import { clamp } from "lodash";
import { useEventListener } from "~/common/hooks";
const STYLES_POPUP = (theme) => css`
${Styles.CONTAINER_CENTERED};
flex-direction: column;
position: fixed;
width: 100%;
height: 100vh;
top: 0px;
left: 0;
background-color: ${theme.semantic.bgWhite};
@supports ((-webkit-backdrop-filter: blur(75px)) or (backdrop-filter: blur(75px))) {
-webkit-backdrop-filter: blur(75px);
backdrop-filter: blur(75px);
background-color: ${theme.semantic.bgBlurWhiteOP};
}
`;
const STYLES_PLACEHOLDER = css`
width: 64px;
height: 80px;
svg {
height: 100%;
width: 100%;
}
`;
export default function Popup() {
const DEFAULT_DROPPING_STATE = {
isDroppingFiles: false,
totalFilesDropped: undefined,
};
const timerRef = React.useRef();
const [{ isDroppingFiles, totalFilesDropped }, setDroppingState] =
React.useState(DEFAULT_DROPPING_STATE);
const handleDragOver = (e) => {
e.preventDefault();
// NOTE(amine): Hack to hide the popup if the user drags files outside of the app
clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
setDroppingState(DEFAULT_DROPPING_STATE);
}, 100);
};
const handleDragEnter = async (e) => {
e.preventDefault();
const { files } = await FileUtilities.formatDroppedFiles({
dataTransfer: e.dataTransfer,
});
setDroppingState({ totalFilesDropped: files.length || undefined, isDroppingFiles: true });
};
useEventListener("dragenter", handleDragEnter, []);
useEventListener("dragover", handleDragOver, []);
return (
<AnimatePresence>
{isDroppingFiles ? (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2, ease: "easeInOut" }}
css={STYLES_POPUP}
>
<DroppedFilesPlaceholder totalFilesDropped={totalFilesDropped} />
<div style={{ marginTop: 64 }}>
<System.H3 as="p" style={{ textAlign: "center" }}>
Dropping {totalFilesDropped}{" "}
{totalFilesDropped ? Strings.pluralize("file", totalFilesDropped) : "files"} to save
to Slate
</System.H3>
<Show when={!totalFilesDropped || totalFilesDropped > 200}>
<System.H5 as="p" color="textGrayDark">
(we recommend uploading 200 files at a time)
</System.H5>
</Show>
</div>
</motion.div>
) : null}
</AnimatePresence>
);
}
const DroppedFilesPlaceholder = ({ totalFilesDropped = 3 }) => {
const marginRight = clamp(totalFilesDropped - 1, 0, 2) * 8;
return (
<div style={{ position: "relative", right: marginRight }}>
<div css={STYLES_PLACEHOLDER}>
<FilePlaceholder />
</div>
<Show when={totalFilesDropped >= 2}>
<div
style={{ position: "absolute", top: -15, right: -16, zIndex: -1 }}
css={STYLES_PLACEHOLDER}
>
<FilePlaceholder />
</div>
</Show>
<Show when={totalFilesDropped >= 3}>
<div
style={{ position: "absolute", top: 2 * -15, right: 2 * -16, zIndex: -2 }}
css={STYLES_PLACEHOLDER}
>
<FilePlaceholder />
</div>
</Show>
</div>
);
};