fix: graphe labels visibles + tooltip/cursor adaptatifs au thème clair/sombre
Some checks failed
CI / Lint, Unit Tests & Build (push) Successful in 5m42s
CI / Deploy production (on server) (push) Failing after 18s

- SlideChart reçoit isDark et adapte tooltip, tick, grid, cursor, légende
- margin bottom 40px pour que les labels X-axis ne soient plus coupés
- cursor et tooltip blancs en thème clair (fini le carré noir)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Antigravity
2026-05-29 12:46:57 +00:00
parent 3ee07c5f55
commit 212420ec62

View File

@@ -19,30 +19,44 @@ const MermaidDiagram = dynamic(
// ── Constants ──────────────────────────────────────────────────────────────────
const CHART_COLORS = ['#6366f1', '#22d3ee', '#f59e0b', '#ef4444', '#10b981', '#a78bfa', '#fb923c', '#14b8a6']
const TT_STYLE: CSSProperties = { background: '#1C1C1C', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 8, fontSize: 12 }
const TICK = { fill: 'rgba(255,255,255,0.55)', fontSize: 11 }
const GRID_STROKE = 'rgba(255,255,255,0.07)'
function chartTheme(isDark: boolean) {
return {
ttStyle: {
background: isDark ? '#1C1C1C' : '#ffffff',
border: `1px solid ${isDark ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)'}`,
borderRadius: 8,
fontSize: 12,
color: isDark ? '#fff' : '#111',
} as CSSProperties,
tick: { fill: isDark ? 'rgba(255,255,255,0.55)' : 'rgba(0,0,0,0.55)', fontSize: 11 },
grid: isDark ? 'rgba(255,255,255,0.07)' : 'rgba(0,0,0,0.08)',
cursor: isDark ? 'rgba(255,255,255,0.04)' : 'rgba(0,0,0,0.04)',
legColor: isDark ? 'rgba(255,255,255,0.6)' : 'rgba(0,0,0,0.6)',
}
}
// ── Chart ──────────────────────────────────────────────────────────────────────
function SlideChart({ slide }: { slide: SlideSpec }) {
function SlideChart({ slide, isDark }: { slide: SlideSpec; isDark: boolean }) {
const chart = slide.chart
if (!chart?.data?.length) return null
const { ttStyle, tick, grid, cursor, legColor } = chartTheme(isDark)
const colors = (chart as any).colors ?? CHART_COLORS
const xKey = chart.xKey ?? 'name'
const yKeys = chart.yKeys ?? Object.keys(chart.data[0]).filter(k => k !== xKey)
const legend = chart.showLegend !== false && yKeys.length > 1
const legSt = { fontSize: 12, color: 'rgba(255,255,255,0.6)' }
const legSt = { fontSize: 12, color: legColor }
switch (chart.type) {
case 'bar':
return (
<ResponsiveContainer width="100%" height="100%">
<BarChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 4 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={GRID_STROKE} />}
<XAxis dataKey={xKey} tick={TICK} axisLine={false} tickLine={false} />
<YAxis tick={TICK} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={TT_STYLE} cursor={{ fill: 'rgba(255,255,255,0.04)' }} />
<BarChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 40 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={grid} />}
<XAxis dataKey={xKey} tick={tick} axisLine={false} tickLine={false} />
<YAxis tick={tick} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={ttStyle} cursor={{ fill: cursor }} />
{legend && <Legend wrapperStyle={legSt} />}
{yKeys.map((k, i) => <Bar key={k} dataKey={k} fill={colors[i % colors.length]} radius={[4, 4, 0, 0]} maxBarSize={56} />)}
</BarChart>
@@ -51,11 +65,11 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
case 'line':
return (
<ResponsiveContainer width="100%" height="100%">
<LineChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 4 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={GRID_STROKE} />}
<XAxis dataKey={xKey} tick={TICK} axisLine={false} tickLine={false} />
<YAxis tick={TICK} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={TT_STYLE} />
<LineChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 40 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={grid} />}
<XAxis dataKey={xKey} tick={tick} axisLine={false} tickLine={false} />
<YAxis tick={tick} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={ttStyle} />
{legend && <Legend wrapperStyle={legSt} />}
{yKeys.map((k, i) => <Line key={k} type="monotone" dataKey={k} stroke={colors[i % colors.length]} strokeWidth={2.5} dot={{ r: 4, strokeWidth: 0 }} activeDot={{ r: 6 }} />)}
</LineChart>
@@ -64,11 +78,11 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
case 'area':
return (
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 4 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={GRID_STROKE} />}
<XAxis dataKey={xKey} tick={TICK} axisLine={false} tickLine={false} />
<YAxis tick={TICK} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={TT_STYLE} />
<AreaChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 40 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={grid} />}
<XAxis dataKey={xKey} tick={tick} axisLine={false} tickLine={false} />
<YAxis tick={tick} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={ttStyle} />
{legend && <Legend wrapperStyle={legSt} />}
{yKeys.map((k, i) => <Area key={k} type="monotone" dataKey={k} stroke={colors[i % colors.length]} fill={`${colors[i % colors.length]}28`} strokeWidth={2.5} />)}
</AreaChart>
@@ -81,7 +95,7 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
<Pie data={chart.data} dataKey={yKeys[0] ?? 'value'} nameKey={xKey} cx="50%" cy="50%" outerRadius="70%" innerRadius="35%" paddingAngle={2}>
{chart.data.map((_, i) => <Cell key={i} fill={colors[i % colors.length]} stroke="transparent" />)}
</Pie>
<Tooltip contentStyle={TT_STYLE} />
<Tooltip contentStyle={ttStyle} />
{chart.showLegend !== false && <Legend wrapperStyle={legSt} />}
</PieChart>
</ResponsiveContainer>
@@ -93,7 +107,7 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
<PolarGrid stroke="rgba(255,255,255,0.1)" />
<PolarAngleAxis dataKey={xKey} tick={{ fill: 'rgba(255,255,255,0.65)', fontSize: 11 }} />
{yKeys.map((k, i) => <Radar key={k} name={k} dataKey={k} stroke={colors[i % colors.length]} fill={colors[i % colors.length]} fillOpacity={0.15} />)}
<Tooltip contentStyle={TT_STYLE} />
<Tooltip contentStyle={ttStyle} />
{legend && <Legend wrapperStyle={legSt} />}
</RadarChart>
</ResponsiveContainer>
@@ -101,11 +115,11 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
case 'stacked-bar':
return (
<ResponsiveContainer width="100%" height="100%">
<BarChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 4 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={GRID_STROKE} />}
<XAxis dataKey={xKey} tick={TICK} axisLine={false} tickLine={false} />
<YAxis tick={TICK} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={TT_STYLE} cursor={{ fill: 'rgba(255,255,255,0.04)' }} />
<BarChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 40 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={grid} />}
<XAxis dataKey={xKey} tick={tick} axisLine={false} tickLine={false} />
<YAxis tick={tick} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={ttStyle} cursor={{ fill: cursor }} />
<Legend wrapperStyle={legSt} />
{yKeys.map((k, i) => <Bar key={k} dataKey={k} stackId="a" fill={colors[i % colors.length]} radius={i === yKeys.length - 1 ? [4, 4, 0, 0] : [0, 0, 0, 0]} />)}
</BarChart>
@@ -116,11 +130,11 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
const barKeys = yKeys.filter(k => !lineKeys.includes(k))
return (
<ResponsiveContainer width="100%" height="100%">
<BarChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 4 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={GRID_STROKE} />}
<XAxis dataKey={xKey} tick={TICK} axisLine={false} tickLine={false} />
<YAxis tick={TICK} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={TT_STYLE} cursor={{ fill: 'rgba(255,255,255,0.04)' }} />
<BarChart data={chart.data} margin={{ top: 8, right: 24, left: 0, bottom: 40 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={grid} />}
<XAxis dataKey={xKey} tick={tick} axisLine={false} tickLine={false} />
<YAxis tick={tick} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={ttStyle} cursor={{ fill: cursor }} />
<Legend wrapperStyle={legSt} />
{barKeys.map((k, i) => <Bar key={k} dataKey={k} fill={colors[i % colors.length]} radius={[4, 4, 0, 0]} maxBarSize={56} />)}
{lineKeys.map((k, i) => <Line key={k} type="monotone" dataKey={k} stroke={colors[(barKeys.length + i) % colors.length]} strokeWidth={2.5} dot={{ r: 4, strokeWidth: 0 }} />)}
@@ -132,7 +146,7 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
return (
<ResponsiveContainer width="100%" height="100%">
<FunnelChart>
<Tooltip contentStyle={TT_STYLE} />
<Tooltip contentStyle={ttStyle} />
<Funnel dataKey={yKeys[0] ?? 'value'} data={chart.data.map((d, i) => ({ ...d, fill: colors[i % colors.length] }))} isAnimationActive>
<LabelList position="center" fill="#fff" fontSize={12} fontWeight={700} dataKey={xKey} />
</Funnel>
@@ -168,11 +182,11 @@ function SlideChart({ slide }: { slide: SlideSpec }) {
})
return (
<ResponsiveContainer width="100%" height="100%">
<BarChart data={waterfallData} margin={{ top: 8, right: 24, left: 0, bottom: 4 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={GRID_STROKE} />}
<XAxis dataKey={xKey} tick={TICK} axisLine={false} tickLine={false} />
<YAxis tick={TICK} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={TT_STYLE} />
<BarChart data={waterfallData} margin={{ top: 8, right: 24, left: 0, bottom: 40 }}>
{chart.showGrid !== false && <CartesianGrid strokeDasharray="3 3" stroke={grid} />}
<XAxis dataKey={xKey} tick={tick} axisLine={false} tickLine={false} />
<YAxis tick={tick} axisLine={false} tickLine={false} width={40} />
<Tooltip contentStyle={ttStyle} />
<Bar dataKey="__start" stackId="w" fill="transparent" />
<Bar dataKey="__delta" stackId="w" radius={[4, 4, 0, 0]} maxBarSize={56}>
{waterfallData.map((d, i) => <Cell key={i} fill={d.__isTotal ? colors[2] : d.__isPositive ? colors[4] : colors[3]} />)}
@@ -395,7 +409,7 @@ function SlideContent({ slide, index, palette, radius }: { slide: SlideSpec; ind
{slide.subtitle && <p style={{ margin: '6px 0 0', fontSize: 15, color: muted }}>{slide.subtitle}</p>}
<div style={accentBar} />
<div style={{ flex: 1 }}>
<SlideChart slide={slide} />
<SlideChart slide={slide} isDark={isDark} />
</div>
</div>
)