style: stack per-class override rows instead of a wide table (REQ-181 layout)

The width:100% table plus the new MaxBox column let the Class column absorb
the slack, stranding the Container checkbox away from its class. One block
per class now: name + Container checkbox on the first line, Conf/IoU/MinBox/
MaxBox inputs in a wrapping grid below. Behavior identical - KEYS,
buildClassParams, compose() copy line, toggleContainer revert, aria labels.
This commit is contained in:
asus committed 2026-10-05 11:01:26 +07:00
1 parent d3a6aa49b6
commit 2971f9192c
4 files changed
+75 -61

No files matched your search

+45 -53
View File
@@ -92,64 +92,56 @@ export default function ClassParamsTable({ classNames, globals, value, onChange,
<span aria-live="polite">{copied ? 'Copied' : 'Copy'}</span>
</button>
</div>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr>
<th className="hint" style={{ fontWeight: 400, fontSize: '0.74rem', textAlign: 'left', padding: '2px 4px' }}>Class</th>
{KEYS.map(k => (
<th key={k.key} className="hint" style={{ fontWeight: 400, fontSize: '0.74rem', color: k.color, padding: '2px 4px' }}>{k.label}</th>
))}
{project && (
<th className="hint" style={{ fontWeight: 400, fontSize: '0.74rem', textAlign: 'left', padding: '2px 4px' }}>Container</th>
)}
</tr>
</thead>
<tbody>
{/* Stacked rows (REQ-181): the name line carries the container flag, the
grid below it the four overrides, so a wide class list never squeezes
the numbers or strands the checkbox away from its class. */}
<div>
{classNames.map(name => {
const cls = project?.classes.find(c => c.name === name)
return (
<tr key={name}>
<td className="mono" style={{ fontSize: '0.76rem', padding: '2px 4px' }}>{name}</td>
{KEYS.map(({ key, label, step, color }) => (
<td key={key} style={{ padding: '2px 4px' }}>
<input
type="number"
value={value[name]?.[key] ?? ''}
min={0}
max={1}
step={step}
placeholder={String(globals[key])}
title={`Empty = use the global value (${globals[key]})`}
aria-label={`${name} ${label} override, empty uses global ${globals[key]}`}
onChange={(e) => set(name, key, e.target.value)}
style={{
width: 64, fontSize: '0.76rem', background: '#09090b', color,
border: '1px solid #3f3f46', borderRadius: 4, padding: '2px 4px',
cursor: 'text',
}}
/>
</td>
))}
{project && (
<td style={{ padding: '2px 4px', textAlign: 'center' }}>
{cls && (
<label title={`Keep boxes inside ${name} when auto-annotating (containment is not overlap)`} style={{ cursor: 'pointer', display: 'inline-flex' }}>
<input
type="checkbox"
checked={containers.has(name)}
onChange={() => toggleContainer(cls)}
aria-label={`Mark ${name} as container`}
style={{ cursor: 'pointer' }}
/>
</label>
)}
</td>
)}
</tr>
<div key={name} style={{ padding: '6px 0', borderBottom: '1px solid #27272a' }}>
<div className="row" style={{ justifyContent: 'space-between', alignItems: 'center', gap: 8 }}>
<span className="mono" style={{ fontSize: '0.76rem', minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{name}</span>
{project && cls && (
<label title={`Keep boxes inside ${name} when auto-annotating (containment is not overlap)`} style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 4, flexShrink: 0, fontSize: '0.74rem' }}>
<input
type="checkbox"
checked={containers.has(name)}
onChange={() => toggleContainer(cls)}
aria-label={`Mark ${name} as container`}
style={{ cursor: 'pointer' }}
/>
Container
</label>
)}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(118px, 1fr))', gap: 6, marginTop: 4 }}>
{KEYS.map(({ key, label, step, color }) => (
<label key={key} style={{ display: 'flex', alignItems: 'center', gap: 4, minWidth: 0, marginBottom: 0 }}>
<span className="hint" style={{ fontSize: '0.7rem', color, whiteSpace: 'nowrap' }}>{label}</span>
<input
type="number"
value={value[name]?.[key] ?? ''}
min={0}
max={1}
step={step}
placeholder={String(globals[key])}
title={`Empty = use the global value (${globals[key]})`}
aria-label={`${name} ${label} override, empty uses global ${globals[key]}`}
onChange={(e) => set(name, key, e.target.value)}
style={{
width: '100%', minWidth: 0, fontSize: '0.76rem', background: '#09090b', color,
border: '1px solid #3f3f46', borderRadius: 4, padding: '2px 4px',
cursor: 'text',
}}
/>
</label>
))}
</div>
</div>
)
})}
</tbody>
</table>
</div>
</>
)
}