'use client' import { Area, AreaChart, Bar, BarChart, CartesianGrid, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts' import { InteractiveDemoPlayer } from '@/components/interactive-demo/interactive-demo-player' import { useDarkMode } from '@/components/interactive-demo/demo-speak' import { PageFormula, PageMd } from '@/components/interactive-page/page-md' import { SimBlockView } from '@/components/interactive-page/sim-block' import { intentColor } from '@/lib/interactive-demo/intent-colors' import type { IntentId, InteractiveDemoV1 } from '@/lib/interactive-demo/types' import type { PageBlock } from '@/lib/interactive-page' import { cn } from '@/lib/utils' /** Intents actually used inside a demo (legend per demo, brainstorm P11). */ function collectDemoIntents(demo: InteractiveDemoV1): IntentId[] { const set = new Set() for (const panel of demo.scene.panels) { if (panel.type === 'svg-scene') { for (const n of panel.payload.nodes) if (n.intent) set.add(n.intent) for (const e of panel.payload.edges ?? []) if (e.intent) set.add(e.intent) } if (panel.type === 'chart') { for (const s of panel.payload.series) if (s.intent) set.add(s.intent) } } for (const act of demo.acts) { for (const step of act.steps) { for (const a of step.annotate ?? []) if (a.intent) set.add(a.intent) } } return [...set] } const DEMO_INTENT_LABELS: Record = { highlight: { fr: 'Focus', en: 'Focus' }, flow: { fr: 'Flux', en: 'Flow' }, cache: { fr: 'Mémoire', en: 'Memory' }, compute: { fr: 'Calcul', en: 'Compute' }, output: { fr: 'Résultat', en: 'Result' }, warning: { fr: 'Attention', en: 'Warning' }, } function DemoLegend({ demo, lang }: { demo: InteractiveDemoV1; lang: string }) { const dark = useDarkMode() const fr = lang.startsWith('fr') const intents = collectDemoIntents(demo) if (!intents.length) return null return (
{fr ? 'Légende' : 'Legend'} {intents.map((id) => ( {fr ? DEMO_INTENT_LABELS[id].fr : DEMO_INTENT_LABELS[id].en} ))}
) } const CALLOUT_STYLES: Record< string, { border: string; bg: string; badge: string } > = { definition: { border: 'border-sky-500/30', bg: 'bg-sky-500/5', badge: 'text-sky-700 dark:text-sky-300', }, warning: { border: 'border-amber-500/35', bg: 'bg-amber-500/5', badge: 'text-amber-800 dark:text-amber-300', }, tip: { border: 'border-emerald-500/30', bg: 'bg-emerald-500/5', badge: 'text-emerald-800 dark:text-emerald-300', }, note: { border: 'border-border', bg: 'bg-muted/40', badge: 'text-muted-foreground', }, } function IntentBadge({ label, intent, }: { label: string intent?: IntentId }) { const dark = useDarkMode() const color = intentColor(intent, dark) return ( {label} ) } function ChartBlockView({ block, }: { block: Extract }) { const dark = useDarkMode() const series = block.payload.series const maxLen = Math.max(...series.map((s) => s.values.length), 0) const data = Array.from({ length: maxLen }, (_, i) => { const row: Record = { i: String(i + 1) } for (const s of series) row[s.id] = s.values[i] ?? 0 return row }) const Chart = block.payload.chartType === 'bar' ? BarChart : block.payload.chartType === 'area' ? AreaChart : LineChart return (
{series.map((s) => { const stroke = intentColor(s.intent, dark) if (block.payload.chartType === 'bar') { return ( ) } if (block.payload.chartType === 'area') { return ( ) } return ( ) })}
{block.caption ? (
{block.caption}
) : null}
) } export function PageBlockView({ block, demoMode = 'static', lang = 'fr', }: { block: PageBlock demoMode?: 'interactive' | 'static' lang?: string }) { if (block.type === 'prose') { return } if (block.type === 'formula') { return } if (block.type === 'callout') { const style = CALLOUT_STYLES[block.kind] ?? CALLOUT_STYLES.note! return ( ) } if (block.type === 'demo') { return (
{block.caption ? (

{block.caption}

) : null} {demoMode === 'static' ? ( ) : null}
) } if (block.type === 'sim') { return } if (block.type === 'chart') { return } if (block.type === 'stats') { return (
{block.items.map((item, i) => (

{item.value}

{item.label}

))}
) } if (block.type === 'table') { return (
{block.caption ? ( ) : null} {block.columns.map((c) => ( ))} {block.rows.map((row, ri) => ( {row.map((cell, ci) => ( ))} ))}
{block.caption}
{c}
) } if (block.type === 'image') { return (
{ } {block.alt} {block.caption ? (
{block.caption}
) : null}
) } return null } export { IntentBadge }