mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-25 16:40:58 -05:00
Add file pasting and drag-n-drop.
This commit is contained in:
parent
454ee7fd6e
commit
56dda66c1c
2 changed files with 74 additions and 3 deletions
|
@ -255,6 +255,13 @@ function MessageBox({ channel, draft, dispatcher }: Props) {
|
|||
remove={async () => setUploadState({ type: "none" })}
|
||||
onChange={files => setUploadState({ type: "attached", files })}
|
||||
cancel={() => uploadState.type === 'uploading' && uploadState.cancel.cancel("cancel")}
|
||||
append={files => {
|
||||
if (uploadState.type === 'none') {
|
||||
setUploadState({ type: 'attached', files });
|
||||
} else if (uploadState.type === 'attached') {
|
||||
setUploadState({ type: 'attached', files: [ ...uploadState.files, ...files ] });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Action>
|
||||
<TextAreaAutoSize
|
||||
|
|
|
@ -4,7 +4,7 @@ import classNames from "classnames";
|
|||
import { AppContext } from "./RevoltClient";
|
||||
import styles from './FileUploads.module.scss';
|
||||
import Axios, { AxiosRequestConfig } from "axios";
|
||||
import { useContext, useState } from "preact/hooks";
|
||||
import { useContext, useEffect, useState } from "preact/hooks";
|
||||
import Preloader from "../../components/ui/Preloader";
|
||||
import { determineFileSize } from "../../lib/fileSize";
|
||||
import IconButton from '../../components/ui/IconButton';
|
||||
|
@ -17,8 +17,8 @@ type Props = {
|
|||
fileType: 'backgrounds' | 'icons' | 'avatars' | 'attachments' | 'banners'
|
||||
} & (
|
||||
{ behaviour: 'ask', onChange: (file: File) => void } |
|
||||
{ behaviour: 'multi', onChange: (files: File[]) => void } |
|
||||
{ behaviour: 'upload', onUpload: (id: string) => Promise<void> }
|
||||
{ behaviour: 'upload', onUpload: (id: string) => Promise<void> } |
|
||||
{ behaviour: 'multi', onChange: (files: File[]) => void, append?: (files: File[]) => void }
|
||||
) & (
|
||||
{ style: 'icon' | 'banner', defaultPreview?: string, previewURL?: string, width?: number, height?: number } |
|
||||
{ style: 'attachment', attached: boolean, uploading: boolean, cancel: () => void, size?: number }
|
||||
|
@ -107,6 +107,70 @@ export function FileUploader(props: Props) {
|
|||
}
|
||||
}
|
||||
|
||||
if (props.behaviour === 'multi' && props.append) {
|
||||
useEffect(() => {
|
||||
// File pasting.
|
||||
function paste(e: ClipboardEvent) {
|
||||
const items = e.clipboardData?.items;
|
||||
if (typeof items === "undefined") return;
|
||||
if (props.behaviour !== 'multi' || !props.append) return;
|
||||
|
||||
let files = [];
|
||||
for (const item of items) {
|
||||
if (!item.type.startsWith("text/")) {
|
||||
const blob = item.getAsFile();
|
||||
if (blob) {
|
||||
if (blob.size > props.maxFileSize) {
|
||||
openScreen({ id: 'error', error: 'FileTooLarge' });
|
||||
}
|
||||
|
||||
files.push(blob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
props.append(files);
|
||||
}
|
||||
|
||||
// Let the browser know we can drop files.
|
||||
function dragover(e: DragEvent) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
|
||||
}
|
||||
|
||||
// File dropping.
|
||||
function drop(e: DragEvent) {
|
||||
e.preventDefault();
|
||||
if (props.behaviour !== 'multi' || !props.append) return;
|
||||
|
||||
const dropped = e.dataTransfer?.files;
|
||||
if (dropped) {
|
||||
let files = [];
|
||||
for (const item of dropped) {
|
||||
if (item.size > props.maxFileSize) {
|
||||
openScreen({ id: 'error', error: 'FileTooLarge' });
|
||||
}
|
||||
|
||||
files.push(item);
|
||||
}
|
||||
|
||||
props.append(files);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("paste", paste);
|
||||
document.addEventListener("dragover", dragover);
|
||||
document.addEventListener("drop", drop);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("paste", paste);
|
||||
document.removeEventListener("dragover", dragover);
|
||||
document.removeEventListener("drop", drop);
|
||||
};
|
||||
}, [ props.append ]);
|
||||
}
|
||||
|
||||
if (props.style === 'icon' || props.style === 'banner') {
|
||||
const { style, previewURL, defaultPreview, width, height } = props;
|
||||
return (
|
||||
|
|
Loading…
Reference in a new issue