StepAnsicht: dominant row height for content + proportional box rows
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 33s
CI / test-go-edu-search (push) Successful in 43s
CI / test-python-klausur (push) Failing after 2m35s
CI / test-python-agent-core (push) Successful in 34s
CI / test-nodejs-website (push) Successful in 31s
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 33s
CI / test-go-edu-search (push) Successful in 43s
CI / test-python-klausur (push) Failing after 2m35s
CI / test-python-agent-core (push) Successful in 34s
CI / test-nodejs-website (push) Successful in 31s
Content sections: use dominant (median) row height from all content rows instead of per-section average. This ensures uniform row height above and below boxes (the standard case on textbook pages). Box sections: distribute height proportionally by text line count per row. A header (1 line) gets 1/7 of box height, a bullet with 3 lines gets 3/7. Fixes Box 2 where row 3 was cut off because even distribution didn't account for multi-line cells. Removed overflow:hidden from box container to prevent clipping. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -173,6 +173,22 @@ export function StepAnsicht({ sessionId, onNext }: StepAnsichtProps) {
|
|||||||
const panelHeight = imgH * scale
|
const panelHeight = imgH * scale
|
||||||
const contentZone = grid.zones.find((z) => z.zone_type === 'content')
|
const contentZone = grid.zones.find((z) => z.zone_type === 'content')
|
||||||
|
|
||||||
|
// Dominant row height: median of row-to-row spacings (excluding box-gap jumps)
|
||||||
|
const dominantRowH = useMemo(() => {
|
||||||
|
const cz = grid.zones.find((z) => z.zone_type === 'content')
|
||||||
|
if (!cz || cz.rows.length < 2) return 47
|
||||||
|
const spacings: number[] = []
|
||||||
|
for (let i = 0; i < cz.rows.length - 1; i++) {
|
||||||
|
const y1 = cz.rows[i].y_min_px ?? (cz.rows[i] as any).y_min ?? 0
|
||||||
|
const y2 = cz.rows[i + 1].y_min_px ?? (cz.rows[i + 1] as any).y_min ?? 0
|
||||||
|
const d = y2 - y1
|
||||||
|
if (d > 0 && d < 100) spacings.push(d)
|
||||||
|
}
|
||||||
|
if (spacings.length === 0) return 47
|
||||||
|
spacings.sort((a, b) => a - b)
|
||||||
|
return spacings[Math.floor(spacings.length / 2)]
|
||||||
|
}, [grid])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
@@ -237,7 +253,7 @@ export function StepAnsicht({ sessionId, onNext }: StepAnsichtProps) {
|
|||||||
rows={sec.rows}
|
rows={sec.rows}
|
||||||
yStart={sec.yStart}
|
yStart={sec.yStart}
|
||||||
scale={scale}
|
scale={scale}
|
||||||
avgRowH={sec.avgRowH}
|
avgRowH={dominantRowH}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -375,13 +391,19 @@ function BoxSectionRenderer({ zone, scale, avgRowH }: {
|
|||||||
const colScale = totalColW > 0 ? width / totalColW : 1
|
const colScale = totalColW > 0 ? width / totalColW : 1
|
||||||
const numCols = zone.columns.length
|
const numCols = zone.columns.length
|
||||||
|
|
||||||
// Evenly distribute rows within the box
|
// Distribute box height proportionally by text line count per row
|
||||||
const numRows = zone.rows.length
|
const rowLineCounts = zone.rows.map((row) => {
|
||||||
const evenRowH = numRows > 0 ? height / numRows : rowH
|
const maxLines = Math.max(1, ...zone.cells
|
||||||
|
.filter((c) => c.row_index === row.index)
|
||||||
|
.map((c) => (c.text ?? '').split('\n').length))
|
||||||
|
return maxLines
|
||||||
|
})
|
||||||
|
const totalLines = rowLineCounts.reduce((s, n) => s + n, 0)
|
||||||
|
const lineUnitH = totalLines > 0 ? height / totalLines : height
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="absolute overflow-hidden"
|
className="absolute"
|
||||||
style={{
|
style={{
|
||||||
left: `${left}px`,
|
left: `${left}px`,
|
||||||
top: `${top}px`,
|
top: `${top}px`,
|
||||||
@@ -395,14 +417,12 @@ function BoxSectionRenderer({ zone, scale, avgRowH }: {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: colWidths.map((w) => `${(w * colScale).toFixed(1)}px`).join(' ') }}>
|
<div style={{ display: 'grid', gridTemplateColumns: colWidths.map((w) => `${(w * colScale).toFixed(1)}px`).join(' ') }}>
|
||||||
{zone.rows.map((row) => {
|
{zone.rows.map((row, rowIdx) => {
|
||||||
const isSpanning = zone.cells.some((c) => c.row_index === row.index && c.col_type === 'spanning_header')
|
const isSpanning = zone.cells.some((c) => c.row_index === row.index && c.col_type === 'spanning_header')
|
||||||
|
|
||||||
// Multi-line height
|
// Height proportional to text line count
|
||||||
const maxLines = Math.max(1, ...zone.cells
|
const rowLines = rowLineCounts[rowIdx] || 1
|
||||||
.filter((c) => c.row_index === row.index)
|
const cellRowH = lineUnitH * rowLines
|
||||||
.map((c) => (c.text ?? '').split('\n').length))
|
|
||||||
const cellRowH = evenRowH * (maxLines > 1 ? maxLines * 0.7 : 1)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={row.index} style={{ display: 'contents' }}>
|
<div key={row.index} style={{ display: 'contents' }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user