diff --git a/components/BuilderClientPage.tsx b/components/BuilderClientPage.tsx index 56a8da2..c9eec70 100644 --- a/components/BuilderClientPage.tsx +++ b/components/BuilderClientPage.tsx @@ -48,6 +48,13 @@ export default function BuilderClientPage() { const [ogImage, setOgImage] = useState('') const [ga4MeasurementId, setGa4MeasurementId] = useState('') const [metaPixelId, setMetaPixelId] = useState('') + // Export Options (manifest/robots overrides) + const [manifestName, setManifestName] = useState('') + const [manifestShortName, setManifestShortName] = useState('') + const [manifestStartUrl, setManifestStartUrl] = useState('') + const [manifestDisplay, setManifestDisplay] = useState('') + const [manifestThemeColor, setManifestThemeColor] = useState('') + const [robotsDisallow, setRobotsDisallow] = useState('') const [viewport, setViewport] = useState<'desktop' | 'mobile'>(() => { if (typeof window !== 'undefined') { try { @@ -186,7 +193,20 @@ export default function BuilderClientPage() { }, [pageData, am]) const doExport = useCallback(async () => { - const valid = pageSchema.parse(pageData) + let valid = pageData as Page + try { + valid = pageSchema.parse(pageData) + } catch { + const fixed: Page = { + ...pageData, + form: { + actionUrl: pageData.form?.actionUrl ?? '', + fields: pageData.form?.fields ?? [], + spamProtection: pageData.form?.spamProtection ?? { honeypotFieldName: '_hp', minSubmitSeconds: 2 }, + }, + } as Page + valid = pageSchema.parse(fixed) + } const exported = exportPage(valid, { assetManager: am ?? undefined }) try { if (typeof window !== 'undefined') { @@ -197,10 +217,24 @@ export default function BuilderClientPage() { } } catch {} const assets = am ? am.toZipStructure() : {} - const extras = buildExtrasForPage(valid) + // Build overrides from UI options + const manifestOverrideBase: Record = {} + if (manifestName && manifestName.trim().length > 0) manifestOverrideBase.name = manifestName.trim() + if (manifestShortName && manifestShortName.trim().length > 0) manifestOverrideBase.short_name = manifestShortName.trim() + if (manifestStartUrl && manifestStartUrl.trim().length > 0) manifestOverrideBase.start_url = manifestStartUrl.trim() + if (manifestDisplay && manifestDisplay.trim().length > 0) manifestOverrideBase.display = manifestDisplay.trim() + if (manifestThemeColor && manifestThemeColor.trim().length > 0) manifestOverrideBase.theme_color = manifestThemeColor.trim() + const manifestOverride = Object.keys(manifestOverrideBase).length > 0 ? (manifestOverrideBase as { name?: string; short_name?: string; start_url?: string; display?: string; theme_color?: string }) : undefined + const robotsTextOverride = (() => { + const lines = (robotsDisallow || '').split(/\n+/).map((s) => s.trim()).filter((s) => s.length > 0) + if (lines.length === 0) return undefined + const disallowLines = lines.map((l) => (l.startsWith('Disallow:') ? l : `Disallow: ${l}`)) + return `User-agent: *\n${disallowLines.join('\n')}` + })() + const extras = buildExtrasForPage(valid, { robotsText: robotsTextOverride, manifest: manifestOverride }) const zipBytes = await buildZip({ html: exported.html, css: exported.css, js: exported.js, assets, extras }) download('landing.zip', zipBytes) - }, [pageData, am]) + }, [pageData, am, manifestName, manifestShortName, manifestStartUrl, manifestDisplay, manifestThemeColor, robotsDisallow]) return (
@@ -263,6 +297,76 @@ export default function BuilderClientPage() { onSelect={(i) => setSelectedIndex(i)} />
+
+

Export Options

+ + + + + +