[split-required] Split 58 monoliths across Python, Go, TypeScript (Phases 1-3)
Phase 1 — Python (klausur-service): 5 monoliths → 36 files - dsfa_corpus_ingestion.py (1,828 LOC → 5 files) - cv_ocr_engines.py (2,102 LOC → 7 files) - cv_layout.py (3,653 LOC → 10 files) - vocab_worksheet_api.py (2,783 LOC → 8 files) - grid_build_core.py (1,958 LOC → 6 files) Phase 2 — Go (edu-search-service, school-service): 8 monoliths → 19 files - staff_crawler.go (1,402 → 4), policy/store.go (1,168 → 3) - policy_handlers.go (700 → 2), repository.go (684 → 2) - search.go (592 → 2), ai_extraction_handlers.go (554 → 2) - seed_data.go (591 → 2), grade_service.go (646 → 2) Phase 3 — TypeScript (admin-lehrer): 45 monoliths → 220+ files - sdk/types.ts (2,108 → 16 domain files) - ai/rag/page.tsx (2,686 → 14 files) - 22 page.tsx files split into _components/ + _hooks/ - 11 component files split into sub-components - 10 SDK data catalogs added to loc-exceptions - Deleted dead backup index_original.ts (4,899 LOC) All original public APIs preserved via re-export facades. Zero new errors: Python imports verified, Go builds clean, TypeScript tsc --noEmit shows only pre-existing errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback, useRef } from 'react'
|
||||
import type { StructureBox, StructureGraphic } from '@/app/(admin)/ai/ocr-kombi/types'
|
||||
import type { EditableCell } from './StepReconstructionTypes'
|
||||
import { colTypeColor } from './StepReconstructionTypes'
|
||||
import { StructureLayer } from './StructureLayer'
|
||||
|
||||
interface ReconstructionSimpleViewProps {
|
||||
cells: EditableCell[]
|
||||
dewarpedUrl: string
|
||||
zoom: number
|
||||
imageNaturalSize: { w: number; h: number } | null
|
||||
imageNaturalH: number
|
||||
emptyCellIds: Set<string>
|
||||
showEmptyHighlight: boolean
|
||||
structureBoxes: StructureBox[]
|
||||
structureGraphics: StructureGraphic[]
|
||||
showStructure: boolean
|
||||
onTextChange: (cellId: string, newText: string) => void
|
||||
onKeyDown: (e: React.KeyboardEvent, cellId: string) => void
|
||||
onResetCell: (cellId: string) => void
|
||||
onImageLoad: () => void
|
||||
getDisplayText: (cell: EditableCell) => string
|
||||
isEdited: (cell: EditableCell) => boolean
|
||||
imageRef: React.RefObject<HTMLImageElement | null>
|
||||
}
|
||||
|
||||
export function ReconstructionSimpleView({
|
||||
cells,
|
||||
dewarpedUrl,
|
||||
zoom,
|
||||
imageNaturalSize,
|
||||
imageNaturalH,
|
||||
emptyCellIds,
|
||||
showEmptyHighlight,
|
||||
structureBoxes,
|
||||
structureGraphics,
|
||||
showStructure,
|
||||
onTextChange,
|
||||
onKeyDown,
|
||||
onResetCell,
|
||||
onImageLoad,
|
||||
getDisplayText,
|
||||
isEdited,
|
||||
imageRef,
|
||||
}: ReconstructionSimpleViewProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Font size based on image natural height (not container) scaled by zoom
|
||||
const getFontSize = useCallback((bboxH: number): number => {
|
||||
const baseH = imageNaturalH || 800
|
||||
const px = (bboxH / 100) * baseH * 0.55
|
||||
return Math.max(8, Math.min(18, px * (zoom / 100)))
|
||||
}, [imageNaturalH, zoom])
|
||||
|
||||
return (
|
||||
<div className="border rounded-lg overflow-auto dark:border-gray-700 bg-gray-100 dark:bg-gray-900" style={{ maxHeight: '75vh' }}>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative inline-block"
|
||||
style={{ transform: `scale(${zoom / 100})`, transformOrigin: 'top left' }}
|
||||
>
|
||||
{/* Background image at reduced opacity */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
ref={imageRef}
|
||||
src={dewarpedUrl}
|
||||
alt="Dewarped"
|
||||
className="block"
|
||||
style={{ opacity: 0.3 }}
|
||||
onLoad={onImageLoad}
|
||||
/>
|
||||
|
||||
{/* Structure elements (boxes, graphics) */}
|
||||
{imageNaturalSize && (
|
||||
<StructureLayer
|
||||
boxes={structureBoxes}
|
||||
graphics={structureGraphics}
|
||||
imgW={imageNaturalSize.w}
|
||||
imgH={imageNaturalSize.h}
|
||||
show={showStructure}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Empty field markers */}
|
||||
{showEmptyHighlight && cells
|
||||
.filter(c => emptyCellIds.has(c.cellId))
|
||||
.map(cell => (
|
||||
<div
|
||||
key={`empty-${cell.cellId}`}
|
||||
className="absolute border-2 border-dashed border-red-400/60 rounded pointer-events-none"
|
||||
style={{
|
||||
left: `${cell.bboxPct.x}%`,
|
||||
top: `${cell.bboxPct.y}%`,
|
||||
width: `${cell.bboxPct.w}%`,
|
||||
height: `${cell.bboxPct.h}%`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Editable text fields at bbox positions */}
|
||||
{cells.map((cell) => {
|
||||
const displayText = getDisplayText(cell)
|
||||
const edited = isEdited(cell)
|
||||
|
||||
return (
|
||||
<div key={cell.cellId} className="absolute group" style={{
|
||||
left: `${cell.bboxPct.x}%`,
|
||||
top: `${cell.bboxPct.y}%`,
|
||||
width: `${cell.bboxPct.w}%`,
|
||||
height: `${cell.bboxPct.h}%`,
|
||||
}}>
|
||||
<input
|
||||
id={`cell-${cell.cellId}`}
|
||||
type="text"
|
||||
value={displayText}
|
||||
onChange={(e) => onTextChange(cell.cellId, e.target.value)}
|
||||
onKeyDown={(e) => onKeyDown(e, cell.cellId)}
|
||||
className={`w-full h-full bg-transparent text-black dark:text-white border px-0.5 outline-none transition-colors ${
|
||||
colTypeColor(cell.colType)
|
||||
} ${edited ? 'border-green-500 bg-green-50/30 dark:bg-green-900/20' : ''}`}
|
||||
style={{
|
||||
fontSize: `${getFontSize(cell.bboxPct.h)}px`,
|
||||
lineHeight: '1',
|
||||
}}
|
||||
title={`${cell.cellId} (${cell.colType})`}
|
||||
/>
|
||||
{/* Per-cell reset button (X) — only shown for edited cells on hover */}
|
||||
{edited && (
|
||||
<button
|
||||
onClick={() => onResetCell(cell.cellId)}
|
||||
className="absolute -top-1 -right-1 w-4 h-4 bg-red-500 text-white rounded-full text-[9px] leading-none opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center"
|
||||
title="Zuruecksetzen"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user