Checkpoint: Remplacement de toutes les valeurs hsl(var(--*)) invalides par des valeurs oklch solides directes (oklch(1 0 0) pour card, oklch(0.97 0.003 80) pour lignes alternées, oklch(0.94 0.005 80) pour muted). Ajout de isolation:isolate sur le conteneur overflow-x-auto. Position sticky en style inline avec zIndex explicite (30 pour thead, 20 pour tbody/tfoot).

This commit is contained in:
Manus
2026-06-10 09:13:06 +00:00
parent 6f118e41f7
commit 90938eb83c

View File

@@ -1248,12 +1248,12 @@ export default function DsiOpex() {
{/* Tableau scrollable horizontalement avec tous les postes */}
<div className="bg-card border border-border rounded-xl overflow-hidden">
<div className="overflow-x-auto">
<div className="overflow-x-auto" style={{ isolation: 'isolate' }}>
<table className="text-xs border-separate border-spacing-0" style={{ minWidth: 'max-content', width: '100%' }}>
<thead>
<tr className="border-b border-border bg-muted/40">
<th className="text-left px-3 py-3 font-medium text-muted-foreground sticky left-0 z-20" style={{ background: 'hsl(var(--muted) / 0.4)', boxShadow: '2px 0 0 0 hsl(var(--border))', width: '110px', minWidth: '110px', maxWidth: '110px' }}>Code</th>
<th className="text-left px-3 py-3 font-medium text-muted-foreground sticky z-20" style={{ left: '110px', background: 'hsl(var(--muted) / 0.4)', boxShadow: '2px 0 6px -2px rgba(0,0,0,0.2)', width: '220px', minWidth: '220px', maxWidth: '220px' }}>
<th className="text-left px-3 py-3 font-medium text-muted-foreground" style={{ position: 'sticky', left: 0, zIndex: 30, background: 'oklch(0.94 0.005 80)', boxShadow: '2px 0 4px -1px rgba(0,0,0,0.15)', width: '110px', minWidth: '110px', maxWidth: '110px' }}>Code</th>
<th className="text-left px-3 py-3 font-medium text-muted-foreground" style={{ position: 'sticky', left: '110px', zIndex: 30, background: 'oklch(0.94 0.005 80)', boxShadow: '2px 0 8px -2px rgba(0,0,0,0.2)', width: '220px', minWidth: '220px', maxWidth: '220px' }}>
<SortBtn col="nom" label="Établissement" />
</th>
{/* Colonnes postes — vert = prorata auto, bleu = manuel */}
@@ -1277,7 +1277,7 @@ export default function DsiOpex() {
</th>
);
})}
<th className="text-right px-3 py-3 font-medium text-muted-foreground sticky right-0 z-20" style={{ background: 'hsl(var(--muted) / 0.4)', boxShadow: '-2px 0 6px -2px rgba(0,0,0,0.2)', width: '120px', minWidth: '120px' }}>
<th className="text-right px-3 py-3 font-medium text-muted-foreground" style={{ position: 'sticky', right: 0, zIndex: 30, background: 'oklch(0.94 0.005 80)', boxShadow: '-2px 0 8px -2px rgba(0,0,0,0.2)', width: '120px', minWidth: '120px' }}>
<SortBtn col="total" label={`Total ${annee}`} />
</th>
</tr>
@@ -1285,10 +1285,10 @@ export default function DsiOpex() {
<tbody>
{sortedEtabs.map((etab, idx) => (
<tr key={etab.code} className={`border-b border-border/50 hover:bg-muted/20 transition-colors ${idx % 2 === 0 ? '' : 'bg-muted/5'}`}>
<td className="px-3 py-2 sticky left-0 z-10 whitespace-nowrap" style={{ background: idx % 2 === 0 ? 'hsl(var(--card))' : 'hsl(var(--muted) / 0.05)', boxShadow: '2px 0 0 0 hsl(var(--border))', width: '110px', minWidth: '110px', maxWidth: '110px' }}>
<td className="px-3 py-2 whitespace-nowrap" style={{ position: 'sticky', left: 0, zIndex: 20, background: idx % 2 === 0 ? 'oklch(1 0 0)' : 'oklch(0.97 0.003 80)', boxShadow: '2px 0 4px -1px rgba(0,0,0,0.12)', width: '110px', minWidth: '110px', maxWidth: '110px' }}>
<span className="font-mono bg-muted px-1.5 py-0.5 rounded text-muted-foreground">{etab.code}</span>
</td>
<td className="px-3 py-2 font-medium text-foreground sticky z-10 whitespace-nowrap overflow-hidden text-ellipsis" style={{ left: '110px', background: idx % 2 === 0 ? 'hsl(var(--card))' : 'hsl(var(--muted) / 0.05)', boxShadow: '2px 0 6px -2px rgba(0,0,0,0.2)', width: '220px', minWidth: '220px', maxWidth: '220px' }} title={etab.nom}>{etab.nom}</td>
<td className="px-3 py-2 font-medium text-foreground whitespace-nowrap overflow-hidden text-ellipsis" style={{ position: 'sticky', left: '110px', zIndex: 20, background: idx % 2 === 0 ? 'oklch(1 0 0)' : 'oklch(0.97 0.003 80)', boxShadow: '2px 0 8px -2px rgba(0,0,0,0.2)', width: '220px', minWidth: '220px', maxWidth: '220px' }} title={etab.nom}>{etab.nom}</td>
{opexState.lignes.map(ligne => {
const srcPoste = getOpexDataForAnnee(annee).postes.find(p => p.libelle === ligne.libelle);
const isManuel = srcPoste?.mode_ventilation === 'Manuel' || ligne.isCustom;
@@ -1341,7 +1341,7 @@ export default function DsiOpex() {
</td>
);
})}
<td className="px-3 py-2 text-right font-semibold tabular-nums sticky right-0 z-10" style={{ background: idx % 2 === 0 ? 'hsl(var(--card))' : 'hsl(var(--muted) / 0.08)', boxShadow: '-3px 0 8px -2px rgba(0,0,0,0.18)', width: '120px', minWidth: '120px' }}>
<td className="px-3 py-2 text-right font-semibold tabular-nums" style={{ position: 'sticky', right: 0, zIndex: 20, background: idx % 2 === 0 ? 'oklch(1 0 0)' : 'oklch(0.97 0.003 80)', boxShadow: '-3px 0 8px -2px rgba(0,0,0,0.18)', width: '120px', minWidth: '120px' }}>
<span className={etab.total > 0 ? 'text-orange-600' : 'text-muted-foreground'}>
{etab.total > 0 ? formatEuros(etab.total) : ''}
</span>
@@ -1351,7 +1351,7 @@ export default function DsiOpex() {
</tbody>
<tfoot>
<tr className="bg-muted/40 border-t-2 border-border">
<td colSpan={2} className="px-3 py-3 font-bold text-foreground sticky left-0 z-10" style={{ background: 'hsl(var(--muted) / 0.4)', boxShadow: '2px 0 6px -2px rgba(0,0,0,0.2)', width: '330px', minWidth: '330px' }}>
<td colSpan={2} className="px-3 py-3 font-bold text-foreground" style={{ position: 'sticky', left: 0, zIndex: 20, background: 'oklch(0.94 0.005 80)', boxShadow: '2px 0 8px -2px rgba(0,0,0,0.2)', width: '330px', minWidth: '330px' }}>
TOTAL — {sortedEtabs.length} établissements
</td>
{opexState.lignes.map(ligne => {
@@ -1371,7 +1371,7 @@ export default function DsiOpex() {
</td>
);
})}
<td className="px-3 py-3 text-right font-bold text-orange-600 text-sm tabular-nums sticky right-0 z-10" style={{ background: 'hsl(var(--muted) / 0.4)', boxShadow: '-3px 0 8px -2px rgba(0,0,0,0.18)', width: '120px', minWidth: '120px' }}>
<td className="px-3 py-3 text-right font-bold text-orange-600 text-sm tabular-nums" style={{ position: 'sticky', right: 0, zIndex: 20, background: 'oklch(0.94 0.005 80)', boxShadow: '-3px 0 8px -2px rgba(0,0,0,0.18)', width: '120px', minWidth: '120px' }}>
{formatEuros(sortedEtabs.reduce((s, e) => s + e.total, 0))}
</td>
</tr>