| /** | |
| * Patch embedded HTML to display correctly inside an iframe. | |
| * | |
| * Injects CSS that ensures proper sizing and scrolling behavior | |
| * when HTML content is rendered via srcDoc in an iframe. | |
| */ | |
| export function patchHtmlForIframe(html: string): string { | |
| const iframeCss = `<style data-iframe-patch> | |
| html, body { | |
| width: 100%; | |
| height: 100%; | |
| margin: 0; | |
| padding: 0; | |
| overflow-x: hidden; | |
| overflow-y: auto; | |
| } | |
| /* Fix min-h-screen: in iframes 100vh is the iframe height, which is correct, | |
| but ensure body actually fills it */ | |
| body { min-height: 100vh; } | |
| </style>`; | |
| // Insert right after <head> or at the start of the document | |
| const headIdx = html.indexOf('<head>'); | |
| if (headIdx !== -1) { | |
| const insertPos = headIdx + 6; // after <head> | |
| return html.substring(0, insertPos) + '\n' + iframeCss + html.substring(insertPos); | |
| } | |
| const headWithAttrs = html.indexOf('<head '); | |
| if (headWithAttrs !== -1) { | |
| const closeAngle = html.indexOf('>', headWithAttrs); | |
| if (closeAngle !== -1) { | |
| const insertPos = closeAngle + 1; | |
| return html.substring(0, insertPos) + '\n' + iframeCss + html.substring(insertPos); | |
| } | |
| } | |
| // Fallback: prepend | |
| return iframeCss + html; | |
| } | |