@brunoalz/smartgesti-site-editor 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/editor/BlockSelector.js +4 -2
- package/dist/editor/BlockSelector.js.map +1 -1
- package/dist/engine/export/exporters/layout/GridExporter.d.ts.map +1 -1
- package/dist/engine/export/exporters/layout/GridExporter.js +29 -12
- package/dist/engine/export/exporters/layout/GridExporter.js.map +1 -1
- package/dist/engine/export/exporters/sections/BlogPostExporters.d.ts +2 -0
- package/dist/engine/export/exporters/sections/BlogPostExporters.d.ts.map +1 -1
- package/dist/engine/export/exporters/sections/BlogPostExporters.js +183 -119
- package/dist/engine/export/exporters/sections/BlogPostExporters.js.map +1 -1
- package/dist/engine/export/exporters/sections/index.d.ts.map +1 -1
- package/dist/engine/export/exporters/sections/index.js +26 -24
- package/dist/engine/export/exporters/sections/index.js.map +1 -1
- package/dist/engine/index.js +97 -95
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/plugins/builtin/blog/manifest.d.ts.map +1 -1
- package/dist/engine/plugins/builtin/blog/manifest.js +160 -72
- package/dist/engine/plugins/builtin/blog/manifest.js.map +1 -1
- package/dist/engine/plugins/contentHydration.js +144 -68
- package/dist/engine/plugins/contentHydration.js.map +1 -1
- package/dist/engine/registry/blocks/layout/grid.d.ts.map +1 -1
- package/dist/engine/registry/blocks/layout/grid.js +10 -4
- package/dist/engine/registry/blocks/layout/grid.js.map +1 -1
- package/dist/engine/registry/blocks/sections/blogRecentPosts.d.ts +3 -0
- package/dist/engine/registry/blocks/sections/blogRecentPosts.d.ts.map +1 -0
- package/dist/engine/registry/blocks/sections/blogRecentPosts.js +29 -0
- package/dist/engine/registry/blocks/sections/blogRecentPosts.js.map +1 -0
- package/dist/engine/registry/blocks/sections/blogTagCloud.d.ts +3 -0
- package/dist/engine/registry/blocks/sections/blogTagCloud.d.ts.map +1 -0
- package/dist/engine/registry/blocks/sections/blogTagCloud.js +31 -0
- package/dist/engine/registry/blocks/sections/blogTagCloud.js.map +1 -0
- package/dist/engine/registry/blocks/sections/index.d.ts +2 -0
- package/dist/engine/registry/blocks/sections/index.d.ts.map +1 -1
- package/dist/engine/render/renderers/layout/GridRenderer.d.ts.map +1 -1
- package/dist/engine/render/renderers/layout/GridRenderer.js +21 -18
- package/dist/engine/render/renderers/layout/GridRenderer.js.map +1 -1
- package/dist/engine/render/renderers/sections/BlogPostDetailRenderer.d.ts.map +1 -1
- package/dist/engine/render/renderers/sections/BlogPostDetailRenderer.js +66 -47
- package/dist/engine/render/renderers/sections/BlogPostDetailRenderer.js.map +1 -1
- package/dist/engine/render/renderers/sections/BlogPostGridRenderer.d.ts.map +1 -1
- package/dist/engine/render/renderers/sections/BlogPostGridRenderer.js +175 -32
- package/dist/engine/render/renderers/sections/BlogPostGridRenderer.js.map +1 -1
- package/dist/engine/render/renderers/sections/BlogRecentPostsRenderer.d.ts +3 -0
- package/dist/engine/render/renderers/sections/BlogRecentPostsRenderer.d.ts.map +1 -0
- package/dist/engine/render/renderers/sections/BlogRecentPostsRenderer.js +148 -0
- package/dist/engine/render/renderers/sections/BlogRecentPostsRenderer.js.map +1 -0
- package/dist/engine/render/renderers/sections/BlogTagCloudRenderer.d.ts +3 -0
- package/dist/engine/render/renderers/sections/BlogTagCloudRenderer.d.ts.map +1 -0
- package/dist/engine/render/renderers/sections/BlogTagCloudRenderer.js +134 -0
- package/dist/engine/render/renderers/sections/BlogTagCloudRenderer.js.map +1 -0
- package/dist/engine/render/renderers/sections/index.js +20 -16
- package/dist/engine/render/renderers/sections/index.js.map +1 -1
- package/dist/engine/schema/siteDocument.d.ts +57 -2
- package/dist/engine/schema/siteDocument.d.ts.map +1 -1
- package/dist/engine/schema/siteDocument.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +108 -106
- package/dist/index.js.map +1 -1
- package/dist/viewer/LandingPageViewer.js +11 -11
- package/dist/viewer/LandingPageViewer.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { LandingPageEditor as
|
|
2
|
-
import { LandingPageViewer as
|
|
1
|
+
import { LandingPageEditor as oe, LandingPageEditor as ae } from "./editor/LandingPageEditor.js";
|
|
2
|
+
import { LandingPageViewer as me, LandingPageViewer as pe } from "./viewer/LandingPageViewer.js";
|
|
3
3
|
import "./engine/registry/blocks/layout/container.js";
|
|
4
4
|
import "./engine/registry/blocks/layout/stack.js";
|
|
5
5
|
import "./engine/registry/blocks/layout/grid.js";
|
|
@@ -49,114 +49,116 @@ import "./engine/registry/blocks/sections/blogSearchBar.js";
|
|
|
49
49
|
import "./engine/registry/blocks/sections/productShowcase.js";
|
|
50
50
|
import "./engine/registry/blocks/sections/aboutSection.js";
|
|
51
51
|
import "./engine/registry/blocks/sections/contactSection.js";
|
|
52
|
+
import "./engine/registry/blocks/sections/blogRecentPosts.js";
|
|
53
|
+
import "./engine/registry/blocks/sections/blogTagCloud.js";
|
|
52
54
|
import "./engine/registry/blocks/forms/form.js";
|
|
53
55
|
import "./engine/registry/blocks/forms/input.js";
|
|
54
56
|
import "./engine/registry/blocks/forms/textarea.js";
|
|
55
57
|
import "./engine/registry/blocks/forms/select.js";
|
|
56
|
-
import { componentRegistry as
|
|
57
|
-
import { createEmptySiteDocument as
|
|
58
|
-
import { corporateThemeTokens as
|
|
59
|
-
import { RenderNode as
|
|
60
|
-
import { RenderPage as
|
|
61
|
-
import { clearHtmlCache as
|
|
62
|
-
import { isSafeUrl as
|
|
63
|
-
import { Preview as
|
|
64
|
-
import { applyPatch as
|
|
65
|
-
import { HistoryManager as
|
|
66
|
-
import { PatchBuilder as
|
|
67
|
-
import { applyOverrides as
|
|
68
|
-
import { CAROUSEL_PLACEHOLDER_IMAGES as
|
|
69
|
-
import { getNavbarVariation as
|
|
70
|
-
import { generateCompleteLandingPage as
|
|
71
|
-
import { evaluateShowWhen as
|
|
72
|
-
import { pluginRegistry as
|
|
73
|
-
import { hydratePageWithContent as
|
|
74
|
-
import { matchDynamicPage as
|
|
75
|
-
import { blogPlugin as
|
|
76
|
-
import { mockBlogContentProvider as
|
|
77
|
-
import { createThemeStyle as
|
|
78
|
-
import { renderBlockNode as
|
|
79
|
-
import { darkTheme as
|
|
58
|
+
import { componentRegistry as se, componentRegistry as ge } from "./engine/registry/registry.js";
|
|
59
|
+
import { createEmptySiteDocument as ce, createEmptySiteDocument as de } from "./engine/schema/siteDocument.js";
|
|
60
|
+
import { corporateThemeTokens as fe, darkThemeTokens as he, defaultComponentTokens as xe, defaultEffectTokens as Se, defaultLayoutTokens as Te, defaultThemeTokens as ye, generateThemeCSSVariables as ue, gradientDirectionMap as Ve, gradientThemeTokens as ke, playfulThemeTokens as Ee, radiusScaleMap as Le, shadowScaleMap as Ce, spacingScaleMap as Me } from "./engine/schema/themeTokens.js";
|
|
61
|
+
import { RenderNode as be } from "./engine/render/renderNode.js";
|
|
62
|
+
import { RenderPage as He, renderPage as Ae } from "./engine/render/renderPage.js";
|
|
63
|
+
import { clearHtmlCache as we, exportBlockToHtml as Oe, exportDocumentToHtml as _e, exportPageToHtml as Ie, generateAssetsManifest as Ne } from "./engine/export/exportHtml.js";
|
|
64
|
+
import { isSafeUrl as Ge, sanitizeHtml as Ue } from "./engine/export/sanitizeHtml.js";
|
|
65
|
+
import { Preview as We, Preview as ze } from "./engine/preview/Preview.js";
|
|
66
|
+
import { applyPatch as Ke, createAddPatch as qe, createCopyPatch as Je, createMovePatch as Qe, createRemovePatch as Xe, createReplacePatch as Ye } from "./engine/patch/applyPatch.js";
|
|
67
|
+
import { HistoryManager as $e, createHistoryManager as er } from "./engine/patch/history.js";
|
|
68
|
+
import { PatchBuilder as tr } from "./engine/patch/PatchBuilder.js";
|
|
69
|
+
import { applyOverrides as ar, classicPreset as ir, cleanPreset as mr, corporatePreset as pr, getAllPresets as nr, getPreset as sr, glassPreset as gr, minimalPreset as lr, neonPreset as cr, pastelPreset as dr, playfulKidsPreset as Pr, themePresets as fr, validateContrast as hr } from "./engine/presets/themePresets.js";
|
|
70
|
+
import { CAROUSEL_PLACEHOLDER_IMAGES as Sr, HERO_IMAGE_NAMES as Tr, PLACEHOLDER_IMAGE_URL as yr, getHeroVariation as ur, heroVariationIds as Vr, heroVariations as kr } from "./engine/presets/heroVariations.js";
|
|
71
|
+
import { getNavbarVariation as Lr, navbarVariationIds as Cr, navbarVariations as Mr } from "./engine/presets/navbarVariations.js";
|
|
72
|
+
import { generateCompleteLandingPage as br, generateModernLandingPage as vr, generatePatchesForLandingPage as Hr } from "./engine/generators/generateLandingPage.js";
|
|
73
|
+
import { evaluateShowWhen as Dr } from "./engine/shared/showWhen.js";
|
|
74
|
+
import { pluginRegistry as Or } from "./engine/plugins/pluginRegistry.js";
|
|
75
|
+
import { hydratePageWithContent as Ir } from "./engine/plugins/contentHydration.js";
|
|
76
|
+
import { matchDynamicPage as Br } from "./engine/plugins/dynamicPageResolver.js";
|
|
77
|
+
import { blogPlugin as Ur } from "./engine/plugins/builtin/blog/manifest.js";
|
|
78
|
+
import { mockBlogContentProvider as Wr } from "./engine/plugins/builtin/blog/mockContentProvider.js";
|
|
79
|
+
import { createThemeStyle as Fr, generateCSSVariables as Kr, generateCSSVariablesObject as qr, mergeThemeTokens as Jr } from "./engine/theme/generateCSSVariables.js";
|
|
80
|
+
import { renderBlockNode as Xr } from "./engine/render/renderNodeImpl.js";
|
|
81
|
+
import { darkTheme as Zr, defaultTheme as $r } from "./engine/theme/defaultTheme.js";
|
|
80
82
|
export {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
83
|
+
Sr as CAROUSEL_PLACEHOLDER_IMAGES,
|
|
84
|
+
Tr as HERO_IMAGE_NAMES,
|
|
85
|
+
$e as HistoryManager,
|
|
86
|
+
oe as LandingPageEditor,
|
|
87
|
+
ae as LandingPageEditorV2,
|
|
88
|
+
me as LandingPageViewer,
|
|
89
|
+
pe as LandingPageViewerV2,
|
|
90
|
+
yr as PLACEHOLDER_IMAGE_URL,
|
|
91
|
+
tr as PatchBuilder,
|
|
92
|
+
We as Preview,
|
|
93
|
+
ze as PreviewV2,
|
|
94
|
+
be as RenderNode,
|
|
95
|
+
He as RenderPage,
|
|
96
|
+
ar as applyOverrides,
|
|
97
|
+
Ke as applyPatch,
|
|
98
|
+
se as blockRegistry,
|
|
99
|
+
Ur as blogPlugin,
|
|
100
|
+
ir as classicPreset,
|
|
101
|
+
mr as cleanPreset,
|
|
102
|
+
we as clearHtmlCache,
|
|
103
|
+
ge as componentRegistry,
|
|
104
|
+
pr as corporatePreset,
|
|
105
|
+
fe as corporateThemeTokens,
|
|
106
|
+
qe as createAddPatch,
|
|
107
|
+
Je as createCopyPatch,
|
|
108
|
+
ce as createEmptySiteDocument,
|
|
109
|
+
de as createEmptySiteDocumentV2,
|
|
110
|
+
er as createHistoryManager,
|
|
111
|
+
Qe as createMovePatch,
|
|
112
|
+
Xe as createRemovePatch,
|
|
113
|
+
Ye as createReplacePatch,
|
|
114
|
+
Fr as createSiteThemeStyle,
|
|
115
|
+
he as darkThemeTokens,
|
|
116
|
+
xe as defaultComponentTokens,
|
|
117
|
+
Se as defaultEffectTokens,
|
|
118
|
+
Te as defaultLayoutTokens,
|
|
119
|
+
ye as defaultThemeTokens,
|
|
120
|
+
Dr as evaluateShowWhen,
|
|
121
|
+
Oe as exportBlockToHtml,
|
|
122
|
+
_e as exportDocumentToHtml,
|
|
123
|
+
Ie as exportPageToHtml,
|
|
124
|
+
Ne as generateAssetsManifest,
|
|
125
|
+
br as generateCompleteLandingPage,
|
|
126
|
+
vr as generateModernLandingPage,
|
|
127
|
+
Hr as generatePatchesForLandingPage,
|
|
128
|
+
Kr as generateSiteCSSVariables,
|
|
129
|
+
qr as generateSiteCSSVariablesObject,
|
|
130
|
+
ue as generateThemeCSSVariables,
|
|
131
|
+
nr as getAllPresets,
|
|
132
|
+
ur as getHeroVariation,
|
|
133
|
+
Lr as getNavbarVariation,
|
|
134
|
+
sr as getPreset,
|
|
135
|
+
gr as glassPreset,
|
|
136
|
+
Ve as gradientDirectionMap,
|
|
137
|
+
ke as gradientThemeTokens,
|
|
138
|
+
Vr as heroVariationIds,
|
|
139
|
+
kr as heroVariations,
|
|
140
|
+
Ir as hydratePageWithContent,
|
|
141
|
+
Ge as isSafeUrl,
|
|
142
|
+
Br as matchDynamicPage,
|
|
143
|
+
Jr as mergeSiteThemeTokens,
|
|
144
|
+
lr as minimalPreset,
|
|
145
|
+
Wr as mockBlogContentProvider,
|
|
146
|
+
Cr as navbarVariationIds,
|
|
147
|
+
Mr as navbarVariations,
|
|
148
|
+
cr as neonPreset,
|
|
149
|
+
dr as pastelPreset,
|
|
150
|
+
Pr as playfulKidsPreset,
|
|
151
|
+
Ee as playfulThemeTokens,
|
|
152
|
+
Or as pluginRegistry,
|
|
153
|
+
Le as radiusScaleMap,
|
|
154
|
+
Xr as renderNode,
|
|
155
|
+
Ae as renderPage,
|
|
156
|
+
Ue as sanitizeHtml,
|
|
157
|
+
Ce as shadowScaleMap,
|
|
158
|
+
Zr as siteDarkTheme,
|
|
159
|
+
$r as siteDefaultTheme,
|
|
160
|
+
Me as spacingScaleMap,
|
|
161
|
+
fr as themePresets,
|
|
162
|
+
hr as validateContrast
|
|
161
163
|
};
|
|
162
164
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as i } from "react/jsx-runtime";
|
|
2
|
-
import { useState as
|
|
2
|
+
import { useState as P, useRef as z, useCallback as B, useEffect as V } from "react";
|
|
3
3
|
import { matchDynamicPage as N } from "../engine/plugins/dynamicPageResolver.js";
|
|
4
|
-
import { hydratePageWithContent as
|
|
4
|
+
import { hydratePageWithContent as _ } from "../engine/plugins/contentHydration.js";
|
|
5
5
|
import { logger as O } from "../utils/logger.js";
|
|
6
|
-
import { defaultThemeTokens as
|
|
7
|
-
import { exportPageToHtml as
|
|
6
|
+
import { defaultThemeTokens as A } from "../engine/schema/themeTokens.js";
|
|
7
|
+
import { exportPageToHtml as G } from "../engine/export/exportHtml.js";
|
|
8
8
|
import { createEmptySiteDocument as q } from "../engine/schema/siteDocument.js";
|
|
9
9
|
function J(o) {
|
|
10
10
|
if (!o || typeof o != "string") return !1;
|
|
@@ -30,7 +30,7 @@ function ne({
|
|
|
30
30
|
contentListParams: c,
|
|
31
31
|
onNavigate: C
|
|
32
32
|
}) {
|
|
33
|
-
const [s, j] =
|
|
33
|
+
const [s, j] = P(null), [H, u] = P(null), [D, l] = P(!0), [g, I] = P(null), [R, y] = P(null), L = z(C);
|
|
34
34
|
L.current = C;
|
|
35
35
|
const M = B((e) => {
|
|
36
36
|
const t = `<script>
|
|
@@ -143,8 +143,8 @@ function ne({
|
|
|
143
143
|
let $ = f;
|
|
144
144
|
return !T && h && ($ = {
|
|
145
145
|
...f,
|
|
146
|
-
dataSource: { mode: "list", provider: "blog-posts" }
|
|
147
|
-
}),
|
|
146
|
+
dataSource: { mode: "list", provider: "blog-posts", defaultParams: { limit: 9, _noPagination: !0 } }
|
|
147
|
+
}), _($, a, x, c).then((d) => {
|
|
148
148
|
if (e) return;
|
|
149
149
|
const p = W(
|
|
150
150
|
d,
|
|
@@ -282,10 +282,10 @@ function W(o, r, m, n, w = !0) {
|
|
|
282
282
|
...o,
|
|
283
283
|
structure: Array.isArray(o.structure) ? o.structure : []
|
|
284
284
|
}, E = q(""), c = r.theme && typeof r.theme == "object" ? r.theme : null, C = c ? {
|
|
285
|
-
...
|
|
285
|
+
...A,
|
|
286
286
|
...c,
|
|
287
|
-
colors: c.colors && typeof c.colors == "object" ? { ...
|
|
288
|
-
typography: c.typography && typeof c.typography == "object" ? { ...
|
|
287
|
+
colors: c.colors && typeof c.colors == "object" ? { ...A.colors, ...c.colors } : A.colors,
|
|
288
|
+
typography: c.typography && typeof c.typography == "object" ? { ...A.typography, ...c.typography } : A.typography
|
|
289
289
|
} : E.theme, s = {
|
|
290
290
|
...r,
|
|
291
291
|
schemaVersion: 2,
|
|
@@ -297,7 +297,7 @@ function W(o, r, m, n, w = !0) {
|
|
|
297
297
|
try {
|
|
298
298
|
const l = {};
|
|
299
299
|
D && (l.layoutFromPage = D), r.metadata && (l.siteMetadata = r.metadata);
|
|
300
|
-
const g =
|
|
300
|
+
const g = G(
|
|
301
301
|
k,
|
|
302
302
|
s,
|
|
303
303
|
w,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LandingPageViewer.js","sources":["../../src/viewer/LandingPageViewer.tsx"],"sourcesContent":["/**\n * Landing Page Viewer\n * Visualização pública da landing page.\n * Usa o mesmo mecanismo do Preview (editor): exportPageToHtml + iframe srcdoc.\n *\n * Supports dynamic pages via ContentProvider (Sprint 3):\n * - Optional `contentProviders` prop allows consumer to supply data providers\n * - Dynamic page resolution (e.g., \"blog/:slug\")\n * - Automatic content hydration before rendering\n */\n\nimport { useState, useEffect, useRef, useCallback } from \"react\";\nimport {\n SiteDocument,\n SitePage,\n exportPageToHtml,\n createEmptySiteDocument,\n defaultThemeTokens,\n} from \"../engine\";\nimport type { ContentProvider, ContentListParams } from \"../engine/plugins/types\";\nimport { matchDynamicPage } from \"../engine/plugins/dynamicPageResolver\";\nimport {\n hydratePageWithContent,\n type ContentProviderMap,\n} from \"../engine/plugins/contentHydration\";\nimport { logger } from \"../utils/logger\";\n\n/** Verifica se o HTML tem conteúdo real no body (evita usar publishedHtml vazio) */\nfunction hasBodyContent(html: string): boolean {\n if (!html || typeof html !== \"string\") return false;\n const match = html.match(/<body[^>]*>([\\s\\S]*?)<\\/body>/i);\n const bodyInner = match ? match[1].trim() : \"\";\n return bodyInner.length > 50;\n}\n\nexport interface SchoolData {\n id: string;\n name: string;\n slug: string;\n logo_url?: string;\n}\n\ninterface LandingPageViewerProps {\n siteId: string;\n apiBaseUrl: string;\n projectId: string;\n /** Slug da página (ex.: avisos). Se não informado, usa home. */\n pageSlug?: string;\n /** Slug da escola no contexto /site/escola/:schoolSlug */\n schoolSlug?: string;\n /** Dados da escola para header/navbar dinâmico (quando em contexto escola) */\n schoolData?: SchoolData;\n /**\n * Content providers for dynamic pages (e.g., blog posts, products).\n * Supplied by the consumer project to connect plugin data to the viewer.\n */\n contentProviders?: ContentProvider[];\n /**\n * Params for content list filtering (search, category).\n * Consumer extracts these from URL query params (e.g., ?busca=X&categoria=Y).\n */\n contentListParams?: ContentListParams;\n /**\n * Callback for internal navigation (link clicks inside iframe).\n * Receives the href from clicked links. Consumer should use router navigation.\n */\n onNavigate?: (href: string) => void;\n}\n\n/**\n * Builds a ContentProviderMap from an array of providers.\n */\nfunction buildProviderMap(providers?: ContentProvider[]): ContentProviderMap {\n const map: ContentProviderMap = new Map();\n if (providers) {\n for (const p of providers) {\n map.set(p.type, p);\n }\n }\n return map;\n}\n\nexport function LandingPageViewer({\n siteId,\n apiBaseUrl,\n projectId,\n pageSlug,\n schoolSlug,\n schoolData: _schoolData, // reservado para header/navbar dinâmico (logo, nome da escola)\n contentProviders,\n contentListParams,\n onNavigate,\n}: LandingPageViewerProps) {\n const [document, setDocument] = useState<SiteDocument | null>(null);\n const [publishedHtml, setPublishedHtml] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [hydratedHtml, setHydratedHtml] = useState<string | null>(null);\n\n const onNavigateRef = useRef(onNavigate);\n onNavigateRef.current = onNavigate;\n\n // Inject click + form submit interceptor into iframe HTML so interactions propagate to parent\n const injectClickInterceptor = useCallback((html: string): string => {\n const script = `<script>\n(function() {\n document.addEventListener('click', function(e) {\n var target = e.target;\n var anchor = target;\n while (anchor && anchor.tagName !== 'A') {\n anchor = anchor.parentElement;\n }\n if (anchor && anchor.tagName === 'A') {\n var href = anchor.getAttribute('href') || '';\n if (href && href !== '#' && !href.startsWith('javascript:')) {\n e.preventDefault();\n e.stopPropagation();\n window.parent.postMessage({ type: 'viewer-navigate', href: href }, '*');\n return;\n }\n }\n }, true);\n document.addEventListener('submit', function(e) {\n var form = e.target;\n if (form && form.tagName === 'FORM') {\n e.preventDefault();\n e.stopPropagation();\n var action = form.getAttribute('action') || '';\n var params = new URLSearchParams(new FormData(form));\n var href = action + (params.toString() ? '?' + params.toString() : '');\n window.parent.postMessage({ type: 'viewer-navigate', href: href }, '*');\n }\n }, true);\n})();\n</script>`;\n if (html.includes(\"</body>\")) {\n return html.replace(\"</body>\", `${script}</body>`);\n }\n return html + script;\n }, []);\n\n // Listen for navigation messages from iframe\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === \"viewer-navigate\" && event.data?.href) {\n if (onNavigateRef.current) {\n onNavigateRef.current(event.data.href);\n }\n }\n };\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, []);\n\n // Load site document from API. Uses stale flag to prevent\n // React Strict Mode double-mount from causing duplicate state updates.\n useEffect(() => {\n let stale = false;\n\n setIsLoading(true);\n setError(null);\n\n (async () => {\n try {\n const response = await fetch(\n `${apiBaseUrl}/sites/${siteId}?projectId=${projectId}`,\n );\n if (!response.ok) {\n throw new Error(\"Landing page não encontrada\");\n }\n\n const data = await response.json();\n if (stale) return;\n\n if (data.template) {\n const schemaVersion = data.template.schemaVersion;\n const hasPages =\n data.template.pages && Array.isArray(data.template.pages);\n const isV2 =\n schemaVersion === 2 || schemaVersion === \"2\" || hasPages;\n\n if (isV2) {\n const template = data.template as SiteDocument;\n if (!Array.isArray(template.pages)) {\n template.pages = [];\n }\n if (\n template.schemaVersion !== 2 &&\n template.schemaVersion !== \"2\"\n ) {\n template.schemaVersion = 2;\n }\n setDocument(template);\n } else {\n throw new Error(\n \"Formato de template legado não suportado. Por favor, recrie o site.\",\n );\n }\n } else {\n setDocument(null);\n }\n\n if (data.publishedHtml && hasBodyContent(data.publishedHtml)) {\n setPublishedHtml(data.publishedHtml);\n } else {\n setPublishedHtml(null);\n }\n\n if (!data.template && !data.publishedHtml) {\n throw new Error(\"Template não encontrado\");\n }\n } catch (err) {\n if (!stale) {\n setError(\n err instanceof Error\n ? err.message\n : \"Erro ao carregar landing page\",\n );\n }\n } finally {\n if (!stale) {\n setIsLoading(false);\n }\n }\n })();\n\n return () => {\n stale = true;\n };\n }, [siteId, apiBaseUrl, projectId]);\n\n // Hydrate pages when document + contentProviders are available.\n // Supports both: pages with explicit dataSource AND pages with blogPostGrid blocks.\n // Does NOT reset hydratedHtml at the start to avoid flash of mock data.\n // Only clears it when navigating to a page that doesn't need hydration.\n useEffect(() => {\n if (!document) {\n setHydratedHtml(null);\n return;\n }\n\n let stale = false;\n\n const pages = Array.isArray(document.pages) ? document.pages : [];\n const providerMap = buildProviderMap(contentProviders);\n\n if (providerMap.size === 0) {\n setHydratedHtml(null);\n return;\n }\n\n // Resolve the current page\n let resolvedPage: SitePage | undefined;\n let urlParams: Record<string, string> = {};\n\n if (pageSlug) {\n const exactPage = pages.find(\n (p) => p.slug === pageSlug || p.id === pageSlug,\n );\n if (exactPage) {\n resolvedPage = exactPage;\n } else {\n const match = matchDynamicPage(pages, pageSlug);\n if (match) {\n resolvedPage = match.page;\n urlParams = match.params;\n }\n }\n } else {\n resolvedPage = pages.find((p) => p.id === \"home\") ?? pages[0];\n }\n\n if (!resolvedPage) {\n setHydratedHtml(null);\n return;\n }\n\n // Check if page needs hydration:\n // 1. Has explicit dataSource (blog page, blog-post page)\n // 2. Has blogPostGrid blocks but no dataSource (home page with blog widget)\n const hasDataSource = !!resolvedPage.dataSource;\n const hasBlogBlocks = resolvedPage.structure?.some(\n (b) => b.type === \"blogPostGrid\",\n );\n\n if (!hasDataSource && !hasBlogBlocks) {\n setHydratedHtml(null);\n return;\n }\n\n // For pages without dataSource but with blog blocks, create synthetic dataSource\n let pageToHydrate = resolvedPage;\n if (!hasDataSource && hasBlogBlocks) {\n pageToHydrate = {\n ...resolvedPage,\n dataSource: { mode: \"list\" as const, provider: \"blog-posts\" },\n };\n }\n\n hydratePageWithContent(pageToHydrate, providerMap, urlParams, contentListParams)\n .then((hydratedPage) => {\n if (stale) return;\n\n // useCache: false — hydrated page has different block props than the\n // cached static render. Without this, exportPageToHtml returns the\n // cached static HTML (same page.id + docHash = same cache key).\n const html = renderPageToHtml(\n hydratedPage,\n document,\n schoolSlug,\n pages,\n false,\n );\n\n setHydratedHtml(html ?? null);\n })\n .catch((err) => {\n if (!stale) {\n logger.error(\"Error in content hydration:\", err);\n setHydratedHtml(null);\n }\n });\n\n return () => {\n stale = true;\n };\n }, [document, pageSlug, contentProviders, schoolSlug, contentListParams]);\n\n if (isLoading) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n }}\n >\n <div>Carregando...</div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n }}\n >\n <div>{error || \"Landing page não encontrada\"}</div>\n </div>\n );\n }\n\n // Preferir renderização via template (client-side) quando disponível.\n // Isso garante que o viewer usa exatamente o mesmo exportPageToHtml() do editor,\n // evitando diferenças de hover effects, CSS, etc. entre editor e site publicado.\n // publishedHtml do servidor é usado apenas como fallback quando não há template.\n const isHomeRoute = !pageSlug || pageSlug === \"home\";\n if (publishedHtml && isHomeRoute && !document) {\n return (\n <iframe\n srcDoc={injectClickInterceptor(publishedHtml)}\n title=\"Site publicado\"\n style={{\n width: \"100%\",\n minHeight: \"100vh\",\n border: \"none\",\n backgroundColor: \"#ffffff\",\n }}\n />\n );\n }\n\n // Renderizar documento (template) — mesmo pipeline do editor\n if (!document) {\n return null;\n }\n\n // Garantir que pages seja array (evita crash se API retornar formato inesperado)\n const pages = Array.isArray(document.pages) ? document.pages : [];\n\n if (pages.length === 0) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n padding: \"2rem\",\n textAlign: \"center\",\n }}\n >\n <div>Nenhuma página no site. Adicione páginas no editor.</div>\n </div>\n );\n }\n\n // If we have hydrated HTML from ContentProvider, use it\n if (hydratedHtml) {\n return (\n <iframe\n srcDoc={injectClickInterceptor(hydratedHtml)}\n title=\"Site\"\n style={{\n width: \"100%\",\n minHeight: \"100vh\",\n border: \"none\",\n backgroundColor: \"#ffffff\",\n }}\n />\n );\n }\n\n // Resolver página por slug ou id; fallback para home\n // Also try dynamic page resolution\n let page =\n (pageSlug\n ? pages.find((p) => p.slug === pageSlug || p.id === pageSlug)\n : null) ??\n null;\n\n if (!page && pageSlug) {\n const match = matchDynamicPage(pages, pageSlug);\n if (match) {\n page = match.page;\n }\n }\n\n if (!page) {\n page = pages.find((p) => p.id === \"home\") ?? pages[0];\n }\n\n if (!page) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n }}\n >\n <div>Página não encontrada</div>\n </div>\n );\n }\n\n const html = renderPageToHtml(page, document, schoolSlug, pages);\n if (!html) {\n return (\n <div\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"2rem\",\n textAlign: \"center\",\n }}\n >\n <div>Conteúdo da página vazio. Adicione blocos no editor.</div>\n </div>\n );\n }\n\n // Mesmo mecanismo do Preview (editor): iframe com srcdoc = HTML completo\n return (\n <iframe\n srcDoc={injectClickInterceptor(html)}\n title=\"Site\"\n style={{\n width: \"100%\",\n minHeight: \"100vh\",\n border: \"none\",\n backgroundColor: \"#ffffff\",\n }}\n />\n );\n}\n\n/**\n * Generates HTML from a page using the standard export pipeline.\n * Extracted to reuse for both static and hydrated pages.\n *\n * @param useCache - Pass false for hydrated pages to bypass the export cache.\n * The cache key uses page.id + docHash, which is identical for static and\n * hydrated renders of the same page. Hydrated pages have different block\n * props (real data), so they must skip the cache to avoid getting stale HTML.\n */\nfunction renderPageToHtml(\n page: SitePage,\n document: SiteDocument,\n schoolSlug?: string,\n allPages?: SitePage[],\n useCache: boolean = true,\n): string | null {\n // Garantir structure para o export (evita erro se página vier sem structure)\n const pageWithStructure = {\n ...page,\n structure: Array.isArray(page.structure) ? page.structure : [],\n };\n\n // Garantir theme completo para o export (merge com default evita theme parcial quebrar CSS)\n const defaultDoc = createEmptySiteDocument(\"\");\n const rawTheme =\n document.theme && typeof document.theme === \"object\"\n ? document.theme\n : null;\n const theme = rawTheme\n ? {\n ...defaultThemeTokens,\n ...rawTheme,\n colors:\n rawTheme.colors && typeof rawTheme.colors === \"object\"\n ? { ...defaultThemeTokens.colors, ...rawTheme.colors }\n : defaultThemeTokens.colors,\n typography:\n rawTheme.typography && typeof rawTheme.typography === \"object\"\n ? { ...defaultThemeTokens.typography, ...rawTheme.typography }\n : defaultThemeTokens.typography,\n }\n : defaultDoc.theme;\n\n const documentWithTheme: SiteDocument = {\n ...document,\n schemaVersion: 2,\n theme,\n };\n\n // basePath para links (ex.: /site ou /site/escola/:slug)\n const basePath = schoolSlug ? `/site/escola/${schoolSlug}` : \"/site\";\n\n const pages = allPages ?? document.pages;\n const homePage = pages.find((p) => p.id === \"home\") ?? pages[0];\n const layoutFromPage =\n homePage && homePage.id !== pageWithStructure.id\n ? {\n ...homePage,\n structure: Array.isArray(homePage.structure)\n ? homePage.structure\n : [],\n }\n : undefined;\n\n try {\n const exportOptions: Record<string, unknown> = {};\n if (layoutFromPage) exportOptions.layoutFromPage = layoutFromPage;\n if (document.metadata) exportOptions.siteMetadata = document.metadata;\n\n const html = exportPageToHtml(\n pageWithStructure,\n documentWithTheme,\n useCache,\n basePath,\n Object.keys(exportOptions).length > 0 ? exportOptions as any : undefined,\n );\n\n if (!html || !html.trim()) {\n return null;\n }\n\n return html;\n } catch (err) {\n logger.error(\"Error generating HTML:\", err);\n return null;\n }\n}\n"],"names":["hasBodyContent","html","match","buildProviderMap","providers","map","p","LandingPageViewer","siteId","apiBaseUrl","projectId","pageSlug","schoolSlug","_schoolData","contentProviders","contentListParams","onNavigate","document","setDocument","useState","publishedHtml","setPublishedHtml","isLoading","setIsLoading","error","setError","hydratedHtml","setHydratedHtml","onNavigateRef","useRef","injectClickInterceptor","useCallback","script","useEffect","handleMessage","event","stale","response","data","schemaVersion","hasPages","template","err","pages","providerMap","resolvedPage","urlParams","exactPage","matchDynamicPage","hasDataSource","hasBlogBlocks","b","pageToHydrate","hydratePageWithContent","hydratedPage","renderPageToHtml","logger","jsx","page","allPages","useCache","pageWithStructure","defaultDoc","createEmptySiteDocument","rawTheme","theme","defaultThemeTokens","documentWithTheme","basePath","homePage","layoutFromPage","exportOptions","exportPageToHtml"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LandingPageViewer.js","sources":["../../src/viewer/LandingPageViewer.tsx"],"sourcesContent":["/**\n * Landing Page Viewer\n * Visualização pública da landing page.\n * Usa o mesmo mecanismo do Preview (editor): exportPageToHtml + iframe srcdoc.\n *\n * Supports dynamic pages via ContentProvider (Sprint 3):\n * - Optional `contentProviders` prop allows consumer to supply data providers\n * - Dynamic page resolution (e.g., \"blog/:slug\")\n * - Automatic content hydration before rendering\n */\n\nimport { useState, useEffect, useRef, useCallback } from \"react\";\nimport {\n SiteDocument,\n SitePage,\n exportPageToHtml,\n createEmptySiteDocument,\n defaultThemeTokens,\n} from \"../engine\";\nimport type { ContentProvider, ContentListParams } from \"../engine/plugins/types\";\nimport { matchDynamicPage } from \"../engine/plugins/dynamicPageResolver\";\nimport {\n hydratePageWithContent,\n type ContentProviderMap,\n} from \"../engine/plugins/contentHydration\";\nimport { logger } from \"../utils/logger\";\n\n/** Verifica se o HTML tem conteúdo real no body (evita usar publishedHtml vazio) */\nfunction hasBodyContent(html: string): boolean {\n if (!html || typeof html !== \"string\") return false;\n const match = html.match(/<body[^>]*>([\\s\\S]*?)<\\/body>/i);\n const bodyInner = match ? match[1].trim() : \"\";\n return bodyInner.length > 50;\n}\n\nexport interface SchoolData {\n id: string;\n name: string;\n slug: string;\n logo_url?: string;\n}\n\ninterface LandingPageViewerProps {\n siteId: string;\n apiBaseUrl: string;\n projectId: string;\n /** Slug da página (ex.: avisos). Se não informado, usa home. */\n pageSlug?: string;\n /** Slug da escola no contexto /site/escola/:schoolSlug */\n schoolSlug?: string;\n /** Dados da escola para header/navbar dinâmico (quando em contexto escola) */\n schoolData?: SchoolData;\n /**\n * Content providers for dynamic pages (e.g., blog posts, products).\n * Supplied by the consumer project to connect plugin data to the viewer.\n */\n contentProviders?: ContentProvider[];\n /**\n * Params for content list filtering (search, category).\n * Consumer extracts these from URL query params (e.g., ?busca=X&categoria=Y).\n */\n contentListParams?: ContentListParams;\n /**\n * Callback for internal navigation (link clicks inside iframe).\n * Receives the href from clicked links. Consumer should use router navigation.\n */\n onNavigate?: (href: string) => void;\n}\n\n/**\n * Builds a ContentProviderMap from an array of providers.\n */\nfunction buildProviderMap(providers?: ContentProvider[]): ContentProviderMap {\n const map: ContentProviderMap = new Map();\n if (providers) {\n for (const p of providers) {\n map.set(p.type, p);\n }\n }\n return map;\n}\n\nexport function LandingPageViewer({\n siteId,\n apiBaseUrl,\n projectId,\n pageSlug,\n schoolSlug,\n schoolData: _schoolData, // reservado para header/navbar dinâmico (logo, nome da escola)\n contentProviders,\n contentListParams,\n onNavigate,\n}: LandingPageViewerProps) {\n const [document, setDocument] = useState<SiteDocument | null>(null);\n const [publishedHtml, setPublishedHtml] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [hydratedHtml, setHydratedHtml] = useState<string | null>(null);\n\n const onNavigateRef = useRef(onNavigate);\n onNavigateRef.current = onNavigate;\n\n // Inject click + form submit interceptor into iframe HTML so interactions propagate to parent\n const injectClickInterceptor = useCallback((html: string): string => {\n const script = `<script>\n(function() {\n document.addEventListener('click', function(e) {\n var target = e.target;\n var anchor = target;\n while (anchor && anchor.tagName !== 'A') {\n anchor = anchor.parentElement;\n }\n if (anchor && anchor.tagName === 'A') {\n var href = anchor.getAttribute('href') || '';\n if (href && href !== '#' && !href.startsWith('javascript:')) {\n e.preventDefault();\n e.stopPropagation();\n window.parent.postMessage({ type: 'viewer-navigate', href: href }, '*');\n return;\n }\n }\n }, true);\n document.addEventListener('submit', function(e) {\n var form = e.target;\n if (form && form.tagName === 'FORM') {\n e.preventDefault();\n e.stopPropagation();\n var action = form.getAttribute('action') || '';\n var params = new URLSearchParams(new FormData(form));\n var href = action + (params.toString() ? '?' + params.toString() : '');\n window.parent.postMessage({ type: 'viewer-navigate', href: href }, '*');\n }\n }, true);\n})();\n</script>`;\n if (html.includes(\"</body>\")) {\n return html.replace(\"</body>\", `${script}</body>`);\n }\n return html + script;\n }, []);\n\n // Listen for navigation messages from iframe\n useEffect(() => {\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === \"viewer-navigate\" && event.data?.href) {\n if (onNavigateRef.current) {\n onNavigateRef.current(event.data.href);\n }\n }\n };\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, []);\n\n // Load site document from API. Uses stale flag to prevent\n // React Strict Mode double-mount from causing duplicate state updates.\n useEffect(() => {\n let stale = false;\n\n setIsLoading(true);\n setError(null);\n\n (async () => {\n try {\n const response = await fetch(\n `${apiBaseUrl}/sites/${siteId}?projectId=${projectId}`,\n );\n if (!response.ok) {\n throw new Error(\"Landing page não encontrada\");\n }\n\n const data = await response.json();\n if (stale) return;\n\n if (data.template) {\n const schemaVersion = data.template.schemaVersion;\n const hasPages =\n data.template.pages && Array.isArray(data.template.pages);\n const isV2 =\n schemaVersion === 2 || schemaVersion === \"2\" || hasPages;\n\n if (isV2) {\n const template = data.template as SiteDocument;\n if (!Array.isArray(template.pages)) {\n template.pages = [];\n }\n if (\n template.schemaVersion !== 2 &&\n template.schemaVersion !== \"2\"\n ) {\n template.schemaVersion = 2;\n }\n setDocument(template);\n } else {\n throw new Error(\n \"Formato de template legado não suportado. Por favor, recrie o site.\",\n );\n }\n } else {\n setDocument(null);\n }\n\n if (data.publishedHtml && hasBodyContent(data.publishedHtml)) {\n setPublishedHtml(data.publishedHtml);\n } else {\n setPublishedHtml(null);\n }\n\n if (!data.template && !data.publishedHtml) {\n throw new Error(\"Template não encontrado\");\n }\n } catch (err) {\n if (!stale) {\n setError(\n err instanceof Error\n ? err.message\n : \"Erro ao carregar landing page\",\n );\n }\n } finally {\n if (!stale) {\n setIsLoading(false);\n }\n }\n })();\n\n return () => {\n stale = true;\n };\n }, [siteId, apiBaseUrl, projectId]);\n\n // Hydrate pages when document + contentProviders are available.\n // Supports both: pages with explicit dataSource AND pages with blogPostGrid blocks.\n // Does NOT reset hydratedHtml at the start to avoid flash of mock data.\n // Only clears it when navigating to a page that doesn't need hydration.\n useEffect(() => {\n if (!document) {\n setHydratedHtml(null);\n return;\n }\n\n let stale = false;\n\n const pages = Array.isArray(document.pages) ? document.pages : [];\n const providerMap = buildProviderMap(contentProviders);\n\n if (providerMap.size === 0) {\n setHydratedHtml(null);\n return;\n }\n\n // Resolve the current page\n let resolvedPage: SitePage | undefined;\n let urlParams: Record<string, string> = {};\n\n if (pageSlug) {\n const exactPage = pages.find(\n (p) => p.slug === pageSlug || p.id === pageSlug,\n );\n if (exactPage) {\n resolvedPage = exactPage;\n } else {\n const match = matchDynamicPage(pages, pageSlug);\n if (match) {\n resolvedPage = match.page;\n urlParams = match.params;\n }\n }\n } else {\n resolvedPage = pages.find((p) => p.id === \"home\") ?? pages[0];\n }\n\n if (!resolvedPage) {\n setHydratedHtml(null);\n return;\n }\n\n // Check if page needs hydration:\n // 1. Has explicit dataSource (blog page, blog-post page)\n // 2. Has blogPostGrid blocks but no dataSource (home page with blog widget)\n const hasDataSource = !!resolvedPage.dataSource;\n const hasBlogBlocks = resolvedPage.structure?.some(\n (b) => b.type === \"blogPostGrid\",\n );\n\n if (!hasDataSource && !hasBlogBlocks) {\n setHydratedHtml(null);\n return;\n }\n\n // For pages without dataSource but with blog blocks, create synthetic dataSource\n let pageToHydrate = resolvedPage;\n if (!hasDataSource && hasBlogBlocks) {\n pageToHydrate = {\n ...resolvedPage,\n dataSource: { mode: \"list\" as const, provider: \"blog-posts\", defaultParams: { limit: 9, _noPagination: true } },\n };\n }\n\n hydratePageWithContent(pageToHydrate, providerMap, urlParams, contentListParams)\n .then((hydratedPage) => {\n if (stale) return;\n\n // useCache: false — hydrated page has different block props than the\n // cached static render. Without this, exportPageToHtml returns the\n // cached static HTML (same page.id + docHash = same cache key).\n const html = renderPageToHtml(\n hydratedPage,\n document,\n schoolSlug,\n pages,\n false,\n );\n\n setHydratedHtml(html ?? null);\n })\n .catch((err) => {\n if (!stale) {\n logger.error(\"Error in content hydration:\", err);\n setHydratedHtml(null);\n }\n });\n\n return () => {\n stale = true;\n };\n }, [document, pageSlug, contentProviders, schoolSlug, contentListParams]);\n\n if (isLoading) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n }}\n >\n <div>Carregando...</div>\n </div>\n );\n }\n\n if (error) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n }}\n >\n <div>{error || \"Landing page não encontrada\"}</div>\n </div>\n );\n }\n\n // Preferir renderização via template (client-side) quando disponível.\n // Isso garante que o viewer usa exatamente o mesmo exportPageToHtml() do editor,\n // evitando diferenças de hover effects, CSS, etc. entre editor e site publicado.\n // publishedHtml do servidor é usado apenas como fallback quando não há template.\n const isHomeRoute = !pageSlug || pageSlug === \"home\";\n if (publishedHtml && isHomeRoute && !document) {\n return (\n <iframe\n srcDoc={injectClickInterceptor(publishedHtml)}\n title=\"Site publicado\"\n style={{\n width: \"100%\",\n minHeight: \"100vh\",\n border: \"none\",\n backgroundColor: \"#ffffff\",\n }}\n />\n );\n }\n\n // Renderizar documento (template) — mesmo pipeline do editor\n if (!document) {\n return null;\n }\n\n // Garantir que pages seja array (evita crash se API retornar formato inesperado)\n const pages = Array.isArray(document.pages) ? document.pages : [];\n\n if (pages.length === 0) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n padding: \"2rem\",\n textAlign: \"center\",\n }}\n >\n <div>Nenhuma página no site. Adicione páginas no editor.</div>\n </div>\n );\n }\n\n // If we have hydrated HTML from ContentProvider, use it\n if (hydratedHtml) {\n return (\n <iframe\n srcDoc={injectClickInterceptor(hydratedHtml)}\n title=\"Site\"\n style={{\n width: \"100%\",\n minHeight: \"100vh\",\n border: \"none\",\n backgroundColor: \"#ffffff\",\n }}\n />\n );\n }\n\n // Resolver página por slug ou id; fallback para home\n // Also try dynamic page resolution\n let page =\n (pageSlug\n ? pages.find((p) => p.slug === pageSlug || p.id === pageSlug)\n : null) ??\n null;\n\n if (!page && pageSlug) {\n const match = matchDynamicPage(pages, pageSlug);\n if (match) {\n page = match.page;\n }\n }\n\n if (!page) {\n page = pages.find((p) => p.id === \"home\") ?? pages[0];\n }\n\n if (!page) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minHeight: \"100vh\",\n }}\n >\n <div>Página não encontrada</div>\n </div>\n );\n }\n\n const html = renderPageToHtml(page, document, schoolSlug, pages);\n if (!html) {\n return (\n <div\n style={{\n minHeight: \"100vh\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"2rem\",\n textAlign: \"center\",\n }}\n >\n <div>Conteúdo da página vazio. Adicione blocos no editor.</div>\n </div>\n );\n }\n\n // Mesmo mecanismo do Preview (editor): iframe com srcdoc = HTML completo\n return (\n <iframe\n srcDoc={injectClickInterceptor(html)}\n title=\"Site\"\n style={{\n width: \"100%\",\n minHeight: \"100vh\",\n border: \"none\",\n backgroundColor: \"#ffffff\",\n }}\n />\n );\n}\n\n/**\n * Generates HTML from a page using the standard export pipeline.\n * Extracted to reuse for both static and hydrated pages.\n *\n * @param useCache - Pass false for hydrated pages to bypass the export cache.\n * The cache key uses page.id + docHash, which is identical for static and\n * hydrated renders of the same page. Hydrated pages have different block\n * props (real data), so they must skip the cache to avoid getting stale HTML.\n */\nfunction renderPageToHtml(\n page: SitePage,\n document: SiteDocument,\n schoolSlug?: string,\n allPages?: SitePage[],\n useCache: boolean = true,\n): string | null {\n // Garantir structure para o export (evita erro se página vier sem structure)\n const pageWithStructure = {\n ...page,\n structure: Array.isArray(page.structure) ? page.structure : [],\n };\n\n // Garantir theme completo para o export (merge com default evita theme parcial quebrar CSS)\n const defaultDoc = createEmptySiteDocument(\"\");\n const rawTheme =\n document.theme && typeof document.theme === \"object\"\n ? document.theme\n : null;\n const theme = rawTheme\n ? {\n ...defaultThemeTokens,\n ...rawTheme,\n colors:\n rawTheme.colors && typeof rawTheme.colors === \"object\"\n ? { ...defaultThemeTokens.colors, ...rawTheme.colors }\n : defaultThemeTokens.colors,\n typography:\n rawTheme.typography && typeof rawTheme.typography === \"object\"\n ? { ...defaultThemeTokens.typography, ...rawTheme.typography }\n : defaultThemeTokens.typography,\n }\n : defaultDoc.theme;\n\n const documentWithTheme: SiteDocument = {\n ...document,\n schemaVersion: 2,\n theme,\n };\n\n // basePath para links (ex.: /site ou /site/escola/:slug)\n const basePath = schoolSlug ? `/site/escola/${schoolSlug}` : \"/site\";\n\n const pages = allPages ?? document.pages;\n const homePage = pages.find((p) => p.id === \"home\") ?? pages[0];\n const layoutFromPage =\n homePage && homePage.id !== pageWithStructure.id\n ? {\n ...homePage,\n structure: Array.isArray(homePage.structure)\n ? homePage.structure\n : [],\n }\n : undefined;\n\n try {\n const exportOptions: Record<string, unknown> = {};\n if (layoutFromPage) exportOptions.layoutFromPage = layoutFromPage;\n if (document.metadata) exportOptions.siteMetadata = document.metadata;\n\n const html = exportPageToHtml(\n pageWithStructure,\n documentWithTheme,\n useCache,\n basePath,\n Object.keys(exportOptions).length > 0 ? exportOptions as any : undefined,\n );\n\n if (!html || !html.trim()) {\n return null;\n }\n\n return html;\n } catch (err) {\n logger.error(\"Error generating HTML:\", err);\n return null;\n }\n}\n"],"names":["hasBodyContent","html","match","buildProviderMap","providers","map","p","LandingPageViewer","siteId","apiBaseUrl","projectId","pageSlug","schoolSlug","_schoolData","contentProviders","contentListParams","onNavigate","document","setDocument","useState","publishedHtml","setPublishedHtml","isLoading","setIsLoading","error","setError","hydratedHtml","setHydratedHtml","onNavigateRef","useRef","injectClickInterceptor","useCallback","script","useEffect","handleMessage","event","stale","response","data","schemaVersion","hasPages","template","err","pages","providerMap","resolvedPage","urlParams","exactPage","matchDynamicPage","hasDataSource","hasBlogBlocks","b","pageToHydrate","hydratePageWithContent","hydratedPage","renderPageToHtml","logger","jsx","page","allPages","useCache","pageWithStructure","defaultDoc","createEmptySiteDocument","rawTheme","theme","defaultThemeTokens","documentWithTheme","basePath","homePage","layoutFromPage","exportOptions","exportPageToHtml"],"mappings":"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"}
|