// astroparse — upload (folio drop) + animated pipeline screens function UploadScreen({ onFile, onSample, onImportSession }) { const [dragging, setDragging] = React.useState(false); const fileRef = React.useRef(null); const sessionRef = React.useRef(null); const handleDrop = (e) => { e.preventDefault(); setDragging(false); const f = e.dataTransfer.files && e.dataTransfer.files[0]; if (f) onFile(f.name); }; return (
astroparse
{ e.preventDefault(); setDragging(true); }} onDragLeave={() => setDragging(false)} onDrop={handleDrop} onClick={() => fileRef.current && fileRef.current.click()} >
Place a manuscript here
drop an astronomy PDF, or click to browse
parsed with pymupdf4llm · annotated against the literature via Pathfinder
{ const f = e.target.files[0]; if (f) onFile(f.name); }} />
· { const f = e.target.files[0]; if (!f) return; const r = new FileReader(); r.onload = () => onImportSession(r.result); r.readAsText(f); }} />
prototype — parsing is simulated; any dropped PDF opens the bundled manuscript (Mowla & Iyer 2024)
); } function PipelineScreen({ fileName, onDone }) { const stages = window.ASTROPARSE_DATA.pipelineStages; // progress: index of current stage; logIdx: how many log lines shown in current stage const [stageIdx, setStageIdx] = React.useState(0); const [logIdx, setLogIdx] = React.useState(0); const [finished, setFinished] = React.useState(false); const doneRef = React.useRef(false); React.useEffect(() => { if (finished) { const t = setTimeout(() => { if (!doneRef.current) { doneRef.current = true; onDone(); } }, 1100); return () => clearTimeout(t); } const stage = stages[stageIdx]; if (!stage) { setFinished(true); return; } if (logIdx < stage.logs.length) { const t = setTimeout(() => setLogIdx(logIdx + 1), 420); return () => clearTimeout(t); } const t = setTimeout(() => { setStageIdx(stageIdx + 1); setLogIdx(0); }, 380); return () => clearTimeout(t); }, [stageIdx, logIdx, finished]); return (
astroparse
{fileName} {finished ? 'ready' : 'in preparation'}
    {stages.map((s, i) => { const state = i < stageIdx ? 'done' : i === stageIdx && !finished ? 'active' : finished ? 'done' : 'pending'; const logsShown = state === 'done' ? s.logs.length : state === 'active' ? logIdx : 0; return (
  1. {s.num}. {s.name} {s.tool} {state === 'done' ? '\u2713' : state === 'active' ? '\u2026' : ''}
    {state !== 'pending' && (
    {s.logs.slice(0, logsShown).map((l, j) => (
    {l.replace('{file}', fileName)}
    ))}
    )}
  2. ); })}
); } Object.assign(window, { UploadScreen, PipelineScreen });