diff --git a/src/app/api/export/route.ts b/src/app/api/export/route.ts
index 0a9106c..9ecc524 100644
--- a/src/app/api/export/route.ts
+++ b/src/app/api/export/route.ts
@@ -52,7 +52,9 @@ const escapeHtml = (value: string): string =>
const escapeAttr = (value: string): string => escapeHtml(value);
export const buildStaticHtml = (blocks: Block[], projectConfig?: ProjectConfig): string => {
- const pageTitleRaw = (projectConfig?.title ?? "").trim() || "Page Builder Export";
+ const baseTitleRaw = (projectConfig?.title ?? "").trim() || "Page Builder Export";
+ const seoTitleRaw = (projectConfig?.seoTitle ?? "").trim();
+ const pageTitleRaw = seoTitleRaw || baseTitleRaw;
const pageTitle = escapeHtml(pageTitleRaw);
const headExtraRaw = (projectConfig?.headHtml ?? "").trim();
@@ -84,6 +86,77 @@ export const buildStaticHtml = (blocks: Block[], projectConfig?: ProjectConfig):
const trackingRaw = (projectConfig?.trackingScript ?? "").trim();
const trackingHtml = trackingRaw ? `\n${trackingRaw}\n` : "";
+ const seoDescriptionRaw = (projectConfig?.seoDescription ?? "").trim();
+ const seoOgImageRaw = (projectConfig?.seoOgImageUrl ?? "").trim();
+ const seoCanonicalRaw = (projectConfig?.seoCanonicalUrl ?? "").trim();
+ const seoNoIndex = projectConfig?.seoNoIndex === true;
+
+ const seoHeadParts: string[] = [];
+
+ if (seoDescriptionRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+
+ if (pageTitleRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+ if (seoDescriptionRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+ seoHeadParts.push(` `);
+
+ if (seoOgImageRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+
+ if (seoCanonicalRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+
+ // Twitter 카드 메타 태그
+ seoHeadParts.push(
+ ` `,
+ );
+ if (pageTitleRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+ if (seoDescriptionRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+ if (seoOgImageRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+
+ if (seoCanonicalRaw) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+
+ if (seoNoIndex) {
+ seoHeadParts.push(
+ ` `,
+ );
+ }
+
+ const seoHeadHtml = seoHeadParts.length > 0 ? `\n${seoHeadParts.join("\n")}` : "";
+
const sectionBlocks = blocks.filter((b) => b.type === "section");
const rootBlocks = blocks.filter((b) => !b.sectionId && b.type !== "section");
@@ -515,7 +588,7 @@ export const buildStaticHtml = (blocks: Block[], projectConfig?: ProjectConfig):
${pageTitle}
- ${headExtra}
+ ${seoHeadHtml}${headExtra}
diff --git a/src/app/editor/forms/FormControllerPanel.tsx b/src/app/editor/forms/FormControllerPanel.tsx
index 811a67b..a3d5996 100644
--- a/src/app/editor/forms/FormControllerPanel.tsx
+++ b/src/app/editor/forms/FormControllerPanel.tsx
@@ -1,8 +1,6 @@
"use client";
import type { Block, ButtonBlockProps, FormBlockProps } from "@/features/editor/state/editorStore";
-import { NumericPropertyControl } from "@/features/editor/components/NumericPropertyControl";
-import { ColorPickerField, TEXT_COLOR_PALETTE } from "@/features/editor/components/ColorPickerField";
interface FormControllerPanelProps {
block: Block; // type === "form"
@@ -131,89 +129,6 @@ export function FormControllerPanel({ block, blocks, selectedBlockId, updateBloc
)}
-
-
폼 레이아웃
-
- {(formProps.formWidthMode ?? "auto") === "fixed" && (
-
- updateBlock(selectedBlockId, {
- formWidthPx: v,
- } as any)
- }
- />
- )}
-
- updateBlock(selectedBlockId, {
- marginYPx: v,
- } as any)
- }
- />
-
-
-
-
폼 스타일
- {
- updateBlock(selectedBlockId, {
- backgroundColorCustom: hex,
- } as any);
- }}
- palette={TEXT_COLOR_PALETTE}
- onPaletteSelect={(item) => {
- updateBlock(selectedBlockId, {
- backgroundColorCustom: item.color,
- } as any);
- }}
- />
-
-
폼 메시지
+
+
SEO / 메타
+
+
+
+
+
+
+
+
+
+
+
+