100 lines
2.5 KiB
TypeScript
100 lines
2.5 KiB
TypeScript
"use client"
|
|
|
|
import { useCallback, useEffect, useRef, useState, type CSSProperties } from "react"
|
|
import { useTheme } from "next-themes"
|
|
import {
|
|
emailPreviewBaseCss,
|
|
emailPreviewDarkOverrideCss,
|
|
emailPreviewLightOverrideCss,
|
|
preprocessEmailHtmlForTheme,
|
|
} from "@/lib/email-preview-dark-styles"
|
|
|
|
const EMAIL_PREVIEW_IFRAME_STYLE: CSSProperties = {
|
|
display: "block",
|
|
background: "transparent",
|
|
}
|
|
|
|
function documentIsDark(): boolean {
|
|
return document.documentElement.classList.contains("dark")
|
|
}
|
|
|
|
export function SandboxedContent({
|
|
html,
|
|
isSpam,
|
|
}: {
|
|
html: string
|
|
isSpam: boolean
|
|
}) {
|
|
const iframeRef = useRef<HTMLIFrameElement>(null)
|
|
const [height, setHeight] = useState(120)
|
|
|
|
const sandboxValue = isSpam
|
|
? "allow-same-origin"
|
|
: "allow-same-origin allow-popups"
|
|
|
|
const { resolvedTheme } = useTheme()
|
|
|
|
const injectContent = useCallback(() => {
|
|
const iframe = iframeRef.current
|
|
if (!iframe) return
|
|
|
|
const doc = iframe.contentDocument
|
|
if (!doc) return
|
|
|
|
const cspMeta = isSpam
|
|
? `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:;">`
|
|
: `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src https: data:;">`
|
|
|
|
const isDark = documentIsDark()
|
|
const processedHtml = preprocessEmailHtmlForTheme(html, isDark)
|
|
const themeOverrides = isDark
|
|
? emailPreviewDarkOverrideCss()
|
|
: emailPreviewLightOverrideCss()
|
|
|
|
doc.open()
|
|
doc.write(`<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
${cspMeta}
|
|
<style>
|
|
${emailPreviewBaseCss(isDark)}
|
|
${themeOverrides}
|
|
</style>
|
|
</head>
|
|
<body>${processedHtml}</body>
|
|
</html>`)
|
|
doc.close()
|
|
|
|
const resizeObserver = new ResizeObserver(() => {
|
|
const body = iframe.contentDocument?.body
|
|
if (body) {
|
|
setHeight(Math.max(60, body.scrollHeight + 2))
|
|
}
|
|
})
|
|
|
|
if (doc.body) {
|
|
resizeObserver.observe(doc.body)
|
|
setHeight(Math.max(60, doc.body.scrollHeight + 2))
|
|
}
|
|
|
|
return () => resizeObserver.disconnect()
|
|
}, [html, isSpam, resolvedTheme])
|
|
|
|
useEffect(() => {
|
|
const cleanup = injectContent()
|
|
return () => cleanup?.()
|
|
}, [injectContent])
|
|
|
|
return (
|
|
<iframe
|
|
ref={iframeRef}
|
|
sandbox={sandboxValue}
|
|
title="Contenu du message"
|
|
className="w-full border-0 bg-transparent"
|
|
style={{ ...EMAIL_PREVIEW_IFRAME_STYLE, height: `${height}px` }}
|
|
tabIndex={-1}
|
|
/>
|
|
)
|
|
}
|