"use client"; import type { CSSProperties } from "react"; import { useEffect } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEditorStore } from "@/features/editor/state/editorStore"; import { PublicPageRenderer } from "@/features/editor/components/PublicPageRenderer"; export default function PreviewPage() { const router = useRouter(); const blocks = useEditorStore((state) => state.blocks); const projectConfig = useEditorStore((state) => (state as any).projectConfig); const replaceBlocks = useEditorStore((state) => state.replaceBlocks); const updateProjectConfig = useEditorStore((state) => state.updateProjectConfig); const resetHistory = useEditorStore((state) => (state as any).resetHistory as () => void); useEffect(() => { let cancelled = false; const checkAuth = async () => { try { const res = await fetch("/api/auth/me"); if (!res.ok && res.status === 401 && !cancelled) { router.push("/login"); } } catch { // 네트워크 오류 등은 일단 무시하고, 페이지 접근을 막지 않는다. } }; void checkAuth(); return () => { cancelled = true; }; }, [router]); useEffect(() => { if (typeof window === "undefined") return; let slug = (projectConfig as any)?.slug?.trim?.(); if (!slug) { try { const url = new URL(window.location.href); const fromQuery = url.searchParams.get("slug")?.trim(); if (fromQuery && fromQuery !== slug) { slug = fromQuery; updateProjectConfig({ slug: fromQuery } as any); } } catch { // URL 파싱 오류는 무시하고, autosave 복원 없이 진행한다. } } if (!slug) return; const key = `pb:autosave:${slug}`; const raw = window.localStorage.getItem(key); if (!raw) return; try { const parsed = JSON.parse(raw) as { blocks?: any[]; projectConfig?: any }; if (Array.isArray(parsed.blocks)) { replaceBlocks(parsed.blocks as any); } if (parsed.projectConfig) { updateProjectConfig(parsed.projectConfig as any); } // 프리뷰 진입 시 autosave 프로젝트를 복원하는 경우에도 에디터 히스토리는 새 프로젝트 기준으로만 유지되도록 초기화한다. resetHistory(); } catch { return; } }, [projectConfig?.slug, replaceBlocks, updateProjectConfig]); const canvasStyle: CSSProperties = {}; const preset = projectConfig?.canvasPreset ?? "full"; const mainStyle: CSSProperties = {}; if (projectConfig?.bodyBgColorHex && projectConfig.bodyBgColorHex.trim()) { mainStyle.backgroundColor = projectConfig.bodyBgColorHex; } const handleExportZip = async () => { try { const payload = { blocks, projectConfig, }; const response = await fetch("/api/export", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(payload), }); if (!response.ok) { return; } const blob = await response.blob(); const url = URL.createObjectURL(blob); const slug = (projectConfig?.slug ?? "").trim() || "page-builder-export"; const link = document.createElement("a"); link.href = url; link.download = `${slug}.zip`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } catch (error) { console.error("프리뷰 ZIP 내보내기 중 오류", error); } }; const widthPx = typeof projectConfig?.canvasWidthPx === "number" && projectConfig.canvasWidthPx > 0 ? projectConfig.canvasWidthPx : null; if (widthPx != null) { canvasStyle.maxWidth = `${widthPx}px`; } else if (preset === "mobile") { canvasStyle.maxWidth = "390px"; } else if (preset === "tablet") { canvasStyle.maxWidth = "768px"; } else if (preset === "desktop") { canvasStyle.maxWidth = "1200px"; } if (projectConfig?.canvasBgColorHex && projectConfig.canvasBgColorHex.trim()) { canvasStyle.backgroundColor = projectConfig.canvasBgColorHex; } return (

Page Preview

빌더로 만든 페이지를 미리 보는 화면

프로젝트 목록 에디터로 돌아가기
{/* 에디터 크롬 없이 순수 페이지 형태로 블록들을 렌더링하되, projectConfig 에 따라 최대 폭을 제한한다. */}
); }