48 lines
1.5 KiB
TypeScript
48 lines
1.5 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>(['allow-same-origin'])
|
|
|
|
if (options.allowScripts) {
|
|
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 })
|
|
iframe.style.width = '640px'
|
|
iframe.style.height = '360px'
|
|
iframe.style.position = 'fixed'
|
|
iframe.style.left = '-10000px'
|
|
iframe.style.border = '0'
|
|
document.body.appendChild(iframe)
|
|
|
|
await new Promise<void>((resolve) => iframe.addEventListener('load', () => resolve(), { once: true }))
|
|
|
|
const content = iframe.contentDocument?.body
|
|
const thumbnail = document.createElement('img')
|
|
if (content) {
|
|
thumbnail.src = domToSvgDataUrl(content, { width: 640, height: 360 })
|
|
}
|
|
iframe.remove()
|
|
return thumbnail
|
|
}
|