feat: Added drag drop, progress bar

This commit is contained in:
florian 2024-03-28 20:30:14 +01:00
parent b12f72bde1
commit 2ec8dbdc69
3 changed files with 99 additions and 24 deletions

View File

@ -0,0 +1,16 @@
const ProgressBar = ({ value, max }: { value: number; max: number }) => {
return (
<div className="w-full bg-gray-200 rounded-lg dark:bg-neutral-900">
{max !== undefined && value !== undefined && max > 0 && (
<div
className="bg-pink-600 text-sm font-medium text-pink-100 text-center p-1 leading-none rounded-lg"
style={{ width: `${Math.floor((value * 100) / max)}%` }}
>
{Math.floor((value * 100) / max)}&nbsp;%
</div>
)}
</div>
);
};
export default ProgressBar;

View File

@ -15,6 +15,7 @@ import { formatFileSize } from '../utils';
import BlobList from '../components/BlobList/BlobList';
import './Transfer.css';
import { useNavigate, useParams } from 'react-router-dom';
import ProgressBar from '../components/ProgressBar/ProgressBar';
type TransferStatus = {
[key: string]: {
@ -134,14 +135,7 @@ export const Transfer = () => {
)}
</div>
<div>
<div className="w-full bg-gray-200 rounded-lg dark:bg-neutral-800">
<div
className="bg-pink-600 text-sm font-medium text-pink-100 text-center p-1 leading-none rounded-lg"
style={{ width: `${Math.floor((transferStatus.size * 100) / transferStatus.fullSize)}%` }}
>
{Math.floor((transferStatus.size * 100) / transferStatus.fullSize)}&nbsp;%
</div>
</div>
<ProgressBar value={transferStatus.size} max={transferStatus.fullSize} />
{
<div className="message">
{formatFileSize(transferStatus.size)} / {formatFileSize(transferStatus.fullSize)} transferred

View File

@ -1,64 +1,129 @@
import { useEffect, useRef, useState } from 'react';
import { ChangeEvent, DragEvent, useEffect, useState } from 'react';
import { useServers } from '../utils/useServers';
import { BlossomClient } from 'blossom-client-sdk';
import { useNDK } from '../ndk';
import { useServerInfo } from '../utils/useServerInfo';
import { useQueryClient } from '@tanstack/react-query';
import { ArrowUpOnSquareIcon } from '@heroicons/react/24/outline';
import ProgressBar from '../components/ProgressBar/ProgressBar';
type TransferStats = {
enabled: boolean;
size: number;
transferred: number;
};
function Upload() {
const servers = useServers();
const { signEventTemplate } = useNDK();
const { serverInfo } = useServerInfo();
const inputRef = useRef<HTMLInputElement>(null);
const queryClient = useQueryClient();
const [uploadTarget, setUploadTarget] = useState<{ [key: string]: boolean }>({});
const [transfers, setTransfers] = useState<{ [key: string]: TransferStats }>({});
const [files, setFiles] = useState<File[]>([]);
const upload = async () => {
if (inputRef.current && inputRef.current.files) {
if (files && files.length) {
// sum files sizes
const totalSize = files.reduce((acc, f) => acc + f.size, 0);
// set all entries size to totalSize
setTransfers(ut => {
const newTransfers = { ...ut };
for (const server of servers) {
if (newTransfers[server.name].enabled) {
newTransfers[server.name].size = totalSize;
}
}
return newTransfers;
});
for (const server of servers) {
if (!uploadTarget[server.name]) {
if (!transfers[server.name]?.enabled) {
continue;
}
const serverUrl = serverInfo[server.name].url;
for (const file of inputRef.current.files) {
for (const file of files) {
const uploadAuth = await BlossomClient.getUploadAuth(file, signEventTemplate, 'Upload Blob');
const newBlob = await BlossomClient.uploadBlob(serverUrl, file, uploadAuth);
transfers[server.name].transferred += file.size;
console.log(newBlob);
}
queryClient.invalidateQueries({ queryKey: ['blobs', server.name] });
setFiles([]);
}
}
};
const clearTransfers = () => {
setTransfers(servers.reduce((acc, s) => ({ ...acc, [s.name]: { enabled: true, size: 0, transferred: 0 } }), {}));
};
useEffect(() => {
setUploadTarget(servers.reduce((acc, s) => ({ ...acc, [s.name]: true }), {}));
clearTransfers();
}, [servers]);
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
const selectedFiles = event.target.files;
if (selectedFiles && selectedFiles.length > 0) {
const newFiles = Array.from(selectedFiles);
setFiles(prevFiles => [...prevFiles, ...newFiles]);
}
};
const handleDrop = (event: DragEvent<HTMLLabelElement>) => {
event.preventDefault();
const droppedFiles = event.dataTransfer?.files;
if (droppedFiles && droppedFiles.length > 0) {
const newFiles = Array.from(droppedFiles);
setFiles(prevFiles => [...prevFiles, ...newFiles]);
}
};
return (
<>
<h2>Upload</h2>
<div className=" bg-neutral-800 rounded-xl p-4 text-neutral-400 gap-4 flex flex-col">
<input className=" cursor-pointer" type="file" ref={inputRef} multiple />
<input id="browse" type="file" hidden multiple onChange={handleFileChange} />
<label
htmlFor="browse"
className="p-8 bg-neutral-700 rounded-lg hover:text-white text-neutral-400 border-dashed border-neutral-500 border-2 block cursor-pointer text-center"
onDrop={handleDrop}
onDragOver={event => event.preventDefault()}
>
<ArrowUpOnSquareIcon className="w-8 inline" /> Browse or drag & drop
</label>
<div className="cursor-pointer grid gap-2" style={{ gridTemplateColumns: '1em 20em auto' }}>
{servers.map(s => (
<div className="cursor-pointer flex flex-row gap-2 " key={s.name}>
<>
<input
className="w-5 accent-pink-700 hover:accent-pink-600"
id={s.name}
type="checkbox"
checked={uploadTarget[s.name] || false}
onChange={e => setUploadTarget(ut => ({ ...ut, [s.name]: e.target.checked }))}
checked={transfers[s.name]?.enabled || false}
onChange={e =>
setTransfers(ut => ({ ...ut, [s.name]: { enabled: e.target.checked, transferred: 0, size: 0 } }))
}
/>
<label htmlFor={s.name} className="cursor-pointer">
{s.name}
</label>
</div>
{transfers[s.name]?.enabled ? (
<ProgressBar value={transfers[s.name].transferred} max={transfers[s.name].size} />
) : (
<div></div>
)}
</>
))}
</div>
<button className="p-2 px-4 bg-neutral-600 hover:bg-pink-700 text-white rounded-lg w-2/6" onClick={() => upload()}>
Upload
</button>
<button
className="p-2 px-4 bg-neutral-600 hover:bg-pink-700 text-white rounded-lg w-2/6"
onClick={() => upload()}
>
Upload{files.length > 0 ? (files.length == 1 ? ` 1 file` : ` ${files.length} files`) : ''}
</button>
</div>
</>
);