Files
breakpilot-lehrer/studio-v2/app/worksheet-cleanup/_components/UploadStep.tsx
Benjamin Admin b6983ab1dc [split-required] Split 500-1000 LOC files across all services
backend-lehrer (5 files):
- alerts_agent/db/repository.py (992 → 5), abitur_docs_api.py (956 → 3)
- teacher_dashboard_api.py (951 → 3), services/pdf_service.py (916 → 3)
- mail/mail_db.py (987 → 6)

klausur-service (5 files):
- legal_templates_ingestion.py (942 → 3), ocr_pipeline_postprocess.py (929 → 4)
- ocr_pipeline_words.py (876 → 3), ocr_pipeline_ocr_merge.py (616 → 2)
- KorrekturPage.tsx (956 → 6)

website (5 pages):
- mail (985 → 9), edu-search (958 → 8), mac-mini (950 → 7)
- ocr-labeling (946 → 7), audit-workspace (871 → 4)

studio-v2 (5 files + 1 deleted):
- page.tsx (946 → 5), MessagesContext.tsx (925 → 4)
- korrektur (914 → 6), worksheet-cleanup (899 → 6)
- useVocabWorksheet.ts (888 → 3)
- Deleted dead page-original.tsx (934 LOC)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 23:35:37 +02:00

126 lines
6.4 KiB
TypeScript

'use client'
import { GlassCard } from './GlassCard'
interface UploadStepProps {
isDark: boolean
previewUrl: string | null
file: File | null
removeHandwriting: boolean
setRemoveHandwriting: (v: boolean) => void
reconstructLayout: boolean
setReconstructLayout: (v: boolean) => void
inpaintingMethod: string
setInpaintingMethod: (v: string) => void
isPreviewing: boolean
onDrop: (e: React.DragEvent) => void
onFileSelect: (file: File) => void
onPreview: () => void
onQRClick: () => void
}
export function UploadStep({
isDark, previewUrl, file,
removeHandwriting, setRemoveHandwriting,
reconstructLayout, setReconstructLayout,
inpaintingMethod, setInpaintingMethod,
isPreviewing, onDrop, onFileSelect, onPreview, onQRClick
}: UploadStepProps) {
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<GlassCard className="col-span-1" delay={100}>
<div
className="border-2 border-dashed border-white/20 rounded-2xl p-8 text-center cursor-pointer transition-all hover:border-purple-400/50 hover:bg-white/5 min-h-[280px] flex flex-col items-center justify-center"
onDrop={onDrop}
onDragOver={(e) => e.preventDefault()}
onClick={() => document.getElementById('file-input')?.click()}
>
<input id="file-input" type="file" accept="image/*"
onChange={(e) => e.target.files?.[0] && onFileSelect(e.target.files[0])}
className="hidden" />
{previewUrl ? (
<div className="space-y-4">
<img src={previewUrl} alt="Preview" className="max-h-40 mx-auto rounded-xl shadow-2xl" />
<p className="text-white font-medium text-sm">{file?.name}</p>
<p className="text-white/50 text-xs">Klicke zum Ändern</p>
</div>
) : (
<>
<svg className="w-16 h-16 mx-auto mb-4 text-white/30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.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>
<p className="text-xl font-semibold text-white mb-2">Datei auswählen</p>
<p className="text-white/50 text-sm mb-2">Ziehe ein Bild hierher oder klicke</p>
<p className="text-white/30 text-xs">PNG, JPG, JPEG</p>
</>
)}
</div>
</GlassCard>
<GlassCard className="col-span-1" delay={150}>
<div
className="border-2 border-dashed border-white/20 rounded-2xl p-8 text-center cursor-pointer transition-all hover:border-purple-400/50 hover:bg-white/5 min-h-[280px] flex flex-col items-center justify-center"
onClick={onQRClick}
>
<div className="w-16 h-16 mx-auto mb-4 rounded-xl bg-purple-500/20 flex items-center justify-center">
<span className="text-3xl">📱</span>
</div>
<p className="text-xl font-semibold text-white mb-2">Mit Handy scannen</p>
<p className="text-white/50 text-sm mb-2">QR-Code scannen um Foto hochzuladen</p>
<p className="text-white/30 text-xs">Im lokalen Netzwerk</p>
</div>
</GlassCard>
{file && (
<>
<GlassCard delay={200}>
<h3 className="text-lg font-semibold text-white mb-4">Optionen</h3>
<div className="space-y-4">
<label className="flex items-center gap-4 cursor-pointer group">
<input type="checkbox" checked={removeHandwriting} onChange={(e) => setRemoveHandwriting(e.target.checked)}
className="w-5 h-5 rounded bg-white/10 border-white/20 text-purple-500 focus:ring-purple-500" />
<div>
<span className="text-white font-medium group-hover:text-purple-300 transition-colors">Handschrift entfernen</span>
<p className="text-white/40 text-sm">Erkennt und entfernt handgeschriebene Inhalte</p>
</div>
</label>
<label className="flex items-center gap-4 cursor-pointer group">
<input type="checkbox" checked={reconstructLayout} onChange={(e) => setReconstructLayout(e.target.checked)}
className="w-5 h-5 rounded bg-white/10 border-white/20 text-purple-500 focus:ring-purple-500" />
<div>
<span className="text-white font-medium group-hover:text-purple-300 transition-colors">Layout rekonstruieren</span>
<p className="text-white/40 text-sm">Erstellt bearbeitbare Textblöcke</p>
</div>
</label>
</div>
</GlassCard>
<GlassCard delay={300}>
<h3 className="text-lg font-semibold text-white mb-4">Methode</h3>
<select value={inpaintingMethod} onChange={(e) => setInpaintingMethod(e.target.value)}
className="w-full p-3 rounded-xl bg-white/10 border border-white/20 text-white focus:ring-2 focus:ring-purple-500 focus:border-transparent">
<option value="auto">Automatisch (empfohlen)</option>
<option value="opencv_telea">OpenCV Telea (schnell)</option>
<option value="opencv_ns">OpenCV NS (glatter)</option>
</select>
<p className="text-white/40 text-sm mt-3">
Die automatische Methode wählt die beste Option basierend auf dem Bildinhalt.
</p>
</GlassCard>
<div className="col-span-1 lg:col-span-2 flex justify-center">
<button onClick={onPreview} disabled={isPreviewing}
className="px-8 py-4 rounded-2xl font-semibold text-lg bg-gradient-to-r from-purple-500 to-pink-500 text-white hover:shadow-lg hover:shadow-purple-500/30 transition-all disabled:opacity-50 flex items-center gap-3">
{isPreviewing ? (
<><div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" />Analysiere...</>
) : (
<><svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" /></svg>Vorschau</>
)}
</button>
</div>
</>
)}
</div>
)
}