import { useMemo } from "react"; import { useTheme } from "../ThemeContext"; import { MONO } from "../theme"; // The self-contained D3/SVG fragments from the multi-harness RL article. // They carry their own data and script, so a glob import is enough: nothing // here fetches, and nothing reaches a CDN. const FRAGMENTS = import.meta.glob("../embeds/*.html", { query: "?raw", import: "default", eager: true, }) as Record; function fragmentFor(name: string): string | null { const needle = name.endsWith(".html") ? name : `${name}.html`; for (const [path, html] of Object.entries(FRAGMENTS)) { if (path.endsWith(`/${needle}`)) return html; } return null; } /** * Render an article figure inside a themed iframe. * * The fragments read their palette from CSS variables, so we map the deck's * theme onto the names the article uses. Several of them take a `config`, * which they look for by walking up the DOM for a `data-config` attribute, * hence the wrapper div. */ export function Embed({ name, config, height = 560, width = "100%", scale = 1, css = "", }: { name: string; config?: Record; height?: number; width?: number | string; scale?: number; /** Per-figure CSS. Several figures are sized for the article's text column * (some cap themselves at 640px), which leaves them small and flush left on * a 1160px slide. Override them here rather than editing the vendored HTML. */ css?: string; }) { const { T, mode } = useTheme(); const fragment = fragmentFor(name); const srcDoc = useMemo(() => { if (!fragment) return ""; const cfg = config ? JSON.stringify(config).replace(/"/g, """) : ""; return `
${fragment}
${css ? `` : ""} `; }, [fragment, config, mode, T, scale, css]); if (!fragment) { return (
missing embed: {name}
); } return (