Rescue Paperjet v1 implementation
This commit is contained in:
parent
7ff5c8130d
commit
db9e2ca51b
83 changed files with 6186 additions and 3894 deletions
|
|
@ -1,88 +1,74 @@
|
|||
import { useRef, useState } from 'react'
|
||||
import { useLibrary } from './useLibrary'
|
||||
import { useRef, useState, type ReactNode } from 'react';
|
||||
import { useLibrary } from './useLibrary';
|
||||
import { UploadPickerContext, useUploadPicker } from './upload-context';
|
||||
|
||||
export const UploadArea = ({ children }: { children: React.ReactNode }) => {
|
||||
const { uploadDocument } = useLibrary()
|
||||
const [isDragging, setIsDragging] = useState(false)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
export function UploadTrigger({ children, className }: { children: ReactNode; className: string }) {
|
||||
const openPicker = useUploadPicker();
|
||||
return <button type="button" onClick={openPicker} className={className}>{children}</button>;
|
||||
}
|
||||
|
||||
const handleDragOver = (e: React.DragEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setIsDragging(true)
|
||||
}
|
||||
|
||||
const handleDragLeave = (e: React.DragEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setIsDragging(false)
|
||||
}
|
||||
|
||||
const handleDrop = async (e: React.DragEvent) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setIsDragging(false)
|
||||
|
||||
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
||||
await processFiles(e.dataTransfer.files)
|
||||
}
|
||||
}
|
||||
|
||||
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files && e.target.files.length > 0) {
|
||||
await processFiles(e.target.files)
|
||||
// Reset input so the same file can be selected again
|
||||
e.target.value = ''
|
||||
}
|
||||
}
|
||||
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 now, process one by one
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
if (file.type === 'application/pdf') {
|
||||
try {
|
||||
await uploadDocument(file)
|
||||
} catch (err) {
|
||||
console.error('Failed to upload', file.name, err)
|
||||
// Could show toast notification here
|
||||
}
|
||||
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 (
|
||||
<div
|
||||
className="relative min-h-screen"
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
accept="application/pdf"
|
||||
ref={fileInputRef}
|
||||
onChange={handleFileChange}
|
||||
className="hidden"
|
||||
multiple
|
||||
/>
|
||||
|
||||
{/* Invisible overlay that appears when dragging to prevent flickering */}
|
||||
{isDragging && (
|
||||
<div className="absolute inset-0 z-50 bg-accent-500/10 dark:bg-accent-900/20 backdrop-blur-md border-4 border-dashed border-accent-400 dark:border-accent-500 rounded-3xl m-4 flex items-center justify-center transition-all pointer-events-none">
|
||||
<div className="bg-white/95 dark:bg-gray-800/95 px-10 py-8 rounded-3xl shadow-2xl shadow-accent-500/20 flex flex-col items-center transform scale-105 transition-transform duration-300 border border-white/50">
|
||||
<div className="w-20 h-20 bg-gradient-to-br from-accent-100 to-accent-200 dark:from-accent-800 dark:to-accent-900 rounded-full flex items-center justify-center mb-6 shadow-inner">
|
||||
<svg className="w-10 h-10 text-accent-600 dark:text-accent-300 animate-bounce" 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 text-gray-900 dark:text-white tracking-tight">Drop PDFs here</h3>
|
||||
<p className="text-gray-500 dark:text-gray-400 mt-2 font-medium">Release to upload to your library</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<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 />
|
||||
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue