since3-portal/modules/templates/ui/components/live-preview.tsx
2026-10-11 18:22:32 +02:00

49 lines
2 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import type { AiAccess } from "../../ai/demos"
import { resolveContent } from "../../lib/content"
import { PREVIEW_CONTENT, PREVIEW_FOCUS, PREVIEW_READY } from "../../lib/preview"
import { getTemplate } from "../../lib/registry"
import type { TemplateContent } from "../../lib/types"
import { TemplateRenderer } from "./template-renderer"
// Baukasten: zum Baustein scrollen und ihn kurz umranden, damit man sieht, was man gerade bearbeitet
function focusBlock(id: string) {
const element = document.querySelector<HTMLElement>(`[data-block="${CSS.escape(id)}"]`)
if (!element) return
element.scrollIntoView({ behavior: "smooth", block: "start" })
element.animate(
[
{ outline: "3px solid rgb(99 102 241 / 0.9)", outlineOffset: "-3px" },
{ outline: "3px solid rgb(99 102 241 / 0)", outlineOffset: "-3px" },
],
{ duration: 1600, easing: "ease-out" }
)
}
// Läuft im iframe des Editors und übernimmt ungespeicherte Änderungen per postMessage
export function LivePreview({ templateKey, initialContent, access }: {
templateKey: string
initialContent: TemplateContent
access: AiAccess | null
}) {
const [content, setContent] = useState(initialContent)
useEffect(() => {
const def = getTemplate(templateKey)
if (!def) return
function onMessage(event: MessageEvent) {
if (event.origin !== window.location.origin || !def) return
if (event.data?.type === PREVIEW_FOCUS && typeof event.data.id === "string") focusBlock(event.data.id)
if (event.data?.type === PREVIEW_CONTENT) setContent(resolveContent(def, event.data.content))
}
window.addEventListener("message", onMessage)
window.parent.postMessage({ type: PREVIEW_READY }, window.location.origin)
return () => window.removeEventListener("message", onMessage)
}, [templateKey])
return <TemplateRenderer templateKey={templateKey} content={content} access={access} />
}