'use client'
/**
* Shared utilities and small presentational components for StepWordRecognition.
*/
/** Render text with \n as line breaks */
export function MultilineText({ text }: { text: string }) {
if (!text) return —
const lines = text.split('\n')
if (lines.length === 1) return <>{text}>
return <>{lines.map((line, i) => (
{line}{i < lines.length - 1 &&
}
))}>
}
/** Column type to human-readable header */
export function colTypeLabel(colType: string): string {
const labels: Record = {
column_en: 'English',
column_de: 'Deutsch',
column_example: 'Example',
column_text: 'Text',
column_marker: 'Marker',
page_ref: 'Seite',
}
return labels[colType] || colType.replace('column_', '')
}
/** Column type to color class */
export function colTypeColor(colType: string): string {
const colors: Record = {
column_en: 'text-blue-600 dark:text-blue-400',
column_de: 'text-green-600 dark:text-green-400',
column_example: 'text-orange-600 dark:text-orange-400',
column_text: 'text-purple-600 dark:text-purple-400',
column_marker: 'text-gray-500 dark:text-gray-400',
}
return colors[colType] || 'text-gray-600 dark:text-gray-400'
}
/** Confidence score to color class */
export function confColor(conf: number): string {
if (conf >= 70) return 'text-green-600 dark:text-green-400'
if (conf >= 50) return 'text-yellow-600 dark:text-yellow-400'
return 'text-red-600 dark:text-red-400'
}
/** Status to badge color class */
export function statusBadge(status?: string): string {
const map: Record = {
pending: 'bg-gray-100 dark:bg-gray-700 text-gray-500',
confirmed: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-400',
edited: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-400',
skipped: 'bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-400',
}
return map[status || 'pending'] || map.pending
}
/**
* CellCrop: Shows a cropped portion of the dewarped image based on percent bbox.
* Uses CSS background-image + background-position for efficient cropping.
*/
export function CellCrop({ imageUrl, bbox }: { imageUrl: string; bbox: { x: number; y: number; w: number; h: number } }) {
// Scale factor: how much to zoom into the cell
const scaleX = 100 / bbox.w
const scaleY = 100 / bbox.h
const scale = Math.min(scaleX, scaleY, 8) // Cap zoom at 8x
return (
)
}