From 31eaa9343a97eb4aa30c6ace30721283799ea001 Mon Sep 17 00:00:00 2001 From: Jaybe Date: Sat, 15 Nov 2025 13:57:42 +0900 Subject: [PATCH] =?UTF-8?q?feat(export-options):=20Google=20Sheets=20?= =?UTF-8?q?=ED=85=9C=ED=94=8C=EB=A6=BF=20=EB=AA=A8=EB=93=9C=20=EC=98=B5?= =?UTF-8?q?=EC=85=98(UI+extras)=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/BuilderClientPage.tsx | 22 +++++++++++++++++++--- lib/exporter/extras.ts | 7 +++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/components/BuilderClientPage.tsx b/components/BuilderClientPage.tsx index 66a27d3..a0b1e5d 100644 --- a/components/BuilderClientPage.tsx +++ b/components/BuilderClientPage.tsx @@ -8,6 +8,7 @@ import { AssetManager } from '@/lib/assets/assetManager' import { buildZip } from '@/lib/exporter/zip' import { buildExtrasForPage } from '@/lib/exporter/extras' import { buildAssetsMetadata } from '@/lib/exporter/assets.meta' +import { buildAssetsIndex } from '@/lib/exporter/assets.index' import type { Section } from '@/lib/state/store' import { createFormStore, type FormState } from '@/lib/state/formStore' import FormBuilderPanel from '@/components/FormBuilderPanel' @@ -56,6 +57,7 @@ export default function BuilderClientPage() { const [manifestDisplay, setManifestDisplay] = useState('') const [manifestThemeColor, setManifestThemeColor] = useState('') const [robotsDisallow, setRobotsDisallow] = useState('') + const [sheetsMode, setSheetsMode] = useState<'auto' | 'include' | 'exclude'>('auto') const [viewport, setViewport] = useState<'desktop' | 'mobile'>(() => { if (typeof window !== 'undefined') { try { @@ -238,14 +240,14 @@ export default function BuilderClientPage() { const disallowLines = lines.map((l) => (l.startsWith('Disallow:') ? l : `Disallow: ${l}`)) return `User-agent: *\n${disallowLines.join('\n')}` })() - const baseExtras = buildExtrasForPage(valid, { robotsText: robotsTextOverride, manifest: manifestOverride }) + const baseExtras = buildExtrasForPage(valid, { robotsText: robotsTextOverride, manifest: manifestOverride, sheetsMode }) const extras: Record = { ...baseExtras, - ...(am ? { 'assets.json': buildAssetsMetadata(am) } : {}), + ...(am ? { 'assets.json': buildAssetsMetadata(am), 'assets.index.json': buildAssetsIndex(am) } : {}), } const zipBytes = await buildZip({ html: exported.html, css: exported.css, js: exported.js, assets, extras }) download('landing.zip', zipBytes) - }, [pageData, am, manifestName, manifestShortName, manifestStartUrl, manifestDisplay, manifestThemeColor, robotsDisallow]) + }, [pageData, am, manifestName, manifestShortName, manifestStartUrl, manifestDisplay, manifestThemeColor, robotsDisallow, sheetsMode]) return (
@@ -381,6 +383,20 @@ export default function BuilderClientPage() { placeholder="/private\n/tmp" /> +
} diff --git a/lib/exporter/extras.ts b/lib/exporter/extras.ts index 84cd4dd..cfc2b1c 100644 --- a/lib/exporter/extras.ts +++ b/lib/exporter/extras.ts @@ -9,6 +9,7 @@ export type ExtrasOverrides = { display: string theme_color: string }> + sheetsMode?: 'auto' | 'include' | 'exclude' } function toBytes(s: string): Uint8Array { @@ -42,10 +43,12 @@ export function buildExtrasForPage(page: Page, overrides?: ExtrasOverrides): Rec const manifestJson = JSON.stringify(manifestMerged, null, 2) out['site.webmanifest'] = toBytes(manifestJson) - // Google Sheets 템플릿: actionUrl 미지정 시 포함 + // Google Sheets 템플릿: 기본 auto. overrides.sheetsMode로 강제 포함/제외 가능 + const mode = overrides?.sheetsMode ?? 'auto' const action = page.form?.actionUrl?.trim() const hasAction = !!(action && action.length > 0) - if (!hasAction) { + const shouldInclude = mode === 'include' || (mode === 'auto' && !hasAction) + if (shouldInclude) { const code = `/** * Google Apps Script Web App for form submissions * - Deploy as Web App and set URL as form action if needed.