parent
182b125a9e
commit
4bb2cf65e6
@ -0,0 +1,126 @@
|
||||
import {
|
||||
faArrowUp,
|
||||
faFileCirclePlus,
|
||||
faXmark,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Box, createStyles, Overlay, Stack, Text } from "@mantine/core";
|
||||
import clsx from "clsx";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
import { DropzoneState } from "react-dropzone";
|
||||
|
||||
const useStyle = createStyles((theme) => {
|
||||
return {
|
||||
container: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
inner: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
overflow: "hidden",
|
||||
margin: theme.spacing.md,
|
||||
borderRadius: theme.radius.md,
|
||||
borderWidth: "0.2rem",
|
||||
borderStyle: "dashed",
|
||||
borderColor: theme.colors.gray[7],
|
||||
backgroundColor: theme.fn.rgba(theme.colors.gray[0], 0.4),
|
||||
},
|
||||
accepted: {
|
||||
borderColor: theme.colors.brand[7],
|
||||
backgroundColor: theme.fn.rgba(theme.colors.brand[0], 0.6),
|
||||
},
|
||||
rejected: {
|
||||
borderColor: theme.colors.red[7],
|
||||
backgroundColor: theme.fn.rgba(theme.colors.red[0], 0.9),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export interface DropOverlayProps {
|
||||
state: DropzoneState;
|
||||
zIndex?: number;
|
||||
}
|
||||
|
||||
export const DropOverlay: FunctionComponent<DropOverlayProps> = ({
|
||||
state,
|
||||
children,
|
||||
zIndex = 10,
|
||||
}) => {
|
||||
const {
|
||||
getRootProps,
|
||||
isDragActive,
|
||||
isDragAccept: accepted,
|
||||
isDragReject: rejected,
|
||||
} = state;
|
||||
|
||||
const { classes } = useStyle();
|
||||
|
||||
const visible = isDragActive;
|
||||
|
||||
const icon = useMemo(() => {
|
||||
if (accepted) {
|
||||
return faArrowUp;
|
||||
} else if (rejected) {
|
||||
return faXmark;
|
||||
} else {
|
||||
return faFileCirclePlus;
|
||||
}
|
||||
}, [accepted, rejected]);
|
||||
|
||||
const title = useMemo(() => {
|
||||
if (accepted) {
|
||||
return "Release to Upload";
|
||||
} else if (rejected) {
|
||||
return "Cannot Upload Files";
|
||||
} else {
|
||||
return "Upload Subtitles";
|
||||
}
|
||||
}, [accepted, rejected]);
|
||||
|
||||
const subtitle = useMemo(() => {
|
||||
if (accepted) {
|
||||
return "";
|
||||
} else if (rejected) {
|
||||
return "Some files are invalid";
|
||||
} else {
|
||||
return "Drop to upload";
|
||||
}
|
||||
}, [accepted, rejected]);
|
||||
|
||||
return (
|
||||
<Box sx={{ position: "relative" }} {...getRootProps()}>
|
||||
{visible && (
|
||||
<Box className={classes.container} style={{ zIndex }}>
|
||||
<Stack
|
||||
spacing="xs"
|
||||
className={clsx(classes.inner, {
|
||||
[classes.accepted]: accepted,
|
||||
[classes.rejected]: rejected,
|
||||
})}
|
||||
style={{ zIndex: zIndex + 1 }}
|
||||
>
|
||||
<Box>
|
||||
<FontAwesomeIcon icon={icon} size="3x" />
|
||||
</Box>
|
||||
<Text size="xl">{title}</Text>
|
||||
<Text color="gray" size="sm">
|
||||
{subtitle}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Overlay zIndex={zIndex}></Overlay>
|
||||
</Box>
|
||||
)}
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
@ -1,78 +0,0 @@
|
||||
import {
|
||||
faArrowUp,
|
||||
faFileCirclePlus,
|
||||
faXmark,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Box, Stack, Text } from "@mantine/core";
|
||||
import {
|
||||
Dropzone,
|
||||
DropzoneProps,
|
||||
DropzoneStatus,
|
||||
FullScreenDropzone,
|
||||
FullScreenDropzoneProps,
|
||||
} from "@mantine/dropzone";
|
||||
import { FunctionComponent, useMemo } from "react";
|
||||
|
||||
export type FileProps = Omit<DropzoneProps, "children"> & {
|
||||
inner?: FileInnerComponent;
|
||||
};
|
||||
|
||||
const File: FunctionComponent<FileProps> = ({
|
||||
inner: Inner = FileInner,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<Dropzone {...props}>
|
||||
{(status) => <Inner status={status}></Inner>}
|
||||
</Dropzone>
|
||||
);
|
||||
};
|
||||
|
||||
export type FileOverlayProps = Omit<FullScreenDropzoneProps, "children"> & {
|
||||
inner?: FileInnerComponent;
|
||||
};
|
||||
|
||||
export const FileOverlay: FunctionComponent<FileOverlayProps> = ({
|
||||
inner: Inner = FileInner,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<FullScreenDropzone {...props}>
|
||||
{(status) => <Inner status={status}></Inner>}
|
||||
</FullScreenDropzone>
|
||||
);
|
||||
};
|
||||
|
||||
export type FileInnerProps = {
|
||||
status: DropzoneStatus;
|
||||
};
|
||||
|
||||
type FileInnerComponent = FunctionComponent<FileInnerProps>;
|
||||
|
||||
const FileInner: FileInnerComponent = ({ status }) => {
|
||||
const { accepted, rejected } = status;
|
||||
const icon = useMemo(() => {
|
||||
if (accepted) {
|
||||
return faArrowUp;
|
||||
} else if (rejected) {
|
||||
return faXmark;
|
||||
} else {
|
||||
return faFileCirclePlus;
|
||||
}
|
||||
}, [accepted, rejected]);
|
||||
|
||||
return (
|
||||
<Stack m="lg" align="center" spacing="xs" style={{ pointerEvents: "none" }}>
|
||||
<Box mb="md">
|
||||
<FontAwesomeIcon size="3x" icon={icon}></FontAwesomeIcon>
|
||||
</Box>
|
||||
<Text size="lg">Upload files here</Text>
|
||||
<Text color="dimmed" size="sm">
|
||||
Drag and drop, or click to select
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default File;
|
@ -1,3 +1,4 @@
|
||||
export { default as Action } from "./Action";
|
||||
export * from "./DropOverlay";
|
||||
export * from "./FileBrowser";
|
||||
export * from "./Selector";
|
||||
|
Loading…
Reference in new issue