feat: drag&drop upload, default 1h links, Media-Tool mit Kino-Stub
This commit is contained in:
@@ -2862,6 +2862,7 @@ function PublicUpload({ token }) {
|
||||
const [done, setDone] = useState([]);
|
||||
const [msg, setMsg] = useState(null);
|
||||
const [attLeft, setAttLeft] = useState(null);
|
||||
const [dragging, setDragging] = useState(false);
|
||||
const fileRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -2892,8 +2893,8 @@ function PublicUpload({ token }) {
|
||||
} catch(e) { setMsg({text:'Netzwerkfehler: '+e.message,type:'error'}); }
|
||||
};
|
||||
|
||||
const doUpload = async () => {
|
||||
const files = fileRef.current?.files;
|
||||
const doUpload = async (droppedFiles) => {
|
||||
const files = droppedFiles || fileRef.current?.files;
|
||||
if (!files?.length) { fileRef.current?.click(); return; }
|
||||
setUploading(true); setMsg(null);
|
||||
const newDone = [];
|
||||
@@ -2919,6 +2920,22 @@ function PublicUpload({ token }) {
|
||||
setUploading(false);
|
||||
};
|
||||
|
||||
const onDragOver = e => { e.preventDefault(); setDragging(true); };
|
||||
const onDragLeave = e => { if (!e.currentTarget.contains(e.relatedTarget)) setDragging(false); };
|
||||
const onDrop = e => {
|
||||
e.preventDefault(); setDragging(false);
|
||||
if (!fileRef.current) return;
|
||||
// DataTransfer.files is read-only – assign via input to trigger React update
|
||||
const dt = e.dataTransfer;
|
||||
if (!dt.files.length) return;
|
||||
// Assign dropped files to the file input
|
||||
Object.defineProperty(fileRef.current, 'files', { value: dt.files, writable: true });
|
||||
fileRef.current.files = dt.files;
|
||||
// Trigger display update by reading back
|
||||
setMsg({text:`${dt.files.length} Datei${dt.files.length!==1?'en':''} ausgewählt`,type:'ok'});
|
||||
doUpload(dt.files);
|
||||
};
|
||||
|
||||
const fmtDate = d => new Date(d).toLocaleString('de-DE',{timeZone:'Europe/Berlin',day:'2-digit',month:'2-digit',year:'numeric',hour:'2-digit',minute:'2-digit'});
|
||||
|
||||
const C = {
|
||||
@@ -2928,6 +2945,7 @@ function PublicUpload({ token }) {
|
||||
infoBox: {background:'rgba(78,205,196,0.08)',border:'1px solid rgba(78,205,196,0.2)',borderRadius:8,padding:'10px 12px',fontSize:12,color:'rgba(255,255,255,0.6)',marginBottom:14},
|
||||
btn: {width:'100%',background:'#4ecdc4',border:'none',borderRadius:8,color:'#0d0d0f',cursor:'pointer',fontFamily:"'Courier New',monospace",fontSize:14,fontWeight:700,padding:12,marginTop:12},
|
||||
msg: t=>({borderRadius:8,padding:'10px 12px',fontSize:13,marginTop:10,...(t==='ok'?{background:'rgba(78,205,196,0.12)',border:'1px solid rgba(78,205,196,0.3)',color:'#4ecdc4'}:t==='warn'?{background:'rgba(255,230,109,0.12)',border:'1px solid rgba(255,230,109,0.3)',color:'#ffe66d'}:{background:'rgba(255,107,157,0.12)',border:'1px solid rgba(255,107,157,0.3)',color:'#ff6b9d'})}),
|
||||
dropZone: active=>({border:`2px dashed ${active?'#4ecdc4':'rgba(255,255,255,0.18)'}`,borderRadius:12,padding:'28px 16px',textAlign:'center',cursor:'pointer',transition:'border-color 0.15s, background 0.15s',background:active?'rgba(78,205,196,0.07)':'rgba(255,255,255,0.02)',marginBottom:12}),
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -2952,8 +2970,21 @@ function PublicUpload({ token }) {
|
||||
|
||||
{phase==='upload' && info && <>
|
||||
<div style={C.infoBox}>✓ Zugang OK · max {info.max_size_mb} MB pro Datei · bis {fmtDate(info.expires_at)}</div>
|
||||
<input type="file" ref={fileRef} multiple style={{...C.inp,padding:8,cursor:'pointer'}}/>
|
||||
<button onClick={doUpload} disabled={uploading} style={{...C.btn,opacity:uploading?0.5:1}}>
|
||||
<div
|
||||
style={C.dropZone(dragging)}
|
||||
onDragOver={onDragOver}
|
||||
onDragLeave={onDragLeave}
|
||||
onDrop={onDrop}
|
||||
onClick={()=>fileRef.current?.click()}
|
||||
>
|
||||
<div style={{fontSize:28,marginBottom:6}}>{dragging?'📂':'📁'}</div>
|
||||
<div style={{color:dragging?'#4ecdc4':'rgba(255,255,255,0.5)',fontSize:13}}>
|
||||
{dragging?'Loslassen zum Hochladen':'Dateien hierher ziehen oder klicken'}
|
||||
</div>
|
||||
<div style={{color:'rgba(255,255,255,0.25)',fontSize:11,marginTop:4}}>max {info.max_size_mb} MB pro Datei</div>
|
||||
</div>
|
||||
<input type="file" ref={fileRef} multiple onChange={()=>doUpload()} style={{display:'none'}}/>
|
||||
<button onClick={()=>doUpload()} disabled={uploading} style={{...C.btn,opacity:uploading?0.5:1}}>
|
||||
{uploading?'⏳ Lädt hoch…':'⬆ Hochladen'}
|
||||
</button>
|
||||
{msg && <div style={C.msg(msg.type)}>{msg.text}</div>}
|
||||
|
||||
Reference in New Issue
Block a user