import { XIcon } from "lucide-react"; import { useContext } from "react"; import { useForm } from "react-hook-form"; import { CMSContext } from "./cms-provider"; interface MetaContentFormData { title: string; description: string; keywords: string; canonicalUrl: string; robots: string; "og:title": string; "og:description": string; "og:image": string; "og:url": string; "og:type": string; "og:site_name": string; "twitter:card": string; "twitter:title": string; "twitter:description": string; "twitter:image": string; themeColor: string; } export default function SeoSettingsForm({ onClose }: { onClose: () => void }) { const { pageData, setPageData } = useContext(CMSContext); // Initialize form and default values by reading from tags when possible const { register, handleSubmit, watch } = useForm({ mode: "onChange", defaultValues: { title: document.title || "", description: ( document.querySelector( 'meta[name="description"]' ) as HTMLMetaElement | null )?.content || "", keywords: ( document.querySelector( 'meta[name="keywords"]' ) as HTMLMetaElement | null )?.content || "", canonicalUrl: ( document.querySelector( 'link[rel="canonical"]' ) as HTMLLinkElement | null )?.href || window.location.href, robots: ( document.querySelector( 'meta[name="robots"]' ) as HTMLMetaElement | null )?.content || "index, follow", "og:title": ( document.querySelector( 'meta[property="og:title"]' ) as HTMLMetaElement | null )?.content || "", "og:description": ( document.querySelector( 'meta[property="og:description"]' ) as HTMLMetaElement | null )?.content || "", "og:image": ( document.querySelector( 'meta[property="og:image"]' ) as HTMLMetaElement | null )?.content || "", "og:url": ( document.querySelector( 'meta[property="og:url"]' ) as HTMLMetaElement | null )?.content || window.location.href, "og:type": ( document.querySelector( 'meta[property="og:type"]' ) as HTMLMetaElement | null )?.content || "website", "og:site_name": ( document.querySelector( 'meta[property="og:site_name"]' ) as HTMLMetaElement | null )?.content || "", "twitter:card": ( document.querySelector( 'meta[name="twitter:card"]' ) as HTMLMetaElement | null )?.content || "summary_large_image", "twitter:title": ( document.querySelector( 'meta[name="twitter:title"]' ) as HTMLMetaElement | null )?.content || "", "twitter:description": ( document.querySelector( 'meta[name="twitter:description"]' ) as HTMLMetaElement | null )?.content || "", "twitter:image": ( document.querySelector( 'meta[name="twitter:image"]' ) as HTMLMetaElement | null )?.content || "", themeColor: ( document.querySelector( 'meta[name="theme-color"]' ) as HTMLMetaElement | null )?.content || "#ffffff", }, }); // Handle form submit - save into special key __seo inside pageData const onSubmit = (data: MetaContentFormData) => { pageData.__seo = data as unknown as Record; setPageData(structuredClone(pageData)); onClose(); }; return (
{/* Header */}

SEO & Metadata Settings

{/* Form */}
{/* =========================== BASIC SEO FIELDS ============================ */}

Basic Metadata

{/* =========================== OPEN GRAPH ============================ */}

Open Graph (Facebook, LinkedIn)

{[ ["og:title", "OG Title"], ["og:description", "OG Description"], ["og:image", "OG Image URL"], ["og:url", "OG URL"], ["og:type", "OG Type"], ["og:site_name", "OG Site Name"], ].map(([id, label]) => (
))}
{/* =========================== TWITTER CARD ============================ */}

Twitter Card Metadata

{[ ["twitter:title", "Twitter Title"], ["twitter:description", "Twitter Description"], ["twitter:image", "Twitter Image URL"], ].map(([id, label]) => (
))}
{/* =========================== ADVANCED OPTIONS ============================ */}

Advanced Options

Google Search Preview

{watch("title") || "Example Page Title - KBK Tech"}

{watch("canonicalUrl") || "https://kbk-tech.com/example-page"}

{watch("description") || "This is a short description that might appear in Google search results."}

{/* =========================== SUBMIT BUTTON ============================ */}
); }