import { isTextChild, type IR, type IRNode, type IRChild } from "../normalize/ir.js"; import type { FontGraph } from "../infer/fonts.js"; import { SYSTEM_FALLBACK } from "../infer/fonts.js"; import { collectNodeRules, keyframesCss, computeBands, assembleCss, RESET_CSS } from "./css.js"; import type { TokenResolver } from "../infer/tokens.js"; import { propsList, resolveTag, resolveHtmlBg, htmlBgRule } from "./app.js"; /** * Fast, self-contained static preview artifact (`preview.html`). * * Product moment: the service shows the cloned page within seconds of `generate` * finishing — BEFORE the Next.js build + deploy completes — then swaps to the * deployed app. This artifact renders WITHOUT any build toolchain (no next / tailwind * / esbuild): it is pure string building over the same frozen IR + rules the JSX * emitter consumes. * * SHARED DECISION CODE (not a parallel emission path): * - CSS: `collectNodeRules` + `keyframesCss` + `computeBands` + `assembleCss` from * css.ts — the identical per-node rule collection + media-query banding the semantic * class-map emitter (classMap.ts) and the legacy per-node emitter (generateCss) use. * We emit `.c` selectors, exactly like `generateCss`, so the preview's computed * styles are byte-for-byte the same rules the built app resolves to. Crucially this * holds even though the app's DEFAULT output is Tailwind (utilities in the JSX, no * `.c` rules) — the preview reuses the css-mode rule collector directly. * - HTML: `propsList` + `resolveTag` from app.ts — the SAME tag resolution, attribute * filtering, asset-URL mapping (src/poster/srcset), video/lottie poster stills, and * class assignment the JSX renderer uses. We translate the JSX-flavoured attribute * pairs to raw HTML attributes; we do NOT re-derive which attrs/assets to keep. * * Runtime-free: no DittoWire / DittoLottie / DittoMotion scripts. Lottie mounts and *