feat: drag'n'drop with directory

This commit is contained in:
lyonbot committed 2025-01-19 14:46:33 +08:00
1 parent 845a7aa5b5
commit 8faf1a233e
2 files changed
+61 -6

No files matched your search

+11 -6
View File
@@ -2,6 +2,7 @@ import { memo, useEffect, useMemo, useRef, useState } from 'react';
import { useConsistCallback } from '../utils/useConsistCallback';
import { isEqual } from '../utils/isEqual';
import { createThumbnail } from '../utils/createThumbnail';
import { getFilesFromDataTransferItem } from '../utils/fileEntry';
interface Props {
text?: string;
@@ -105,10 +106,13 @@ export const ContentInput = memo<Props>((props) => {
e.preventDefault();
e.stopPropagation();
const droppedFiles = Array.from(e.dataTransfer!.files);
if (droppedFiles.length) {
handleFilesChange((prev) => [...prev, ...droppedFiles]);
}
const promises = Array.from(e.dataTransfer?.items || [], getFilesFromDataTransferItem)
Promise.all(promises).then((files) => {
const droppedFiles = ([] as File[]).concat(...files);
if (droppedFiles.length) {
handleFilesChange((prev) => [...prev, ...droppedFiles]);
}
});
};
window.addEventListener('drop', handleDrop, true);
@@ -184,7 +188,7 @@ export const ContentInput = memo<Props>((props) => {
Add file
</button>
{files.map((file, index) => <UploadedFileItem file={file} index={index} removeFile={removeFile} key={index} />)}
{files.map((file, index) => <AttachedFileItem file={file} index={index} removeFile={removeFile} key={index} />)}
<button onClick={doClear} className='btn-gray' key='clearBtn'>
Clear
@@ -209,7 +213,7 @@ declare global {
}
}
function UploadedFileItem({ index, file, removeFile }: { index: number; file: File; removeFile: (index: number) => void; }) {
function AttachedFileItem({ index, file, removeFile }: { index: number; file: File; removeFile: (index: number) => void; }) {
const [url, setUrl] = useState<string>();
useEffect(() => {
const url = URL.createObjectURL(file);
@@ -250,3 +254,4 @@ export async function addThumbnail(file: File) {
return true;
}
+50
View File
@@ -0,0 +1,50 @@
export async function getFilesFromDataTransferItem(item: DataTransferItem) {
const entry = item.webkitGetAsEntry?.();
const allFiles: File[] = [];
if (entry?.isDirectory) {
const dir = entry as FileSystemDirectoryEntry;
await readDirectory(dir, allFiles, `${dir.name}/`);
return allFiles;
}
if (entry?.isFile) {
const file = await getFile(entry as FileSystemFileEntry);
allFiles.push(file);
return allFiles;
}
return [];
}
function readDirectory(directory: FileSystemDirectoryEntry, allFiles: File[], pathPrefix: string): Promise<void> {
return new Promise((resolve) => {
const reader = directory.createReader();
reader.readEntries(async (entries) => {
for (const entry of entries) {
if (entry.isDirectory) {
await readDirectory(entry as FileSystemDirectoryEntry, allFiles, `${pathPrefix}${entry.name}/`);
} else if (entry.isFile) {
const originalFile = await getFile(entry as FileSystemFileEntry);
const file = new File(
[originalFile],
`${pathPrefix}${entry.name}`,
{
type: originalFile.type,
lastModified: originalFile.lastModified,
}
);
allFiles.push(file);
}
}
resolve();
});
});
}
function getFile(fileEntry: FileSystemFileEntry): Promise<File> {
return new Promise((resolve, reject) => {
fileEntry.file((file) => {
resolve(file);
}, reject);
});
}