Paperjet/frontend/src/features/library/UploadArea.tsx

74 lines
3.3 KiB
TypeScript

import { useRef, useState, type ReactNode } from 'react';
import { useLibrary } from './useLibrary';
import { UploadPickerContext, useUploadPicker } from './upload-context';
export function UploadTrigger({ children, className }: { children: ReactNode; className: string }) {
const openPicker = useUploadPicker();
return <button type="button" onClick={openPicker} className={className}>{children}</button>;
}
export const UploadArea = ({ children }: { children: ReactNode }) => {
const { uploadDocument } = useLibrary();
const [isDragging, setIsDragging] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const processFiles = async (files: FileList) => {
for (let index = 0; index < files.length; index += 1) {
const file = files[index];
if (file.type !== 'application/pdf' && !file.name.toLowerCase().endsWith('.pdf')) continue;
try {
await uploadDocument(file);
} catch (reason) {
console.error('Failed to upload', file.name, reason);
}
}
};
const handleDragOver = (event: React.DragEvent) => {
event.preventDefault();
event.stopPropagation();
setIsDragging(true);
};
const handleDragLeave = (event: React.DragEvent) => {
event.preventDefault();
event.stopPropagation();
setIsDragging(false);
};
const handleDrop = async (event: React.DragEvent) => {
event.preventDefault();
event.stopPropagation();
setIsDragging(false);
if (event.dataTransfer.files.length > 0) await processFiles(event.dataTransfer.files);
};
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files && event.target.files.length > 0) await processFiles(event.target.files);
event.target.value = '';
};
return (
<UploadPickerContext.Provider value={() => fileInputRef.current?.click()}>
<div className="relative min-h-screen" onDragOver={handleDragOver} onDragLeave={handleDragLeave} onDrop={(event) => void handleDrop(event)}>
<input ref={fileInputRef} type="file" accept="application/pdf" onChange={(event) => void handleFileChange(event)} className="hidden" multiple />
{isDragging && (
<div className="pointer-events-none absolute inset-0 z-50 m-4 flex items-center justify-center rounded-3xl border-4 border-dashed border-accent-400 bg-accent-500/10 backdrop-blur-md">
<div className="flex flex-col items-center rounded-3xl border border-white/50 bg-white/95 px-10 py-8 shadow-2xl">
<div className="mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-accent-100 shadow-inner">
<svg className="h-10 w-10 animate-bounce text-accent-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
</svg>
</div>
<h3 className="text-3xl font-heading font-bold tracking-tight text-neutral-900">Drop PDFs here</h3>
<p className="mt-2 font-medium text-neutral-500">Release to upload to your library</p>
</div>
</div>
)}
{children}
</div>
</UploadPickerContext.Provider>
);
};