1
0
Fork 0
forked from jan/psslides
psslides/src/code-to-element.ts
2026-09-27 20:18:32 +02:00

57 lines
1.8 KiB
TypeScript

import { domToSvgDataUrl } from './dom-to-image'
export interface CodeToElementOptions {
title?: string
allowScripts?: boolean
styles?: string[]
}
export function codeToElement(code: string, options: CodeToElementOptions = {}): HTMLIFrameElement {
const iframe = document.createElement('iframe')
const sandbox = new Set<string>()
if (!options.allowScripts) {
sandbox.add('allow-same-origin')
} else {
sandbox.add('allow-scripts')
}
iframe.title = options.title ?? 'Rendered code'
iframe.setAttribute('sandbox', Array.from(sandbox).join(' '))
iframe.srcdoc = `<!doctype html><html><head><meta charset="UTF-8"><style>html,body{margin:0;min-height:100%;}</style>${(options.styles ?? []).join('\n')}</head><body>${code}</body></html>`
return iframe
}
export async function createCodeThumbnail(
code: string,
options: CodeToElementOptions = {}
): Promise<HTMLImageElement> {
const iframe = codeToElement(code, { title: 'Code thumbnail', ...options, allowScripts: false })
iframe.style.width = '640px'
iframe.style.height = '360px'
iframe.style.position = 'fixed'
iframe.style.left = '-10000px'
iframe.style.border = '0'
document.body.append(iframe)
try {
await new Promise<void>((resolve, reject) => {
iframe.addEventListener('load', () => resolve(), { once: true })
iframe.addEventListener(
'error',
() => reject(new Error('Unable to render code thumbnail')),
{ once: true }
)
})
const content = iframe.contentDocument?.body
const thumbnail = document.createElement('img')
if (content) {
thumbnail.src = domToSvgDataUrl(content, { width: 640, height: 360 })
}
return thumbnail
} finally {
iframe.remove()
}
}