fix(cockpit): Modul-Spalten sauber ausgerichtet + Zahl-Spalten im Rapport (v1.8.8)
- table-module: Spaltenbreiten respektieren Breiten-Hinweise (w-16…w-32); Eingabezeile im selben Raster wie Kopf/Daten (keine abgeschnittenen Platzhalter, saubere Ausrichtung) - Rapport (/rapport/[token]): Zahl-Spalten rechtsbündig/monospace - Hinweis: Modul→Rapport war bereits vollständig integriert; leere Module werden im Rapport ausgelassen (erst mit Zeilen sichtbar) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "lageplan",
|
||||
"version": "1.8.7",
|
||||
"version": "1.8.8",
|
||||
"description": "Feuerwehr Lageplan - Krokier-App für Einsatzdokumentation",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -268,7 +268,7 @@ export default function RapportViewerPage({ params }: { params: Promise<{ token:
|
||||
<thead>
|
||||
<tr className="bg-gray-900 text-white">
|
||||
{(mt.columns || []).map((c: any) => (
|
||||
<th key={c.key} className={`p-1.5 font-semibold uppercase tracking-wider text-[7pt] ${c.type === 'check' ? 'text-center w-10' : c.type === 'time' ? 'text-left w-16' : 'text-left'}`}>{c.label}</th>
|
||||
<th key={c.key} className={`p-1.5 font-semibold uppercase tracking-wider text-[7pt] ${c.type === 'check' ? 'text-center w-10' : c.type === 'time' ? 'text-left w-16' : c.type === 'number' ? 'text-right w-20' : 'text-left'}`}>{c.label}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -276,7 +276,7 @@ export default function RapportViewerPage({ params }: { params: Promise<{ token:
|
||||
{mt.rows.map((row: any, ri: number) => (
|
||||
<tr key={ri} className={ri % 2 === 1 ? 'bg-gray-50' : ''}>
|
||||
{(mt.columns || []).map((c: any) => (
|
||||
<td key={c.key} className={`p-1.5 border-b border-gray-100 ${c.type === 'check' ? 'text-center font-bold' : ''} ${c.type === 'time' ? 'font-mono text-[8pt] text-gray-500' : ''}`}>
|
||||
<td key={c.key} className={`p-1.5 border-b border-gray-100 ${c.type === 'check' ? 'text-center font-bold' : ''} ${c.type === 'time' ? 'font-mono text-[8pt] text-gray-500' : ''} ${c.type === 'number' ? 'text-right font-mono tabular-nums' : ''}`}>
|
||||
{c.type === 'check'
|
||||
? (row[c.key] ? '✓' : '—')
|
||||
: c.type === 'time'
|
||||
|
||||
@@ -115,10 +115,17 @@ export function TableModule({ projectId, module, canEdit, notifyChanged }: Table
|
||||
}
|
||||
}, [projectId, module.id, notifyChanged])
|
||||
|
||||
// Spaltenbreite ableiten — respektiert optionale Breiten-Hinweise (w-16 … w-32)
|
||||
const WIDTH_MAP: Record<string, string> = { 'w-10': '40px', 'w-16': '68px', 'w-20': '92px', 'w-24': '108px', 'w-28': '124px', 'w-32': '140px' }
|
||||
const colSize = (c: ModuleColumn): string => {
|
||||
if (c.type === 'check') return '36px'
|
||||
if (c.type === 'time') return '58px'
|
||||
if (c.width && WIDTH_MAP[c.width]) return WIDTH_MAP[c.width]
|
||||
if (c.type === 'number') return '96px'
|
||||
return 'minmax(90px,1fr)'
|
||||
}
|
||||
// Grid-Template aus Spalten ableiten (+ Lösch-Spalte)
|
||||
const gridCols = columns.map(c =>
|
||||
c.type === 'check' ? '32px' : c.type === 'time' ? '52px' : c.type === 'number' ? 'minmax(0,0.6fr)' : 'minmax(0,1fr)'
|
||||
).join(' ') + (canEdit ? ' 24px' : '')
|
||||
const gridCols = columns.map(colSize).join(' ') + (canEdit ? ' 28px' : '')
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -194,21 +201,27 @@ export function TableModule({ projectId, module, canEdit, notifyChanged }: Table
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Neue Zeile */}
|
||||
{/* Neue Zeile — im selben Raster wie die Spalten, damit Eingaben unter den Titeln stehen */}
|
||||
{canEdit && (
|
||||
<div className="flex gap-1 px-1.5 py-1.5 border-t border-border/50 print:hidden">
|
||||
{textColumns.map((c, i) => (
|
||||
<div className="grid items-center gap-1 px-1.5 py-1.5 border-t border-border/50 print:hidden" style={{ gridTemplateColumns: gridCols }}>
|
||||
{columns.map(c => {
|
||||
if (c.type === 'text' || c.type === 'number') {
|
||||
return (
|
||||
<Input
|
||||
key={c.key}
|
||||
placeholder={c.label + '…'}
|
||||
placeholder={c.label}
|
||||
inputMode={c.type === 'number' ? 'numeric' : undefined}
|
||||
value={draft[c.key] || ''}
|
||||
onChange={(e) => setDraft(prev => ({ ...prev, [c.key]: e.target.value }))}
|
||||
onKeyDown={(e) => e.key === 'Enter' && addRow()}
|
||||
className={`h-6 text-[11px] ${i === 0 && c.type !== 'number' ? 'flex-1 min-w-0' : 'w-20 shrink-0'}`}
|
||||
className="h-6 text-[11px] min-w-0 px-1.5"
|
||||
/>
|
||||
))}
|
||||
<Button size="sm" variant="ghost" onClick={addRow} disabled={!textColumns.some(c => (draft[c.key] || '').trim())} className="h-6 px-1.5 shrink-0">
|
||||
)
|
||||
}
|
||||
// Zeit/Haken: leere Zelle (wird automatisch/durch Klick gesetzt)
|
||||
return <div key={c.key} className="text-center text-[10px] text-muted-foreground/50">{c.type === 'time' ? 'auto' : ''}</div>
|
||||
})}
|
||||
<Button size="sm" variant="ghost" onClick={addRow} disabled={!textColumns.some(c => (draft[c.key] || '').trim())} className="h-6 w-6 p-0 shrink-0">
|
||||
<Plus className="w-3 h-3" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user