/* global React, PaperCard, Button, Chip, WaxSeal, StageChip, ProgressBar, LogLine, Icons, deriveStages, stageStatuses, overallProgress, chipFor */ // Palimpsest — Mobile workshop view (real API) const { useState: useStateM } = React; function MobileWorkshop(props) { const { state, page, total, currentStage, log, jobId, file, pageCount, cfg, setCfg, cost, wsConnected, hasPdf, errorMsg, onPick, onClear, onStart, flash, canStart, uploading, } = props; const [sheetOpen, setSheetOpen] = useStateM(false); const inputRef = React.useRef(null); const sizeMB = file ? (file.size / 1048576).toFixed(1) : null; return (
// Palimpsest

Drop your old scan, get a clean scientific document back.

palimpsest · a manuscript page scraped clean and written over, with traces of the original still showing through. read more ↗
{/* Dropzone */}
!file && inputRef.current?.click()} style={{ cursor: file ? 'default' : 'pointer' }} > e.target.files[0] && onPick(e.target.files[0])} />
{file ? 'staged · ready' : 'tap to browse a PDF'}
{file ? 'tap start below' : 'scanned · max 60 MB'}
{file && (
{file.name}
{pageCount ? `${pageCount} p · ` : ''}{sizeMB} MB
staged
)} {/* Config summary -> bottom sheet */}
setSheetOpen(true)}>
SPECIMEN
{(window.COSTS[cfg.model]?.label || cfg.model)} {cfg.ocr} {cost != null ? `≈ $${cost.toFixed(2)}` : '— · pick a PDF'}
tap ›
{/* Inline terminal section */} {state !== 'idle' && (
palimpsest@workshop ~/jobs/{jobId || '—'}
{file?.name || '(resumed)'} {jobId && #{jobId}}
{chipFor(state, page, total)}
{(() => { const s = deriveStages(state, currentStage); const t = stageStatuses(state, currentStage, page, total); return ['preprocess', 'ocr', 'rewrite', 'compile'].map((n, i) => ( )); })()}
{(() => { const p = overallProgress(state, currentStage, page, total); return (
// progress {p.label} · {p.sub}
); })()}
# pipeline.log {state === 'processing' ? 'live' : state === 'done' ? 'complete' : 'halted'}
{log.slice(-12).map((l, i) => )}
{state === 'done' &&
} {state === 'processing' && ( ↳ outputs unlock at compile )} {state === 'done' && ( <> {hasPdf && ( download pdf )} .tex Overleaf )} {state === 'error' && ( <> {jobId && ( .tex if any )} ↳ {errorMsg || 'halted'} )}
)}
{/* Sticky bottom CTA — only when idle and no in-flight */} {!sheetOpen && state === 'idle' && (
)} {/* Bottom sheet — specimen config */} {sheetOpen && ( <>
setSheetOpen(false)} />

Specimen · pipeline settings

MODEL
OCR ENGINE
{['vision','mathpix'].map(o => ( ))}
SOURCE
{['preserve images','text only'].map(o => ( ))}
ESTIMATED COST
{cost != null ? `$${cost.toFixed(2)}` : '—'} per run
)}
); } Object.assign(window, { MobileWorkshop });