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" })}
|
remove={async () => setUploadState({ type: "none" })}
|
||||||
onChange={files => setUploadState({ type: "attached", files })}
|
onChange={files => setUploadState({ type: "attached", files })}
|
||||||
cancel={() => uploadState.type === 'uploading' && uploadState.cancel.cancel("cancel")}
|
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>
|
</Action>
|
||||||
<TextAreaAutoSize
|
<TextAreaAutoSize
|
||||||
|
|
|
@ -4,7 +4,7 @@ import classNames from "classnames";
|
||||||
import { AppContext } from "./RevoltClient";
|
import { AppContext } from "./RevoltClient";
|
||||||
import styles from './FileUploads.module.scss';
|
import styles from './FileUploads.module.scss';
|
||||||
import Axios, { AxiosRequestConfig } from "axios";
|
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 Preloader from "../../components/ui/Preloader";
|
||||||
import { determineFileSize } from "../../lib/fileSize";
|
import { determineFileSize } from "../../lib/fileSize";
|
||||||
import IconButton from '../../components/ui/IconButton';
|
import IconButton from '../../components/ui/IconButton';
|
||||||
|
@ -17,8 +17,8 @@ type Props = {
|
||||||
fileType: 'backgrounds' | 'icons' | 'avatars' | 'attachments' | 'banners'
|
fileType: 'backgrounds' | 'icons' | 'avatars' | 'attachments' | 'banners'
|
||||||
} & (
|
} & (
|
||||||
{ behaviour: 'ask', onChange: (file: File) => void } |
|
{ 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: 'icon' | 'banner', defaultPreview?: string, previewURL?: string, width?: number, height?: number } |
|
||||||
{ style: 'attachment', attached: boolean, uploading: boolean, cancel: () => void, size?: 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') {
|
if (props.style === 'icon' || props.style === 'banner') {
|
||||||
const { style, previewURL, defaultPreview, width, height } = props;
|
const { style, previewURL, defaultPreview, width, height } = props;
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in a new issue