sanity-plugin-seofields 1.3.0 → 1.3.2

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts","../src/components/SeoHealthDashboard.tsx","../src/components/SeoHealthTool.tsx","../src/schemas/index.ts","../src/components/meta/MetaDescription.tsx","../src/utils/seoUtils.ts","../src/components/meta/MetaImage.tsx","../src/components/meta/MetaTitle.tsx","../src/components/SeoPreview.tsx","../src/utils/fieldsUtils.ts","../src/utils/utils.ts","../src/schemas/types/openGraph/index.ts","../src/components/openGraph/OgDescription.tsx","../src/components/openGraph/OgImage.tsx","../src/components/openGraph/OgImageUrl.tsx","../src/components/openGraph/OgTitle.tsx","../src/schemas/types/twitter/index.ts","../src/components/twitter/twitterDescription.tsx","../src/components/twitter/TwitterImage.tsx","../src/components/twitter/TwitterImageUrl.tsx","../src/components/twitter/twitterTitle.tsx","../src/schemas/types/metaAttribute/index.ts","../src/schemas/types/metaTag/index.ts","../src/schemas/types/robots/index.ts","../src/schemas/types/index.ts","../src/components/SeoHealthPane.tsx","../src/index.ts"],"sourcesContent":["// plugin.ts\nimport React from 'react'\nimport {definePlugin} from 'sanity'\n\nimport SeoHealthTool from './components/SeoHealthTool'\nimport types from './schemas/types'\nimport type {DocumentWithSeoHealth} from './types'\n\nexport interface SeoFieldConfig {\n title?: string\n description?: string\n}\n\nexport type SeoFieldKeys =\n | 'title'\n | 'description'\n | 'canonicalUrl'\n | 'metaImage'\n | 'keywords'\n | 'metaAttributes'\n | 'robots'\n\nexport type openGraphFieldKeys =\n | 'openGraphUrl'\n | 'openGraphTitle'\n | 'openGraphDescription'\n | 'openGraphSiteName'\n | 'openGraphType'\n | 'openGraphImageType'\n | 'openGraphImage'\n | 'openGraphImageUrl'\n\nexport type twitterFieldKeys =\n | 'twitterCard'\n | 'twitterSite'\n | 'twitterCreator'\n | 'twitterTitle'\n | 'twitterDescription'\n | 'twitterImageType'\n | 'twitterImage'\n | 'twitterImageUrl'\n\nexport type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys\n\nexport type ValidHiddenFieldKeys = Exclude<\n AllFieldKeys,\n 'openGraphImageUrl' | 'twitterImageUrl' | 'openGraphImageType' | 'twitterImageType'\n>\n\nexport interface FieldVisibilityConfig {\n hiddenFields?: ValidHiddenFieldKeys[]\n}\n\nexport interface SeoFieldsPluginConfig {\n /**\n * Enable or configure the SEO preview feature.\n * If set to `true`, the SEO preview will be enabled with default settings.\n * If set to an object, you can provide a custom prefix function to modify the URL prefix in the preview.\n * The prefix function receives the current document as an argument and should return a string.\n * Example:\n * ```\n * seoPreview: {\n * prefix: (doc) => `/${doc.slug?.current || 'untitled'}`\n * }\n * ```\n */\n seoPreview?:\n | boolean\n | {\n prefix?: (doc: {_type?: string} & Record<string, unknown>) => string\n }\n\n /**\n * A mapping of field keys to their configuration settings.\n * This allows customization of field titles and descriptions.\n * For example, to change the title of the 'title' field:\n */\n fieldOverrides?: Partial<Record<AllFieldKeys, SeoFieldConfig>>\n /**\n * A mapping of document types to field visibility configurations.\n * This allows you to specify which fields should be hidden for specific document types.\n */\n fieldVisibility?: Record<string, FieldVisibilityConfig>\n\n /**\n * A list of fields that should be hidden by default in all document types.\n * This can be overridden by specific document type settings in `fieldVisibility`.\n */\n defaultHiddenFields?: ValidHiddenFieldKeys[]\n /**\n * The base URL of your website, used for generating full URLs in the SEO preview.\n * Defaults to 'https://www.example.com' if not provided.\n */\n baseUrl?: string\n /**\n * Enable or configure the SEO Health Dashboard tool.\n * If set to `true`, the dashboard is enabled with all defaults.\n * If set to an object, you can customise the tool and dashboard settings.\n * Defaults to `true`.\n * Example:\n * ```\n * healthDashboard: {\n * toolTitle: 'SEO Overview', // Studio nav tab label\n * content: {\n * icon: '🔍', // Emoji icon shown before the page heading\n * title: 'My SEO Dashboard',// Page heading inside the tool (no emoji)\n * description: 'Track SEO across all documents', // Subtitle under the heading\n * },\n * display: {\n * typeColumn: false, // Hide the document type column (default: true)\n * documentId: false, // Hide the document ID under titles (default: true)\n * },\n * query: {\n * // Option 1 – filter by specific document types\n * types: ['post', 'page'],\n * // Option 2 – provide a full custom GROQ query (takes precedence over `types`)\n * // Must return documents with at least: _id, _type, title, seo, _updatedAt\n * groq: `*[seo != null && defined(slug.current)]{ _id, _type, title, slug, seo, _updatedAt }`,\n * },\n * }\n * ```\n */\n healthDashboard?:\n | boolean\n | {\n tool?: {\n title?: string\n name?: string\n }\n toolTitle?: string\n content?: {\n icon?: string\n title?: string\n description?: string\n /** Text shown while the license key is being verified. Defaults to \"Verifying license…\" */\n loadingLicense?: string\n /** Text shown while documents are being fetched. Defaults to \"Loading documents…\" */\n loadingDocuments?: string\n /** Text shown when the query returns zero results. Defaults to \"No documents found\" */\n noDocuments?: string\n }\n display?: {\n typeColumn?: boolean\n documentId?: boolean\n }\n query?: {\n /**\n * Limit the dashboard to specific document types.\n * Example: `['post', 'page']`\n */\n types?: string[]\n /**\n * When using `types`, also require the `seo` field to be non-null.\n * Set to `false` to include documents of those types even if `seo` is missing.\n * Defaults to `true`.\n */\n requireSeo?: boolean\n /**\n * Provide a fully custom GROQ query. Takes precedence over `types`.\n * The query must return documents with at least: _id, _type, title, seo, _updatedAt\n */\n groq?: string\n }\n /**\n * The Sanity API version to use for the client (e.g. '2023-01-01').\n * Defaults to '2023-01-01'.\n */\n apiVersion?: string\n /**\n * License key for the SEO Health Dashboard pro feature.\n * Obtain a license at https://sanity-plugin-seofields.thehardik.in\n */\n licenseKey?: string\n /**\n * Map raw `_type` values to human-readable display labels.\n * Used in both the Type column and the Type filter dropdown.\n * Any type without an entry falls back to the raw `_type` string.\n *\n * @example\n * typeLabels: { productDrug: 'Products', singleCondition: 'Condition' }\n */\n typeLabels?: Record<string, string>\n /**\n * Controls how the document type is rendered in the Type column.\n * - `'badge'` (default) — coloured pill\n * - `'text'` — plain text, useful for dense layouts\n */\n typeColumnMode?: 'badge' | 'text'\n /**\n * The document field to use as the display title in the dashboard.\n *\n * - `string` — use this field for every document type (e.g. `'name'`)\n * - `Record<string, string>` — per-type mapping; unmapped types fall back to `title`\n *\n * @example\n * titleField: 'name'\n *\n * @example\n * titleField: { post: 'title', product: 'name', category: 'label' }\n */\n titleField?: string | Record<string, string>\n /**\n * Callback function to render a custom badge next to the document title.\n * Receives the full document and should return badge data or undefined.\n *\n * @example\n * docBadge: (doc) => {\n * if (doc.services === 'NHS')\n * return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }\n * if (doc.services === 'Private')\n * return { label: 'Private', bgColor: '#fef3c7', textColor: '#92400e' }\n * }\n */\n docBadge?: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n /**\n * The `name` of the Sanity structure tool that contains the monitored documents.\n * Required when you have multiple structure tools and the documents live in a\n * non-default one. Clicking a title will navigate to\n * `/{basePath}/{structureTool}/intent/edit/…` directly.\n *\n * @example\n * structureTool: 'common'\n */\n structureTool?: string\n /**\n * Enable preview/demo mode to show dummy data.\n * Useful for testing, documentation, or showcasing the dashboard.\n * When enabled, displays realistic sample documents with various SEO scores.\n * Defaults to `false`.\n *\n * @example\n * previewMode: true\n */\n previewMode?: boolean\n }\n}\n\ninterface ResolvedDashboardConfig {\n enabled: boolean\n toolTitle: string\n toolName: string\n icon: string | undefined\n title: string | undefined\n description: string | undefined\n showTypeColumn: boolean | undefined\n showDocumentId: boolean | undefined\n queryTypes: string[] | undefined\n queryRequireSeo: boolean | undefined\n queryGroq: string | undefined\n apiVersion: string | undefined\n licenseKey: string | undefined\n typeLabels: Record<string, string> | undefined\n typeColumnMode: 'badge' | 'text' | undefined\n titleField: string | Record<string, string> | undefined\n docBadge:\n | ((\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined)\n | undefined\n loadingLicense: string | undefined\n loadingDocuments: string | undefined\n noDocuments: string | undefined\n previewMode: boolean | undefined\n structureTool: string | undefined\n}\n\nconst resolveDashboardConfig = (\n healthDashboard: SeoFieldsPluginConfig['healthDashboard'],\n): ResolvedDashboardConfig => {\n const cfg = typeof healthDashboard === 'object' ? healthDashboard : undefined\n return {\n enabled: healthDashboard !== false,\n toolTitle: cfg?.tool?.title ?? 'SEO Health',\n toolName: cfg?.tool?.name ?? 'seo-health-dashboard',\n icon: cfg?.content?.icon,\n title: cfg?.content?.title,\n description: cfg?.content?.description,\n showTypeColumn: cfg?.display?.typeColumn,\n showDocumentId: cfg?.display?.documentId,\n queryTypes: cfg?.query?.types,\n queryRequireSeo: cfg?.query?.requireSeo,\n queryGroq: cfg?.query?.groq,\n apiVersion: cfg?.apiVersion,\n licenseKey: cfg?.licenseKey,\n typeLabels: cfg?.typeLabels,\n typeColumnMode: cfg?.typeColumnMode,\n titleField: cfg?.titleField,\n docBadge: cfg?.docBadge,\n loadingLicense: cfg?.content?.loadingLicense,\n loadingDocuments: cfg?.content?.loadingDocuments,\n noDocuments: cfg?.content?.noDocuments,\n previewMode: cfg?.previewMode,\n structureTool: cfg?.structureTool,\n }\n}\n\nconst seofields = definePlugin<SeoFieldsPluginConfig | void>((config = {}) => {\n const {healthDashboard = true} = config as SeoFieldsPluginConfig\n const dash = resolveDashboardConfig(healthDashboard)\n\n const BoundSeoHealthTool = () =>\n React.createElement(SeoHealthTool, {\n icon: dash.icon,\n title: dash.title,\n description: dash.description,\n showTypeColumn: dash.showTypeColumn,\n showDocumentId: dash.showDocumentId,\n queryTypes: dash.queryTypes,\n queryRequireSeo: dash.queryRequireSeo,\n customQuery: dash.queryGroq,\n apiVersion: dash.apiVersion,\n licenseKey: dash.licenseKey,\n typeLabels: dash.typeLabels,\n typeColumnMode: dash.typeColumnMode,\n titleField: dash.titleField,\n docBadge: dash.docBadge,\n loadingLicense: dash.loadingLicense,\n loadingDocuments: dash.loadingDocuments,\n noDocuments: dash.noDocuments,\n previewMode: dash.previewMode,\n structureTool: dash.structureTool,\n })\n\n return {\n name: 'sanity-plugin-seofields',\n schema: {\n types: types(config as SeoFieldsPluginConfig),\n },\n ...(dash.enabled && {\n tools: [\n {\n name: dash.toolName,\n title: dash.toolTitle,\n component: BoundSeoHealthTool,\n icon: () => '📊',\n },\n ],\n }),\n }\n})\n\nexport default seofields\n","import React, {useCallback, useEffect, useMemo, useState} from 'react'\nimport {useClient, useWorkspace} from 'sanity'\nimport {useIntentLink} from 'sanity/router'\nimport {usePaneRouter} from 'sanity/structure'\nimport styled, {keyframes} from 'styled-components'\n\nimport {DocumentWithSeoHealth, SeoHealthMetrics} from '../types'\n\nconst DashboardContainer = styled.div`\n width: 100%;\n min-height: 100%;\n background: #f0f2f5;\n padding: 28px 32px;\n box-sizing: border-box;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n`\n\nconst PageHeader = styled.div`\n margin-bottom: 28px;\n`\n\nconst PageTitle = styled.h1`\n margin: 0 0 6px 0;\n font-size: 22px;\n font-weight: 700;\n color: #111827;\n letter-spacing: -0.3px;\n display: flex;\n align-items: center;\n gap: 10px;\n`\n\nconst PreviewBadge = styled.span`\n display: inline-block;\n background: #fef3c7;\n color: #92400e;\n font-size: 11px;\n font-weight: 600;\n padding: 4px 8px;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-left: 8px;\n`\n\nconst PageSubtitle = styled.p`\n margin: 0;\n font-size: 13px;\n color: #6b7280;\n`\n\nconst StatsGrid = styled.div`\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));\n gap: 14px;\n margin-bottom: 20px;\n`\n\nconst StatCard = styled.div<{$accent?: string}>`\n background: #ffffff;\n border-radius: 10px;\n padding: 16px 18px;\n box-shadow:\n 0 1px 3px rgba(0, 0, 0, 0.07),\n 0 1px 2px rgba(0, 0, 0, 0.05);\n border-left: ${(p) => (p.$accent ? `4px solid ${p.$accent}` : '4px solid transparent')};\n transition: box-shadow 0.15s ease;\n\n &:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n }\n`\n\nconst StatLabel = styled.div`\n font-size: 11px;\n font-weight: 500;\n color: #9ca3af;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n`\n\nconst StatValue = styled.div`\n font-size: 26px;\n font-weight: 700;\n color: #111827;\n line-height: 1;\n`\n\nconst ControlsBar = styled.div`\n background: #ffffff;\n border-radius: 10px;\n padding: 14px 18px;\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n margin-bottom: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);\n`\n\nconst SearchWrapper = styled.div`\n position: relative;\n flex: 1;\n min-width: 220px;\n`\n\nconst SearchIconSvg = styled.span`\n position: absolute;\n left: 11px;\n top: 50%;\n transform: translateY(-50%);\n color: #9ca3af;\n display: flex;\n align-items: center;\n pointer-events: none;\n`\n\nconst SearchInput = styled.input`\n width: 100%;\n height: 36px;\n padding: 0 12px 0 34px;\n border: 1px solid #e5e7eb;\n border-radius: 7px;\n font-size: 13px;\n color: #111827;\n background: #f9fafb;\n box-sizing: border-box;\n outline: none;\n transition:\n border-color 0.15s,\n background 0.15s;\n\n &::placeholder {\n color: #9ca3af;\n }\n\n &:focus {\n border-color: #6366f1;\n background: #fff;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n`\n\nconst StyledSelect = styled.select`\n height: 36px;\n padding: 0 32px 0 12px;\n border: 1px solid #e5e7eb;\n border-radius: 7px;\n font-size: 13px;\n color: #374151;\n background: #f9fafb\n url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E\")\n no-repeat right 10px center;\n appearance: none;\n outline: none;\n cursor: pointer;\n transition: border-color 0.15s;\n\n &:focus {\n border-color: #6366f1;\n background-color: #fff;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n`\n\nconst TableCard = styled.div`\n background: #ffffff;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);\n overflow: hidden;\n`\n\nconst TableHeader = styled.div`\n display: flex;\n align-items: center;\n padding: 11px 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n font-size: 11px;\n font-weight: 600;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n gap: 12px;\n`\n\nconst TableRow = styled.div`\n display: flex;\n align-items: center;\n padding: 13px 20px;\n border-bottom: 1px solid #f3f4f6;\n gap: 12px;\n transition: background 0.1s;\n\n &:last-child {\n border-bottom: none;\n }\n\n &:hover {\n background: #fafafa;\n }\n`\n\nconst ColTitle = styled.div`\n flex: 2;\n min-width: 0;\n`\n\nconst TitleWrapper = styled.div`\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n min-width: 0;\n`\n\n/* Constrains the title + doc-id block so text-overflow works inside flex */\nconst TitleCell = styled.div`\n min-width: 0;\n overflow: hidden;\n flex: 1;\n`\n\nconst ColType = styled.div`\n flex: 0.8;\n min-width: 80px;\n`\n\nconst ColScore = styled.div`\n flex: 0.6;\n min-width: 70px;\n`\n\nconst ColIssues = styled.div`\n flex: 2;\n min-width: 0;\n`\n\nconst DocTitleLink = styled.a`\n font-size: 13px;\n font-weight: 600;\n color: #4f46e5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n text-decoration: none;\n display: block;\n transition: color 0.15s;\n\n &:hover {\n color: #4338ca;\n text-decoration: underline;\n }\n`\n\nconst DocId = styled.div`\n font-size: 11px;\n color: #9ca3af;\n margin-top: 2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`\n\nconst TypeBadge = styled.span<{$bgColor?: string; $textColor?: string}>`\n display: inline-block;\n padding: 3px 8px;\n border-radius: 5px;\n font-size: 11px;\n font-weight: 500;\n background: ${(p) => p.$bgColor || '#ede9fe'};\n color: ${(p) => p.$textColor || '#5b21b6'};\n`\n\nconst TypeText = styled.span`\n font-size: 12px;\n font-weight: 500;\n color: #374151;\n`\n\nconst CustomBadge = styled.span<{$bgColor?: string; $textColor?: string; $fontSize?: string}>`\n display: inline-block;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: ${(p) => p.$fontSize || '10px'};\n font-weight: 600;\n background: ${(p) => p.$bgColor || '#e0e7ff'};\n color: ${(p) => p.$textColor || '#3730a3'};\n white-space: nowrap;\n`\n\nconst ScoreBadge = styled.span<{$score: number}>`\n display: inline-block;\n padding: 4px 10px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 700;\n background: ${(p) => {\n if (p.$score >= 80) return '#d1fae5'\n if (p.$score >= 60) return '#fef3c7'\n if (p.$score >= 40) return '#ffedd5'\n return '#fee2e2'\n }};\n color: ${(p) => {\n if (p.$score >= 80) return '#065f46'\n if (p.$score >= 60) return '#92400e'\n if (p.$score >= 40) return '#9a3412'\n return '#991b1b'\n }};\n`\n\nconst IssueTag = styled.div`\n font-size: 11px;\n color: #ef4444;\n line-height: 1.5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`\n\nconst MoreIssues = styled.div`\n font-size: 11px;\n color: #6b7280;\n cursor: pointer;\n transition: color 0.15s;\n\n &:hover {\n color: #374151;\n }\n`\n\nconst MoreIssuesWrapper = styled.div`\n position: relative;\n display: inline-block;\n`\n\nconst IssuesPopover = styled.div<{\n $left?: number\n}>`\n position: absolute;\n bottom: auto;\n left: 0;\n transform: translateY(calc(-100% - 14px));\n background: #1f2937;\n color: #ffffff;\n padding: 12px;\n border-radius: 8px;\n font-size: 12px;\n z-index: 50;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);\n width: 280px;\n word-break: break-word;\n line-height: 1.5;\n\n &::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 12px;\n width: 0;\n height: 0;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid #1f2937;\n }\n`\n\nconst PopoverIssueItem = styled.div`\n display: flex;\n gap: 6px;\n margin-bottom: 6px;\n\n &:last-child {\n margin-bottom: 0;\n }\n`\n\nconst UpgradeContainer = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100%;\n padding: 60px 24px;\n`\n\nconst UpgradeBox = styled.div`\n background: #ffffff;\n border-radius: 16px;\n padding: 48px 40px;\n max-width: 480px;\n width: 100%;\n text-align: center;\n box-shadow:\n 0 4px 24px rgba(0, 0, 0, 0.08),\n 0 1px 4px rgba(0, 0, 0, 0.05);\n border: 1px solid #e5e7eb;\n`\n\nconst UpgradeLock = styled.div`\n font-size: 40px;\n margin-bottom: 16px;\n`\n\nconst UpgradeTitle = styled.h2`\n margin: 0 0 10px;\n font-size: 20px;\n font-weight: 700;\n color: #111827;\n`\n\nconst UpgradeText = styled.p`\n margin: 0 0 20px;\n font-size: 14px;\n color: #6b7280;\n line-height: 1.6;\n`\n\nconst UpgradeCode = styled.pre`\n background: #f3f4f6;\n border-radius: 8px;\n padding: 14px 16px;\n font-size: 12px;\n color: #374151;\n text-align: left;\n margin: 0 0 24px;\n overflow-x: auto;\n line-height: 1.6;\n border: 1px solid #e5e7eb;\n`\n\nconst UpgradeButton = styled.a`\n display: inline-block;\n background: #4f46e5;\n color: #ffffff;\n font-size: 14px;\n font-weight: 600;\n padding: 10px 24px;\n border-radius: 8px;\n text-decoration: none;\n transition: background 0.15s;\n\n &:hover {\n background: #4338ca;\n }\n`\n\nconst ReloadButton = styled.button`\n display: inline-block;\n background: transparent;\n color: #6b7280;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 20px;\n border-radius: 8px;\n border: 1px solid #d1d5db;\n cursor: pointer;\n margin-top: 10px;\n transition:\n background 0.15s,\n color 0.15s,\n border-color 0.15s;\n\n &:hover {\n background: #f3f4f6;\n color: #374151;\n border-color: #9ca3af;\n }\n`\n\n// Sub-component so useIntentLink can be called at the top level of a component (not inside .map)\nconst DocTitleAnchor: React.FC<{\n id: string\n type: string\n structureTool?: string\n children: React.ReactNode\n}> = ({id, type, structureTool, children}) => {\n const {basePath} = useWorkspace()\n const {onClick: intentOnClick, href: intentHref} = useIntentLink({\n intent: 'edit',\n params: {id, type},\n })\n // When a specific structure tool name is provided, build a tool-scoped intent URL so that\n // Sanity routes directly to that tool instead of letting the router pick the first match.\n const href = structureTool\n ? `${basePath}/${structureTool}/intent/edit/id=${id};type=${type}/`\n : intentHref\n const onClick = structureTool ? undefined : intentOnClick\n return (\n <DocTitleLink href={href} onClick={onClick} title=\"Open document\">\n {children}\n </DocTitleLink>\n )\n}\n\n// Wrapper that applies DocTitleLink styles to the ChildLink <a> rendered by Sanity's pane router\nconst PaneLinkWrapper = styled.span`\n display: block;\n min-width: 0;\n overflow: hidden;\n\n a {\n font-size: 13px;\n font-weight: 600;\n color: #4f46e5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n text-decoration: none;\n display: block;\n transition: color 0.15s;\n\n &:hover {\n color: #4338ca;\n text-decoration: underline;\n }\n }\n`\n\n// Sub-component for desk-structure split-pane navigation.\n// Uses ChildLink from usePaneRouter to open the document editor to the right\n// while keeping the SEO Health pane visible on the left.\nconst DocTitleAnchorPane: React.FC<{id: string; type: string; children: React.ReactNode}> = ({\n id,\n type,\n children,\n}) => {\n const {ChildLink} = usePaneRouter()\n return (\n <PaneLinkWrapper>\n <ChildLink childId={id} childParameters={{type}}>\n {children}\n </ChildLink>\n </PaneLinkWrapper>\n )\n}\n\n// Sub-component to safely call docBadge outside a .map expression\nconst DocBadgeRenderer: React.FC<{\n doc: DocumentWithSeoHealth & Record<string, unknown>\n docBadge: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n}> = ({doc, docBadge}) => {\n const badge = docBadge(doc)\n if (!badge) return null\n return (\n <CustomBadge $bgColor={badge.bgColor} $textColor={badge.textColor} $fontSize={badge.fontSize}>\n {badge.label}\n </CustomBadge>\n )\n}\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst Spinner = styled.div`\n width: 28px;\n height: 28px;\n border: 3px solid #e5e7eb;\n border-top-color: #6366f1;\n border-radius: 50%;\n animation: ${spin} 0.7s linear infinite;\n margin: 0 auto 12px;\n`\n\nconst LoadingState = styled.div`\n padding: 48px 24px;\n text-align: center;\n color: #6b7280;\n font-size: 13px;\n`\n\nconst EmptyState = styled.div`\n padding: 48px 24px;\n text-align: center;\n color: #9ca3af;\n font-size: 13px;\n`\n\n/**\n * Color palette for dynamic document type badges\n * Colors are randomly assigned based on type hash for visual variety\n * while maintaining consistency across sessions\n */\nconst TYPE_COLOR_PALETTE: Array<{bg: string; text: string}> = [\n {bg: '#dbeafe', text: '#0c4a6e'}, // Blue\n {bg: '#dcfce7', text: '#14532d'}, // Green\n {bg: '#fce7f3', text: '#500724'}, // Pink\n {bg: '#fed7aa', text: '#7c2d12'}, // Orange\n {bg: '#e9d5ff', text: '#581c87'}, // Purple\n {bg: '#f3e8ff', text: '#3f0f5c'}, // Deep Purple\n {bg: '#ccfbf1', text: '#134e4a'}, // Teal\n {bg: '#ddd6fe', text: '#3730a3'}, // Indigo\n {bg: '#fca5a5', text: '#7f1d1d'}, // Red\n {bg: '#a7f3d0', text: '#065f46'}, // Emerald\n {bg: '#fbbf24', text: '#78350f'}, // Amber\n {bg: '#c4b5fd', text: '#3b0764'}, // Violet\n {bg: '#f0fdf4', text: '#15803d'}, // Light Green\n {bg: '#fef2f2', text: '#991b1b'}, // Light Red\n {bg: '#f5f3ff', text: '#5b21b6'}, // Light Purple\n {bg: '#fffbeb', text: '#92400e'}, // Light Amber\n]\n\n/**\n * Get dynamic color for a document type based on type name hash\n * Same type always gets the same color, but assignment is not fixed\n */\nconst getTypeColor = (type: string): {bg: string; text: string} => {\n // Generate consistent hash from type string using simple arithmetic\n let hash = 0\n for (let i = 0; i < type.length; i += 1) {\n const char = type.charCodeAt(i)\n hash = Math.abs(hash * 31 + char)\n }\n\n // Use modulo to get index within palette range\n const colorIndex = hash % TYPE_COLOR_PALETTE.length\n return TYPE_COLOR_PALETTE[colorIndex]\n}\n\nconst getStatusCategory = (score: number): SeoHealthMetrics['status'] => {\n if (score >= 80) return 'excellent'\n if (score >= 60) return 'good'\n if (score >= 40) return 'fair'\n if (score > 0) return 'poor'\n return 'missing'\n}\n\nconst scoreMetaTitle = (title?: string): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (title && title.length >= 50 && title.length <= 60) {\n score = 15\n } else if (title && title.length > 0) {\n score = 10\n if (title.length < 50) issues.push('Meta title too short (< 50 chars)')\n if (title.length > 60) issues.push('Meta title too long (> 60 chars)')\n } else {\n issues.push('Missing meta title')\n }\n\n return {score, issues}\n}\n\nconst scoreMetaDescription = (description?: string): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (description && description.length >= 120 && description.length <= 160) {\n score = 15\n } else if (description && description.length > 0) {\n score = 10\n if (description.length < 120) issues.push('Meta description too short (< 120 chars)')\n if (description.length > 160) issues.push('Meta description too long (> 160 chars)')\n } else {\n issues.push('Missing meta description')\n }\n\n return {score, issues}\n}\n\nconst scoreOpenGraph = (openGraph?: Record<string, unknown>): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (openGraph) {\n if (openGraph.title) score += 6\n else issues.push('Missing OG title')\n\n if (openGraph.description) score += 6\n else issues.push('Missing OG description')\n\n if (openGraph.image) score += 6\n else issues.push('Missing OG image')\n\n if (openGraph.type) score += 7\n else issues.push('Missing OG type')\n } else {\n issues.push('Open Graph not configured')\n }\n\n return {score, issues}\n}\n\nconst scoreTwitterCard = (twitter?: Record<string, unknown>): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (twitter) {\n if (twitter.title) score += 5\n else issues.push('Missing Twitter title')\n\n if (twitter.description) score += 5\n else issues.push('Missing Twitter description')\n\n if (twitter.image) score += 5\n else issues.push('Missing Twitter image')\n } else {\n issues.push('Twitter Card not configured')\n }\n\n return {score, issues}\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst calculateHealthScore = (doc: any): SeoHealthMetrics => {\n if (!doc.seo) {\n return {score: 0, status: 'missing', issues: ['SEO fields not configured']}\n }\n\n const {title, description, keywords, robots, canonicalUrl, openGraph, twitter} = doc.seo\n let score = 0\n const issues: string[] = []\n\n const titleResult = scoreMetaTitle(title)\n score += titleResult.score\n issues.push(...titleResult.issues)\n\n const descResult = scoreMetaDescription(description)\n score += descResult.score\n issues.push(...descResult.issues)\n\n // Image\n if (doc.seo.metaImage) score += 10\n else issues.push('Missing meta image')\n\n // Keywords\n if (keywords && keywords.length > 0) score += 10\n else issues.push('No keywords defined')\n\n // Robots\n if (robots && !robots.noIndex) score += 5\n else if (!robots) score += 5\n\n // Canonical URL\n if (canonicalUrl) score += 0 // bonus, not counted in base\n\n const ogResult = scoreOpenGraph(openGraph)\n score += ogResult.score\n issues.push(...ogResult.issues)\n\n const twResult = scoreTwitterCard(twitter)\n score += twResult.score\n issues.push(...twResult.issues)\n\n // Image Completeness bonus (+5 pts when all three images are present)\n const hasMetaImage = !!doc.seo.metaImage\n const hasOgImage = !!(openGraph && openGraph.image)\n const hasTwitterImage = !!(twitter && twitter.image)\n if (hasMetaImage && hasOgImage && hasTwitterImage) {\n score += 5\n } else {\n const missingImages: string[] = []\n if (!hasMetaImage) missingImages.push('meta image')\n if (!hasOgImage) missingImages.push('OG image')\n if (!hasTwitterImage) missingImages.push('Twitter image')\n issues.push(`Missing images for full score: ${missingImages.join(', ')}`)\n }\n\n const status = getStatusCategory(score)\n return {score, status, issues}\n}\n\nconst resolveTypeLabel = (type: string, typeLabels?: Record<string, string>): string =>\n typeLabels?.[type] ?? type\n\n/**\n * Builds the GROQ projection snippet for the title field.\n * - undefined / 'title' → `title`\n * - 'name' → `\"title\": name`\n * - { post: 'title', product: 'name' } → `\"title\": select(_type == \"post\" => title, _type == \"product\" => name, title)`\n */\nconst buildTitleProjection = (titleField?: string | Record<string, string>): string => {\n if (!titleField || titleField === 'title') return 'title'\n if (typeof titleField === 'string') return `\"title\": ${titleField}`\n const cases = Object.entries(titleField)\n .map(([type, field]) => `_type == \"${type}\" => ${field}`)\n .join(', ')\n return `\"title\": select(${cases}, title)`\n}\n\nexport interface SeoHealthDashboardProps {\n icon?: string\n title?: string\n description?: string\n showTypeColumn?: boolean\n showDocumentId?: boolean\n /**\n * Limit the dashboard to specific document type names.\n * If both queryTypes and customQuery are provided, customQuery takes precedence.\n */\n queryTypes?: string[]\n /**\n * When using `queryTypes`, also filter by `seo != null`.\n * Set to `false` to include documents of those types even without an seo field.\n * Defaults to `true`.\n */\n queryRequireSeo?: boolean\n /**\n * A fully custom GROQ query used to fetch documents.\n * Must return objects with at least: _id, _type, title, seo, _updatedAt\n * Takes precedence over queryTypes.\n */\n customQuery?: string\n /**\n * The Sanity API version to use for the client (e.g. '2023-01-01').\n * Defaults to '2023-01-01'.\n */\n apiVersion?: string\n /**\n * License key for the SEO Health Dashboard.\n * Obtain a key at https://sanity-plugin-seofields.thehardik.in\n */\n licenseKey?: string\n /**\n * Map raw `_type` values to human-readable display labels used in the\n * Type column and the Type filter dropdown.\n * Any type without an entry falls back to the raw `_type` string.\n *\n * @example\n * typeLabels={{ productDrug: 'Products', singleCondition: 'Condition' }}\n */\n typeLabels?: Record<string, string>\n /**\n * Controls how the type is rendered in the Type column.\n * - `'badge'` (default) — coloured pill, consistent with score badges\n * - `'text'` — plain text, useful for dense layouts\n */\n typeColumnMode?: 'badge' | 'text'\n /**\n * The document field to use as the display title.\n *\n * - `string` — use this field for every document type (e.g. `'name'`)\n * - `Record<string, string>` — per-type mapping; unmapped types fall back to `title`\n *\n * @example\n * // Same field for all types\n * titleField: 'name'\n *\n * @example\n * // Different field per type\n * titleField: { post: 'title', product: 'name', category: 'label' }\n */\n titleField?: string | Record<string, string>\n /**\n * Callback function to render a custom badge next to the document title.\n * Receives the full document and should return badge data or undefined.\n *\n * @example\n * docBadge: (doc) => {\n * if (doc.services === 'NHS')\n * return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }\n * if (doc.services === 'Private')\n * return { label: 'Private', bgColor: '#fef3c7', textColor: '#92400e' }\n * }\n */\n docBadge?: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n /**\n * Custom text shown while the license key is being verified.\n * Defaults to `\"Verifying license…\"`.\n */\n loadingLicense?: React.ReactNode\n /**\n * Custom text shown while documents are being fetched.\n * Defaults to `\"Loading documents…\"`.\n */\n loadingDocuments?: React.ReactNode\n /**\n * Custom text shown when the query returns zero results.\n * Defaults to `\"No documents found\"`.\n */\n noDocuments?: React.ReactNode\n /**\n * Enable preview/demo mode to show dummy data.\n * Useful for testing, documentation, or showcasing the dashboard.\n * When enabled, displays realistic sample documents with various SEO scores.\n * Defaults to `false`.\n */\n previewMode?: boolean\n /**\n * When `true`, clicking a document title opens the document editor as a split\n * pane to the right, keeping the SEO Health pane visible on the left.\n * This uses Sanity's pane router and requires the component to be rendered\n * inside a desk-structure pane context (i.e. via `createSeoHealthPane`).\n *\n * When `false` (default), clicking navigates to the document via the standard\n * intent-link system (full navigation).\n *\n * This is set to `true` automatically by `createSeoHealthPane`.\n */\n openInPane?: boolean\n /**\n * The `name` of the Sanity structure tool that contains the monitored documents.\n * When provided, clicking a document title navigates directly to that tool's\n * intent URL (`/{basePath}/{structureTool}/intent/edit/id=…;type=…/`) instead of\n * using the generic intent resolver, which always picks the first registered tool.\n *\n * Required when you have multiple structure tools and the documents live in a\n * non-default one (e.g. `name: 'common'`).\n *\n * @example\n * structureTool: 'common'\n */\n structureTool?: string\n}\n\n/**\n * Generate dummy data for preview mode showing various SEO health scenarios\n */\nconst generateDummyData = (): DocumentWithSeoHealth[] => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const dummyDocs: any[] = [\n {\n _id: 'preview-post-1',\n _type: 'post',\n title: 'Getting Started with SEO Best Practices',\n slug: {current: 'getting-started-seo'},\n _updatedAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Getting Started with SEO Best Practices | My Blog',\n description:\n 'Learn the fundamentals of SEO optimization to improve your website visibility and search rankings.',\n keywords: ['seo', 'best practices', 'optimization'],\n metaImage: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}},\n openGraph: {\n title: 'SEO Best Practices Guide',\n description: 'Master SEO optimization',\n image: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}, alt: 'SEO Guide'},\n type: 'article',\n },\n twitter: {\n title: 'SEO Best Practices',\n description: 'Learn SEO optimization',\n image: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}, alt: 'Guide'},\n card: 'summary_large_image',\n },\n },\n },\n {\n _id: 'preview-post-2',\n _type: 'post',\n title: 'Advanced Analytics Strategy',\n slug: {current: 'advanced-analytics'},\n _updatedAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Advanced Analytics',\n description: 'Strategy tips',\n keywords: ['analytics', 'data'],\n openGraph: {\n title: 'Analytics Guide',\n },\n },\n },\n {\n _id: 'preview-page-1',\n _type: 'page',\n title: 'About Us',\n slug: {current: 'about'},\n _updatedAt: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'About',\n keywords: ['company', 'team'],\n metaImage: {_type: 'image', asset: {_ref: 'image-456', _type: 'reference'}},\n },\n },\n {\n _id: 'preview-post-3',\n _type: 'post',\n title: 'Content Marketing Trends for 2024',\n slug: {current: 'content-marketing-trends'},\n _updatedAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Content Marketing Trends 2024',\n description:\n 'Discover the latest content marketing trends and strategies to engage your audience effectively.',\n keywords: ['content marketing', 'trends', 'strategy', 'engagement'],\n metaImage: {_type: 'image', asset: {_ref: 'image-789', _type: 'reference'}},\n openGraph: {\n title: 'Content Marketing Trends 2024',\n description: 'Latest trends in content marketing',\n image: {_type: 'image', asset: {_ref: 'image-789', _type: 'reference'}, alt: 'Trends'},\n type: 'article',\n },\n twitter: {\n title: 'Content Marketing Trends',\n description: 'Discover the latest trends',\n card: 'summary',\n },\n },\n },\n {\n _id: 'preview-post-4',\n _type: 'product',\n title: 'Pro Plan',\n slug: {current: 'pro-plan'},\n _updatedAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Pro',\n keywords: ['pricing'],\n },\n },\n {\n _id: 'preview-page-2',\n _type: 'page',\n title: 'Contact',\n slug: {current: 'contact'},\n _updatedAt: new Date(Date.now() - 8 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n openGraph: {\n title: 'Get in Touch',\n },\n },\n },\n {\n _id: 'preview-post-5',\n _type: 'post',\n title: 'Mobile Optimization Guide',\n slug: {current: 'mobile-optimization'},\n _updatedAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Mobile Optimization Guide: Best Practices for Responsive Design',\n description:\n 'Complete guide to mobile optimization including responsive design, performance tips, and user experience best practices for modern web development.',\n keywords: ['mobile', 'optimization', 'responsive', 'performance'],\n metaImage: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}},\n openGraph: {\n title: 'Mobile Optimization Best Practices',\n description: 'Master mobile web optimization',\n image: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}, alt: 'Mobile'},\n type: 'article',\n },\n twitter: {\n title: 'Mobile Optimization Tips',\n description: 'Responsive design best practices',\n image: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}, alt: 'Mobile'},\n card: 'summary_large_image',\n },\n },\n },\n ]\n\n // Calculate health scores and return\n return dummyDocs.map((doc) => ({\n ...doc,\n health: calculateHealthScore(doc),\n }))\n}\n\nconst SeoHealthDashboard: React.FC<SeoHealthDashboardProps> = ({\n icon = '📊',\n title = 'SEO Health Dashboard',\n description = 'Monitor and optimize SEO fields across all your documents',\n showTypeColumn = true,\n showDocumentId = true,\n queryTypes,\n queryRequireSeo = true,\n customQuery,\n apiVersion = '2023-01-01',\n licenseKey,\n typeLabels,\n typeColumnMode = 'badge',\n titleField,\n docBadge,\n loadingLicense,\n loadingDocuments,\n noDocuments,\n previewMode = false,\n openInPane = false,\n structureTool,\n}) => {\n const client = useClient({apiVersion})\n const [licenseStatus, setLicenseStatus] = useState<'loading' | 'valid' | 'invalid'>('loading')\n const [documents, setDocuments] = useState<DocumentWithSeoHealth[]>([])\n const [loading, setLoading] = useState(true)\n const [searchQuery, setSearchQuery] = useState('')\n const [filterStatus, setFilterStatus] = useState<string>('all')\n const [filterType, setFilterType] = useState<string>('all')\n const [sortBy, setSortBy] = useState<'score' | 'title'>('score')\n const [activePopover, setActivePopover] = useState<{\n top: number\n left: number\n issues: string[]\n } | null>(null)\n\n const VALIDATION_ENDPOINT = 'https://sanity-plugin-seofields.thehardik.in/api/validate-license'\n const CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour\n\n const validateLicense = useCallback(\n async (forceRefresh = false) => {\n // Preview mode bypasses license validation\n if (previewMode) {\n setLicenseStatus('valid')\n return\n }\n\n // No key provided\n if (!licenseKey) {\n setLicenseStatus('invalid')\n return\n }\n\n const projectId = client.config().projectId ?? ''\n const cacheKey = `seofields_license_${projectId}`\n\n if (forceRefresh) {\n try {\n sessionStorage.removeItem(cacheKey)\n } catch {\n // ignore storage errors\n }\n }\n\n // Check sessionStorage cache\n if (!forceRefresh) {\n try {\n const cached = sessionStorage.getItem(cacheKey)\n if (cached) {\n const {valid, ts} = JSON.parse(cached) as {valid: boolean; ts: number}\n if (Date.now() - ts < CACHE_TTL_MS) {\n setLicenseStatus(valid ? 'valid' : 'invalid')\n return\n }\n }\n } catch {\n // ignore storage errors\n }\n }\n\n setLicenseStatus('loading')\n\n try {\n const res = await fetch(VALIDATION_ENDPOINT, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify({licenseKey, projectId}),\n })\n const valid = res.ok\n setLicenseStatus(valid ? 'valid' : 'invalid')\n try {\n sessionStorage.setItem(cacheKey, JSON.stringify({valid, ts: Date.now()}))\n } catch {\n // ignore storage errors\n }\n } catch {\n // Network error — fail open to avoid blocking legitimate users\n setLicenseStatus('valid')\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [licenseKey, previewMode],\n )\n\n useEffect(() => {\n validateLicense()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [licenseKey, previewMode])\n\n const handleMouseEnterIssues = (el: HTMLDivElement | null, issues: string[]) => {\n if (!el) return\n const rect = el.getBoundingClientRect()\n const popoverWidth = 280\n const viewportWidth = window.innerWidth\n\n // Align popover left edge to trigger left edge, clamp within viewport\n let left = rect.left\n if (left + popoverWidth > viewportWidth - 10) left = viewportWidth - popoverWidth - 10\n if (left < 10) left = 10\n\n setActivePopover({top: rect.top, left, issues})\n }\n\n useEffect(() => {\n const fetchDocuments = async () => {\n try {\n setLoading(true)\n\n // Use dummy data in preview mode\n if (previewMode) {\n setDocuments(generateDummyData())\n return\n }\n\n let groqQuery: string\n let params: Record<string, unknown> = {}\n\n if (customQuery) {\n // Mode 3: fully custom GROQ (user-provided)\n groqQuery = customQuery\n } else if (queryTypes && queryTypes.length > 0) {\n // Mode 2: filter by specific document types (excluding drafts)\n const seoFilter = queryRequireSeo ? ' && seo != null' : ''\n const titleProj = buildTitleProjection(titleField)\n groqQuery = `*[_type in $types${seoFilter} && !(_id in path(\"drafts.**\"))]{\n _id,\n _type,\n ${titleProj},\n slug,\n seo,\n _updatedAt\n }`\n params = {types: queryTypes}\n } else {\n // Mode 1: default — all documents with an seo field (excluding drafts)\n const titleProj = buildTitleProjection(titleField)\n groqQuery = `*[seo != null && !(_id in path(\"drafts.**\"))]{\n _id,\n _type,\n ${titleProj},\n slug,\n seo,\n _updatedAt\n }`\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await client.fetch(groqQuery, params, {perspective: 'published'})\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const docsWithHealth: DocumentWithSeoHealth[] = result.map((doc: any) => ({\n ...doc,\n health: calculateHealthScore(doc),\n }))\n\n setDocuments(docsWithHealth)\n } catch (error) {\n console.error('Error fetching documents:', error)\n } finally {\n setLoading(false)\n }\n }\n\n fetchDocuments()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n client,\n customQuery,\n queryRequireSeo,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(queryTypes),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(titleField),\n previewMode,\n ])\n\n const uniqueDocumentTypes = useMemo(() => {\n const types = new Set(documents.map((doc) => doc._type))\n return Array.from(types).sort()\n }, [documents])\n\n const filteredAndSortedDocs = useMemo(() => {\n let filtered = documents\n\n if (searchQuery) {\n filtered = filtered.filter(\n (doc) =>\n doc.title?.toLowerCase().includes(searchQuery.toLowerCase()) ||\n doc._id?.toLowerCase().includes(searchQuery.toLowerCase()),\n )\n }\n\n if (filterStatus !== 'all') {\n filtered = filtered.filter((doc) => doc.health.status === filterStatus)\n }\n\n if (filterType !== 'all') {\n filtered = filtered.filter((doc) => doc._type === filterType)\n }\n\n const sorted = [...filtered].sort((a, b) => {\n if (sortBy === 'score') {\n return b.health.score - a.health.score\n }\n return (a.title || '').localeCompare(b.title || '')\n })\n\n return sorted\n }, [documents, searchQuery, filterStatus, filterType, sortBy])\n\n const stats = useMemo(() => {\n const total = documents.length\n const excellent = documents.filter((d) => d.health.score >= 80).length\n const good = documents.filter((d) => d.health.score >= 60 && d.health.score < 80).length\n const fair = documents.filter((d) => d.health.score >= 40 && d.health.score < 60).length\n const poor = documents.filter((d) => d.health.score > 0 && d.health.score < 40).length\n const missing = documents.filter((d) => d.health.score === 0).length\n\n const avgScore =\n total > 0 ? Math.round(documents.reduce((sum, d) => sum + d.health.score, 0) / total) : 0\n\n return {total, excellent, good, fair, poor, missing, avgScore}\n }, [documents])\n\n const handleMouseLeave = useCallback(() => {\n setActivePopover(null)\n }, [])\n\n return (\n <DashboardContainer>\n {licenseStatus === 'loading' && (\n <LoadingState style={{padding: '80px 24px'}}>\n <Spinner />\n {loadingLicense ?? 'Verifying license…'}\n </LoadingState>\n )}\n {licenseStatus === 'invalid' && (\n <UpgradeContainer>\n <UpgradeBox>\n {licenseKey ? (\n <>\n <UpgradeLock>❌</UpgradeLock>\n <UpgradeTitle>Invalid License Key</UpgradeTitle>\n <UpgradeText>\n The license key you provided is invalid or has been revoked. Please check your key\n and update it in the plugin config.\n </UpgradeText>\n <UpgradeCode>{`seofields({\n healthDashboard: {\n licenseKey: 'YOUR_LICENSE_KEY', // ← replace with a valid key\n },\n})`}</UpgradeCode>\n <UpgradeButton\n href=\"https://sanity-plugin-seofields.thehardik.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Get a New License Key →\n </UpgradeButton>\n <br />\n {/* eslint-disable-next-line react/jsx-no-bind */}\n <ReloadButton onClick={() => validateLicense(true)}>\n Click here If You Just Updated Your Key\n </ReloadButton>\n </>\n ) : (\n <>\n <UpgradeLock>🔒</UpgradeLock>\n <UpgradeTitle>SEO Health Dashboard</UpgradeTitle>\n <UpgradeText>\n This feature requires a license key. Add your key to the plugin config to unlock\n the full dashboard.\n </UpgradeText>\n <UpgradeCode>{`// sanity.config.ts\nimport { seofields } from 'sanity-plugin-seofields'\n\nexport default defineConfig({\n plugins: [\n seofields({\n healthDashboard: {\n licenseKey: 'SEOF-XXXX-XXXX-XXXX',\n },\n }),\n ],\n})`}</UpgradeCode>\n <UpgradeButton\n href=\"https://sanity-plugin-seofields.thehardik.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Get a License Key →\n </UpgradeButton>\n </>\n )}\n </UpgradeBox>\n </UpgradeContainer>\n )}\n {licenseStatus === 'valid' && (\n <>\n {/* Header */}\n <PageHeader>\n <PageTitle>\n <span>\n {icon} {title}\n </span>\n {previewMode && <PreviewBadge>Preview Mode</PreviewBadge>}\n </PageTitle>\n <PageSubtitle>{description}</PageSubtitle>\n </PageHeader>\n {/* Stats Grid */}\n {!loading && (\n <StatsGrid>\n <StatCard>\n <StatLabel>Total Docs</StatLabel>\n <StatValue>{stats.total}</StatValue>\n </StatCard>\n <StatCard>\n <StatLabel>Avg Score</StatLabel>\n <StatValue>{stats.avgScore}%</StatValue>\n </StatCard>\n <StatCard $accent=\"#10b981\">\n <StatLabel>Excellent (80+)</StatLabel>\n <StatValue>{stats.excellent}</StatValue>\n </StatCard>\n <StatCard $accent=\"#f59e0b\">\n <StatLabel>Good (60–79)</StatLabel>\n <StatValue>{stats.good}</StatValue>\n </StatCard>\n <StatCard $accent=\"#f97316\">\n <StatLabel>Fair (40–59)</StatLabel>\n <StatValue>{stats.fair}</StatValue>\n </StatCard>\n <StatCard $accent=\"#ef4444\">\n <StatLabel>Poor / Missing</StatLabel>\n <StatValue>{stats.poor + stats.missing}</StatValue>\n </StatCard>\n </StatsGrid>\n )}\n {/* Controls */}\n <ControlsBar>\n <SearchWrapper>\n <SearchIconSvg>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </SearchIconSvg>\n <SearchInput\n placeholder=\"Search documents...\"\n value={searchQuery}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setSearchQuery(e.currentTarget.value)}\n />\n </SearchWrapper>\n <StyledSelect\n value={filterStatus}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setFilterStatus(e.currentTarget.value)}\n >\n <option value=\"all\">All Status</option>\n <option value=\"excellent\">Excellent</option>\n <option value=\"good\">Good</option>\n <option value=\"fair\">Fair</option>\n <option value=\"poor\">Poor</option>\n <option value=\"missing\">Missing</option>\n </StyledSelect>\n {uniqueDocumentTypes.length > 1 && (\n <StyledSelect\n value={filterType}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setFilterType(e.currentTarget.value)}\n >\n <option value=\"all\">All Types</option>\n {uniqueDocumentTypes.map((type) => (\n <option key={type} value={type}>\n {resolveTypeLabel(type, typeLabels)}\n </option>\n ))}\n </StyledSelect>\n )}\n <StyledSelect\n value={sortBy}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setSortBy(e.currentTarget.value as 'score' | 'title')}\n >\n <option value=\"score\">Sort by Score</option>\n <option value=\"title\">Sort by Title</option>\n </StyledSelect>\n </ControlsBar>\n {/* Documents Table */}\n <TableCard>\n {loading && (\n <LoadingState>\n <Spinner />\n {loadingDocuments ?? 'Loading documents…'}\n </LoadingState>\n )}\n {!loading &&\n (filteredAndSortedDocs.length === 0 ? (\n <EmptyState>{noDocuments ?? 'No documents found'}</EmptyState>\n ) : (\n <>\n <TableHeader>\n <ColTitle>Title</ColTitle>\n {showTypeColumn && <ColType>Type</ColType>}\n <ColScore>Score</ColScore>\n <ColIssues>Top Issues</ColIssues>\n </TableHeader>\n {filteredAndSortedDocs.map((doc) => {\n return (\n <TableRow key={doc._id}>\n <ColTitle>\n <TitleWrapper>\n <TitleCell>\n {openInPane ? (\n <DocTitleAnchorPane id={doc._id} type={doc._type}>\n {doc.title || 'Untitled'}\n </DocTitleAnchorPane>\n ) : (\n <DocTitleAnchor\n id={doc._id}\n type={doc._type}\n structureTool={structureTool}\n >\n {doc.title || 'Untitled'}\n </DocTitleAnchor>\n )}\n {showDocumentId && <DocId>{doc._id}</DocId>}\n {docBadge && (\n <DocBadgeRenderer\n doc={doc as DocumentWithSeoHealth & Record<string, unknown>}\n docBadge={docBadge}\n />\n )}\n </TitleCell>\n </TitleWrapper>\n </ColTitle>\n {showTypeColumn && (\n <ColType>\n {typeColumnMode === 'text' ? (\n <TypeText>{resolveTypeLabel(doc._type, typeLabels)}</TypeText>\n ) : (\n (() => {\n const typeColor = getTypeColor(doc._type)\n return (\n <TypeBadge $bgColor={typeColor.bg} $textColor={typeColor.text}>\n {resolveTypeLabel(doc._type, typeLabels)}\n </TypeBadge>\n )\n })()\n )}\n </ColType>\n )}\n <ColScore>\n <ScoreBadge $score={doc.health.score}>{doc.health.score}%</ScoreBadge>\n </ColScore>\n <ColIssues>\n {doc.health.issues.slice(0, 2).map((issue) => (\n <IssueTag key={`issue-${doc._id}-${issue}`}>• {issue}</IssueTag>\n ))}\n {doc.health.issues.length > 2 && (\n <MoreIssuesWrapper\n // eslint-disable-next-line react/jsx-no-bind\n onMouseEnter={function (e) {\n handleMouseEnterIssues(\n e.currentTarget as HTMLDivElement,\n doc.health.issues,\n )\n }}\n onMouseLeave={handleMouseLeave}\n >\n <MoreIssues>+{doc.health.issues.length - 2} more issues</MoreIssues>\n </MoreIssuesWrapper>\n )}\n </ColIssues>\n </TableRow>\n )\n })}\n </>\n ))}\n </TableCard>\n {/* Single shared popover rendered outside the table */}\n {activePopover && (\n <IssuesPopover\n style={{\n top: activePopover.top,\n left: activePopover.left,\n transform: 'translateY(calc(-100% - 10px))',\n }}\n >\n {activePopover.issues.map((issue) => (\n <PopoverIssueItem key={issue}>⚠️ {issue}</PopoverIssueItem>\n ))}\n </IssuesPopover>\n )}{' '}\n </>\n )}{' '}\n </DashboardContainer>\n )\n}\n\nexport default SeoHealthDashboard\n","import SeoHealthDashboard, {SeoHealthDashboardProps} from './SeoHealthDashboard'\n\n/**\n * Sanity Tool component for the SEO Health Dashboard\n * This component wraps the SeoHealthDashboard for use as a custom tool in Sanity Studio\n */\nconst SeoHealthTool = (props: SeoHealthDashboardProps) => {\n return <SeoHealthDashboard {...props} />\n}\n\nexport default SeoHealthTool\n","import {defineField, defineType, SchemaTypeDefinition} from 'sanity'\n\nimport MetaDescription from '../components/meta/MetaDescription'\nimport MetaImage from '../components/meta/MetaImage'\nimport MetaTitle from '../components/meta/MetaTitle'\nimport SeoPreview from '../components/SeoPreview'\nimport {SeoFieldsPluginConfig} from '../plugin'\nimport {getFieldHiddenFunction, getFieldInfo} from '../utils/fieldsUtils'\nimport {isEmpty} from '../utils/utils'\nimport openGraph from './types/openGraph'\nimport twitter from './types/twitter'\n\nexport default function seoFieldsSchema(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition {\n return defineType({\n name: 'seoFields',\n title: 'SEO Fields',\n type: 'object',\n fields: [\n defineField({\n name: 'robots',\n title: 'Robots Settings',\n type: 'robots', // Use the separate robots type here\n hidden: getFieldHiddenFunction('robots', config),\n }),\n // 👇 conditionally spread preview field\n ...((typeof config.seoPreview === 'boolean' && config.seoPreview) ||\n (typeof config.seoPreview === 'object' && !isEmpty(config.seoPreview))\n ? [\n defineField({\n name: 'preview',\n title: 'SEO Preview',\n type: 'string',\n components: {input: SeoPreview},\n options: {\n baseUrl: config.baseUrl || 'https://www.example.com',\n ...(typeof config.seoPreview === 'object' &&\n config.seoPreview &&\n config.seoPreview.prefix\n ? {prefix: config.seoPreview.prefix}\n : {}),\n } as Record<string, unknown>,\n // Use a readOnly field to prevent editing\n // This field is just for preview purposes\n initialValue: '' as string, // Set an initial value\n readOnly: true,\n }),\n ]\n : []),\n\n defineField({\n name: 'title',\n ...getFieldInfo('title', config.fieldOverrides),\n // title: 'Meta Title',\n type: 'string',\n // description:\n // 'The meta title is displayed in search engine results as the clickable headline for a given result. It should be concise and accurately reflect the content of the page.',\n components: {\n input: MetaTitle,\n },\n // validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),\n hidden: getFieldHiddenFunction('title', config),\n }),\n defineField({\n name: 'description',\n ...getFieldInfo('description', config.fieldOverrides),\n // title: 'Meta Description',\n // description:\n // 'Provide a concise summary of the page content. This description may be used by search engines in search results.',\n type: 'text',\n rows: 3,\n components: {\n input: MetaDescription,\n },\n // validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),\n hidden: getFieldHiddenFunction('description', config),\n }),\n defineField({\n name: 'metaImage',\n ...getFieldInfo('metaImage', config.fieldOverrides),\n // title: 'Meta Image',\n // description:\n // 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',\n type: 'image',\n options: {\n hotspot: true,\n },\n components: {\n input: MetaImage,\n },\n hidden: getFieldHiddenFunction('metaImage', config),\n }),\n defineField({\n name: 'metaAttributes',\n // title: 'Additional Meta Attributes',\n ...getFieldInfo('metaAttributes', config.fieldOverrides),\n type: 'array',\n of: [{type: 'metaAttribute'}],\n // description:\n // 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',\n hidden: getFieldHiddenFunction('metaAttributes', config),\n }),\n defineField({\n name: 'keywords',\n ...getFieldInfo('keywords', config.fieldOverrides),\n title: 'Keywords',\n type: 'array',\n of: [{type: 'string'}],\n description:\n 'Add relevant keywords for this page. These keywords will be used for SEO purposes.',\n hidden: getFieldHiddenFunction('keywords', config),\n }),\n defineField({\n name: 'canonicalUrl',\n ...getFieldInfo('canonicalUrl', config.fieldOverrides),\n title: 'Canonical URL',\n type: 'url',\n description:\n 'Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.',\n hidden: getFieldHiddenFunction('canonicalUrl', config),\n }),\n openGraph(config) as any,\n twitter(config) as any,\n ],\n })\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getMetaDescriptionValidationMessages} from '../../utils/seoUtils'\n\nconst MetaDescription = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getMetaDescriptionValidationMessages(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{width: 10, height: 10, borderRadius: '50%', backgroundColor: item.color}}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default MetaDescription\n","import {FeedbackType} from '../types'\n\nexport const stopWords = ['the', 'a', 'an', 'and', 'or', 'but']\n\nexport const hasMatchingKeyword = (title: string, keywordList: string[]): boolean => {\n if (!title || keywordList.length === 0) return false\n const lowerTitle = title.toLowerCase()\n return keywordList.some((keyword) => keyword && lowerTitle.includes(keyword.toLowerCase()))\n}\n\nexport const hasKeywordOveruse = (\n title: string,\n keywordList: string[],\n maxOccurrences = 3,\n): boolean => {\n if (!title || keywordList.length === 0) return false\n const lowerTitle = title.toLowerCase()\n return keywordList.some((keyword) => {\n if (!keyword) return false\n const matches = lowerTitle.match(new RegExp(keyword.toLowerCase(), 'g'))\n return matches ? matches.length > maxOccurrences : false\n })\n}\n\nexport const startsWithStopWord = (title: string): boolean => {\n if (!title) return false\n const firstWord = title.trim().split(' ')[0].toLowerCase()\n return stopWords.includes(firstWord)\n}\n\nexport const primaryKeywordAtStart = (title: string, keywords: string[]): boolean => {\n if (!title || keywords.length === 0) return true\n return title.toLowerCase().startsWith(keywords[0].toLowerCase())\n}\n\nexport const truncate = (text: string, maxLength: number): string =>\n text.length > maxLength ? `${text.slice(0, maxLength)}…` : text\n\nexport const hasExcessivePunctuation = (title: string): boolean => /[!@#$%^&*]{2,}/.test(title)\n\nexport const getMetaTitleValidationMessages = (\n title: string,\n keywords: string[],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n const minChar = 50\n const maxChar = 60\n const charCount = title?.length || 0\n\n // Empty check\n if (!title?.trim()) {\n feedback.push({text: 'Meta Title is empty. Add content to improve SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (charCount < minChar)\n feedback.push({\n text: `Title is ${charCount} characters — below recommended ${minChar}.`,\n color: 'orange',\n })\n else if (charCount > maxChar)\n feedback.push({\n text: `Title is ${charCount} characters — exceeds recommended ${maxChar}.`,\n color: 'red',\n })\n else feedback.push({text: `Title length (${charCount}) looks good for SEO.`, color: 'green'})\n\n // Keyword checks\n if (isParentseoField) {\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(title, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in title — good job!'\n : 'Keywords defined but missing in title.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(title, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Stop word check\n if (startsWithStopWord(title))\n feedback.push({text: 'Title starts with a stop word — consider rephrasing.', color: 'orange'})\n\n // Punctuation check\n if (hasExcessivePunctuation(title))\n feedback.push({text: 'Title contains excessive punctuation — simplify it.', color: 'orange'})\n\n return feedback\n}\n\nexport const getMetaDescriptionValidationMessages = (\n description: string,\n keywords: string[],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n const minChar = 120\n const maxChar = 160\n const charCount = description?.length || 0\n\n if (!description?.trim()) {\n feedback.push({text: 'Meta description is empty. Add content to improve SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (charCount < minChar)\n feedback.push({\n text: `Description is ${charCount} chars — below recommended ${minChar}.`,\n color: 'orange',\n })\n else if (charCount > maxChar)\n feedback.push({\n text: `Description is ${charCount} chars — exceeds recommended ${maxChar}.`,\n color: 'red',\n })\n else\n feedback.push({text: `Description length (${charCount}) looks good for SEO.`, color: 'green'})\n\n // Keyword checks\n if (isParentseoField) {\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(description, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in description — good job!'\n : 'Keywords defined but missing in description.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(description, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Stop word / filler check\n if (startsWithStopWord(description))\n feedback.push({\n text: 'Description starts with a stop word — consider rephrasing.',\n color: 'orange',\n })\n\n // Punctuation / special characters\n if (hasExcessivePunctuation(description))\n feedback.push({\n text: 'Description contains excessive punctuation — simplify it.',\n color: 'orange',\n })\n\n return feedback\n}\n\nexport const getOgTitleValidation = (\n title: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 40\n const max = 60\n const count = title?.length || 0\n\n // Empty check\n if (!title?.trim()) {\n feedback.push({text: 'OG Title is empty. Add content for better social preview.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `OG Title is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({text: `OG Title is ${count} chars — exceeds recommended ${max}.`, color: 'red'})\n else feedback.push({text: `OG Title length (${count}) looks good.`, color: 'green'})\n\n if (isParentseoField) {\n // Keyword checks\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(title, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in OG title — good job!'\n : 'Keywords defined but missing in OG title.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(title, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times in OG title — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Additional OG-specific checks\n if (startsWithStopWord(title))\n feedback.push({\n text: 'OG Title starts with a stop word — consider rephrasing.',\n color: 'orange',\n })\n\n if (hasExcessivePunctuation(title))\n feedback.push({text: 'OG Title contains excessive punctuation — simplify it.', color: 'orange'})\n\n return feedback\n}\n\nexport const getOgDescriptionValidation = (\n desc: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 90\n const max = 120\n const count = desc?.length || 0\n\n // Empty check\n if (!desc?.trim()) {\n feedback.push({\n text: 'OG Description is empty. Add content for better social preview.',\n color: 'red',\n })\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `OG Description is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({\n text: `OG Description is ${count} chars — exceeds recommended ${max}.`,\n color: 'red',\n })\n else feedback.push({text: `OG Description length (${count}) looks good.`, color: 'green'})\n\n // Keyword checks\n if (isParentseoField) {\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(desc, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in OG description — good job!'\n : 'Keywords defined but missing in OG description.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(desc, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times in OG description — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Additional OG-specific checks\n if (startsWithStopWord(desc))\n feedback.push({\n text: 'OG Description starts with a stop word — consider rephrasing.',\n color: 'orange',\n })\n\n if (hasExcessivePunctuation(desc))\n feedback.push({\n text: 'OG Description contains excessive punctuation — simplify it.',\n color: 'orange',\n })\n\n return feedback\n}\n\nexport const getTwitterTitleValidation = (\n title: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 30\n const max = 70\n const count = title?.length || 0\n\n if (!title?.trim()) {\n feedback.push({text: 'X Title is empty. Add content for better SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `X Title is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({\n text: `X Title is ${count} chars — exceeds recommended ${max}.`,\n color: 'red',\n })\n else feedback.push({text: `X Title length (${count}) looks good.`, color: 'green'})\n\n if (isParentseoField) {\n // Keyword checks\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(title, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in X title — good job!'\n : 'Keywords defined but missing in X title.',\n color: hasKeyword ? 'green' : 'red',\n })\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Punctuation check\n if (/[!@#$%^&*]{2,}/.test(title))\n feedback.push({text: 'X Title has excessive punctuation — simplify it.', color: 'orange'})\n\n return feedback\n}\n\nexport const getTwitterDescriptionValidation = (\n desc: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 50\n const max = 200\n const count = desc?.length || 0\n\n if (!desc?.trim()) {\n feedback.push({text: 'X Description is empty. Add content for better SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `X Description is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({\n text: `X Description is ${count} chars — exceeds recommended ${max}.`,\n color: 'red',\n })\n else feedback.push({text: `X Description length (${count}) looks good.`, color: 'green'})\n\n if (isParentseoField) {\n // Keyword checks\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(desc, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in X description — good job!'\n : 'Keywords defined but missing in X description.',\n color: hasKeyword ? 'green' : 'red',\n })\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Punctuation check\n if (/[!@#$%^&*]{2,}/.test(desc))\n feedback.push({\n text: 'X Description has excessive punctuation — simplify it.',\n color: 'orange',\n })\n\n return feedback\n}\n\n// ── Image Validation Helpers ──\n\n/** Check if an image is set in an OG/Twitter sub-object (handles upload vs URL) */\nexport const isSubImageSet = (subObj: Record<string, unknown> | null | undefined): boolean => {\n if (!subObj) return false\n if (subObj.imageType === 'url') return !!(subObj.imageUrl as string)?.trim()\n const img = subObj.image as Record<string, unknown> | undefined\n return !!img?.asset\n}\n\n/** Check if metaImage asset is set */\nconst isMetaImageSet = (seoParent: Record<string, unknown> | null | undefined): boolean => {\n if (!seoParent) return false\n const metaImage = seoParent.metaImage as Record<string, unknown> | undefined\n return !!metaImage?.asset\n}\n\nexport const getMetaImageValidation = (\n hasImage: boolean,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!hasImage) {\n feedback.push({\n text: 'No meta image provided. Adding an image improves click-through rates.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'Meta image is set — great for SEO and social sharing.', color: 'green'})\n\n const ogSet = isSubImageSet(seoParent?.openGraph as Record<string, unknown> | undefined)\n const twSet = isSubImageSet(seoParent?.twitter as Record<string, unknown> | undefined)\n\n if (!ogSet && !twSet) {\n feedback.push({\n text: 'OG and Twitter images are missing — add them for full social coverage.',\n color: 'orange',\n })\n } else if (!ogSet) {\n feedback.push({\n text: 'OG image is missing — add it for better Facebook/LinkedIn previews.',\n color: 'orange',\n })\n } else if (!twSet) {\n feedback.push({\n text: 'Twitter image is missing — add it for better X (Twitter) cards.',\n color: 'orange',\n })\n } else {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n }\n\n return feedback\n}\n\nexport const getOgImageValidation = (\n hasImage: boolean,\n altText: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!hasImage) {\n feedback.push({\n text: 'No OG image provided. Social shares will lack a visual preview.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'OG image is set — good for social sharing.', color: 'green'})\n\n if (altText?.trim()) {\n feedback.push({text: 'Alt text is set — good for accessibility.', color: 'green'})\n } else {\n feedback.push({text: 'Consider adding alt text for better accessibility.', color: 'orange'})\n }\n\n const metaSet = isMetaImageSet(seoParent)\n const twSet = isSubImageSet(seoParent?.twitter as Record<string, unknown> | undefined)\n\n if (metaSet && twSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!twSet)\n feedback.push({\n text: 'Twitter image is missing — add it for X (Twitter) cards.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n\nexport const getOgImageUrlValidation = (\n imageUrl: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!imageUrl?.trim()) {\n feedback.push({\n text: 'No OG image URL provided. Social shares will lack a visual preview.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'OG image URL is set — good for social sharing.', color: 'green'})\n\n const metaSet = isMetaImageSet(seoParent)\n const twSet = isSubImageSet(seoParent?.twitter as Record<string, unknown> | undefined)\n\n if (metaSet && twSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!twSet)\n feedback.push({\n text: 'Twitter image is missing — add it for X (Twitter) cards.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n\nexport const getTwitterImageValidation = (\n hasImage: boolean,\n altText: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!hasImage) {\n feedback.push({\n text: 'No Twitter image provided. Posts on X will lack a visual.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'Twitter image is set — good for X sharing.', color: 'green'})\n\n if (altText?.trim()) {\n feedback.push({text: 'Alt text is set — good for accessibility.', color: 'green'})\n } else {\n feedback.push({text: 'Consider adding alt text for better accessibility.', color: 'orange'})\n }\n\n const metaSet = isMetaImageSet(seoParent)\n const ogSet = isSubImageSet(seoParent?.openGraph as Record<string, unknown> | undefined)\n\n if (metaSet && ogSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!ogSet)\n feedback.push({\n text: 'OG image is missing — add it for Facebook/LinkedIn sharing.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n\nexport const getTwitterImageUrlValidation = (\n imageUrl: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!imageUrl?.trim()) {\n feedback.push({\n text: 'No Twitter image URL provided. Posts on X will lack a visual.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'Twitter image URL is set — good for X sharing.', color: 'green'})\n\n const metaSet = isMetaImageSet(seoParent)\n const ogSet = isSubImageSet(seoParent?.openGraph as Record<string, unknown> | undefined)\n\n if (metaSet && ogSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!ogSet)\n feedback.push({\n text: 'OG image is missing — add it for Facebook/LinkedIn sharing.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {ObjectInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getMetaImageValidation} from '../../utils/seoUtils'\n\nconst MetaImage = (props: ObjectInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n const hasImage = !!(value as Record<string, unknown> | undefined)?.asset\n\n const feedbackItems = useMemo(\n () => getMetaImageValidation(hasImage, seoParent),\n [hasImage, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default MetaImage\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getMetaTitleValidationMessages} from '../../utils/seoUtils'\n\nconst MetaTitle = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getMetaTitleValidationMessages(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default MetaTitle\n","import {Box, Stack, Text} from '@sanity/ui'\nimport React from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\nimport styled from 'styled-components'\n\nimport {truncate} from '../utils/seoUtils'\n\nconst PreviewContainer = styled.div`\n max-width: 600px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n border: 1px solid #dadce0;\n border-radius: 8px;\n overflow: hidden;\n`\n\nconst PreviewHeader = styled.div`\n background: #f8f9fa;\n padding: 12px 16px;\n border-bottom: 1px solid #dadce0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n`\n\nconst PreviewBody = styled.div`\n padding: 16px;\n`\n\nconst SerpUrl = styled.p`\n margin: 0 0 4px;\n color: #006621;\n font-size: 13px;\n line-height: 1.4;\n word-break: break-word;\n`\n\nconst SerpTitle = styled.h3`\n margin: 0 0 8px;\n color: #1a0dab;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.4;\n word-break: break-word;\n\n &:hover {\n text-decoration: underline;\n }\n`\n\nconst SerpDescription = styled.p`\n margin: 0;\n color: #545454;\n font-size: 14px;\n line-height: 1.6;\n word-break: break-word;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`\n\nconst LiveIndicator = styled.span`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: #4f46e5;\n background: #f0f4ff;\n padding: 4px 8px;\n border-radius: 4px;\n`\n\nconst SeoPreview = (props: StringInputProps): React.ReactElement => {\n const {path, schemaType} = props\n const {options} = schemaType as {\n options?: {\n baseUrl?: string\n prefix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n }\n }\n const baseUrl = options?.baseUrl || 'https://www.example.com'\n const prefixFunction = options?.prefix as\n | ((doc: {_type?: string} & Record<string, unknown>) => string)\n | undefined\n const parent = useFormValue([path[0]]) || {\n title: '',\n description: '',\n canonicalUrl: '',\n }\n const rootDoc: {\n slug?: {current: string}\n } = useFormValue([]) || {\n slug: {current: ''},\n }\n const slug: string = rootDoc?.slug?.current || ''\n\n const {\n title,\n description,\n canonicalUrl: url,\n } = parent as {\n title?: string\n description?: string\n canonicalUrl?: string\n }\n\n // Build full URL\n const base = (url || baseUrl)?.replace(/\\/+$/, '')\n const slugStr = String(slug || '').replace(/^\\/+/, '')\n const pref = String(\n prefixFunction ? prefixFunction(rootDoc as {slug?: {current: string}}) : '',\n ).replace(/^\\/+|\\/+$/g, '')\n const urlPath = [pref, slugStr].filter(Boolean).join('/')\n const finalUrl = urlPath ? `${base}/${urlPath}` : base\n\n // Extract domain for display\n const domain = (() => {\n try {\n const u = new URL(finalUrl || base)\n return u.hostname\n } catch {\n return 'example.com'\n }\n })()\n\n // Format URL display with › separator\n const urlDisplay = `${domain}${urlPath ? ` › ${urlPath.split('/').slice(-1)[0]}` : ''}`\n\n return (\n <Box padding={3}>\n <PreviewContainer>\n <PreviewHeader>\n <span\n style={{\n fontSize: '11px',\n color: '#5f6368',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n Search Preview\n </span>\n <LiveIndicator>\n <span\n style={{\n width: '4px',\n height: '4px',\n borderRadius: '50%',\n backgroundColor: '#4f46e5',\n display: 'inline-block',\n }}\n />\n Live\n </LiveIndicator>\n </PreviewHeader>\n\n <PreviewBody>\n <SerpUrl>{finalUrl ? urlDisplay : 'example.com › page-url'}</SerpUrl>\n <SerpTitle>\n {title && title.length > 0 ? truncate(title, 60) : 'Your SEO Title will appear here'}\n </SerpTitle>\n <SerpDescription>\n {description && description.length > 0\n ? truncate(description, 160)\n : 'Your meta description will show up here. Make it compelling!'}\n </SerpDescription>\n </PreviewBody>\n </PreviewContainer>\n </Box>\n )\n}\n\nexport default SeoPreview\n","import {AllFieldKeys, SeoFieldsPluginConfig, ValidHiddenFieldKeys} from '../plugin'\n\nconst DEFAULT_FIELD_INFO: Record<AllFieldKeys, {title: string; description: string}> = {\n title: {\n title: 'Meta Title',\n description:\n 'The meta title is displayed in search engine results as the clickable headline for a given result. It should be concise and accurately reflect the content of the page.',\n },\n description: {\n title: 'Meta Description',\n description:\n 'Provide a concise summary of the page content. This description may be used by search engines in search results.',\n },\n metaImage: {\n title: 'Meta Image',\n description:\n 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',\n },\n keywords: {\n title: 'Keywords',\n description:\n 'Add relevant keywords for this page. These keywords will be used for SEO purposes.',\n },\n canonicalUrl: {\n title: 'Canonical URL',\n description:\n 'Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.',\n },\n robots: {\n title: 'Robots Settings',\n description: 'Configure how search engine crawlers should index and follow links on this page.',\n },\n metaAttributes: {\n title: 'Additional Meta Attributes',\n description:\n 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',\n },\n openGraphTitle: {\n title: 'Open Graph Title',\n description: '',\n },\n openGraphUrl: {\n title: 'Open Graph URL',\n description:\n 'The canonical URL of the page. This should be the full URL including protocol (https://).',\n },\n openGraphDescription: {\n title: 'Open Graph Description',\n description: '',\n },\n openGraphSiteName: {\n title: 'Open Graph Site Name',\n description: 'The name of your website. This is often the site title.',\n },\n openGraphType: {\n title: 'Open Graph Type',\n description: 'Select the type of content for Open Graph.',\n },\n openGraphImageType: {\n title: 'Image Type',\n description: 'Choose whether to upload an image or provide an image URL for Open Graph.',\n },\n openGraphImage: {\n title: 'Open Graph Image',\n description:\n 'Recommended size: 1200x630px (minimum 600x315px). Max file size: 5MB. Aspect ratio 1.91:1.',\n },\n openGraphImageUrl: {\n title: 'Open Graph Image URL',\n description:\n 'Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px).',\n },\n twitterCard: {\n title: 'X Card Type',\n description: '',\n },\n twitterSite: {\n title: 'Site X Handle',\n description: 'The X (formerly Twitter) handle of the website (e.g., @example)',\n },\n twitterCreator: {\n title: 'X Creator Handle',\n description: 'The X (formerly Twitter) handle of the content creator (e.g., @creator)',\n },\n twitterTitle: {\n title: 'X Title',\n description: 'The title of the content as it should appear on X (formerly Twitter).',\n },\n twitterDescription: {\n title: 'X Description',\n description: 'A brief description of the content for X (formerly Twitter).',\n },\n twitterImageType: {\n title: 'X Image Type',\n description:\n 'Choose whether to upload an image or provide an image URL for X (formerly Twitter).',\n },\n twitterImage: {\n title: 'X Image',\n description:\n 'An image URL which should be at least 120x120px for \"summary\" card and 280x150px for \"summary_large_image\" card.',\n },\n twitterImageUrl: {\n title: 'X Image URL',\n description:\n 'Enter the full URL of the image for X (formerly Twitter). Ensure the image is accessible and meets the recommended size.',\n },\n}\n\nexport const getFieldInfo = (\n fieldName: string,\n fieldOverrides: SeoFieldsPluginConfig['fieldOverrides'],\n): {title: string; description: string} => {\n const fieldInfo =\n (fieldOverrides && fieldOverrides[fieldName as keyof typeof fieldOverrides]) ||\n DEFAULT_FIELD_INFO[fieldName as keyof typeof DEFAULT_FIELD_INFO]\n return fieldInfo\n ? {title: fieldInfo.title || '', description: fieldInfo.description || ''}\n : {title: '', description: ''}\n}\n\n/**\n * Check if a field should be hidden based on the current document type\n */\nexport const isFieldHidden = (\n fieldName: ValidHiddenFieldKeys,\n config: SeoFieldsPluginConfig,\n documentType?: string,\n): boolean => {\n // Check if field is in default hidden fields\n if (config.defaultHiddenFields?.includes(fieldName)) {\n return true\n }\n\n // Check if field is hidden for specific post type\n if (documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)) {\n return true\n }\n\n return false\n}\n\n/**\n * Get the hidden function for any field\n */\nexport const getFieldHiddenFunction = (\n fieldName: ValidHiddenFieldKeys,\n config: SeoFieldsPluginConfig,\n) => {\n return ({\n document,\n }: {\n document?: {\n _type?: string\n }\n }): boolean => {\n const documentType = document?._type\n return isFieldHidden(fieldName, config, documentType)\n }\n}\n","export const isEmpty = (value: unknown): boolean => {\n return (\n value === null ||\n value === undefined ||\n (typeof value === 'string' && value.trim() === '') ||\n (Array.isArray(value) && value.length === 0) ||\n (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0)\n )\n}\n","import {defineField, defineType, SchemaTypeDefinition} from 'sanity'\n\nimport OgDescription from '../../../components/openGraph/OgDescription'\nimport OgImage from '../../../components/openGraph/OgImage'\nimport OgImageUrl from '../../../components/openGraph/OgImageUrl'\nimport OgTitle from '../../../components/openGraph/OgTitle'\nimport {SeoFieldsPluginConfig} from '../../../plugin'\nimport {getFieldHiddenFunction, getFieldInfo} from '../../../utils/fieldsUtils'\n\nexport default function openGraph(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition {\n return defineType({\n name: 'openGraph',\n title: 'Open Graph Settings',\n type: 'object',\n fields: [\n defineField({\n name: 'url',\n type: 'url',\n ...getFieldInfo('openGraphUrl', config.fieldOverrides),\n hidden: getFieldHiddenFunction('openGraphUrl', config),\n description:\n 'The canonical URL of the page. This should be the full URL including protocol (https://).',\n }),\n defineField({\n name: 'title',\n ...getFieldInfo('openGraphTitle', config.fieldOverrides),\n type: 'string',\n hidden: getFieldHiddenFunction('openGraphTitle', config),\n components: {\n input: OgTitle, // Can also wrap with a string input + preview\n },\n }),\n defineField({\n name: 'description',\n ...getFieldInfo('openGraphDescription', config.fieldOverrides),\n type: 'text',\n rows: 3,\n hidden: getFieldHiddenFunction('openGraphDescription', config),\n components: {\n input: OgDescription, // Can also wrap with a text area + preview\n },\n }),\n defineField({\n name: 'siteName',\n ...getFieldInfo('openGraphSiteName', config.fieldOverrides),\n type: 'string',\n hidden: getFieldHiddenFunction('openGraphSiteName', config),\n }),\n defineField({\n name: 'type',\n ...getFieldInfo('openGraphType', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Website', value: 'website'},\n {title: 'Article', value: 'article'},\n {title: 'Profile', value: 'profile'},\n {title: 'Book', value: 'book'},\n {title: 'Music', value: 'music'},\n {title: 'Video', value: 'video'},\n {title: 'Product', value: 'product'},\n ],\n // layout: 'radio', // Display as radio buttons\n },\n hidden: getFieldHiddenFunction('openGraphType', config),\n initialValue: 'website',\n }),\n defineField({\n name: 'imageType',\n ...getFieldInfo('openGraphImageType', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Upload Image', value: 'upload'},\n {title: 'Image URL', value: 'url'},\n ],\n },\n hidden: getFieldHiddenFunction('openGraphImage', config),\n initialValue: 'upload',\n }),\n defineField({\n name: 'image',\n ...getFieldInfo('openGraphImage', config.fieldOverrides),\n type: 'image',\n options: {\n hotspot: true,\n },\n components: {\n input: OgImage,\n },\n fields: [\n defineField({\n name: 'alt',\n title: 'Image Alt Text',\n type: 'string',\n description: 'A description of the image for accessibility purposes.',\n }),\n ],\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'upload') return true\n const hiddenFn = getFieldHiddenFunction('openGraphImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n defineField({\n name: 'imageUrl',\n ...getFieldInfo('openGraphImageUrl', config.fieldOverrides),\n type: 'url',\n components: {\n input: OgImageUrl,\n },\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'url') return true\n const hiddenFn = getFieldHiddenFunction('openGraphImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n ],\n })\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgDescriptionValidation} from '../../utils/seoUtils'\n\nconst OgDescription = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getOgDescriptionValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n {/* Validation */}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgDescription\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {ObjectInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgImageValidation} from '../../utils/seoUtils'\n\nconst OgImage = (props: ObjectInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n const imgValue = value as Record<string, unknown> | undefined\n const hasImage = !!imgValue?.asset\n const altText = imgValue?.alt as string | undefined\n\n const feedbackItems = useMemo(\n () => getOgImageValidation(hasImage, altText, seoParent),\n [hasImage, altText, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgImage\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgImageUrlValidation} from '../../utils/seoUtils'\n\nconst OgImageUrl = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n\n const feedbackItems = useMemo(\n () => getOgImageUrlValidation(value, seoParent),\n [value, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgImageUrl\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgTitleValidation} from '../../utils/seoUtils'\n\nconst OgTitle: React.FC<StringInputProps> = (props) => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getOgTitleValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgTitle\n","import {defineField, defineType, SchemaTypeDefinition} from 'sanity'\n\nimport TwitterDescription from '../../../components/twitter/twitterDescription'\nimport TwitterImage from '../../../components/twitter/TwitterImage'\nimport TwitterImageUrl from '../../../components/twitter/TwitterImageUrl'\nimport TwitterTitle from '../../../components/twitter/twitterTitle'\nimport {SeoFieldsPluginConfig} from '../../../plugin'\nimport {getFieldHiddenFunction, getFieldInfo} from '../../../utils/fieldsUtils'\n\nexport default function twitter(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition {\n return defineType({\n name: 'twitter',\n title: 'X (Formerly Twitter)',\n type: 'object',\n fields: [\n defineField({\n name: 'card',\n ...getFieldInfo('twitterCard', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Summary', value: 'summary'},\n {title: 'Summary with Large Image', value: 'summary_large_image'},\n {title: 'App', value: 'app'},\n {title: 'Player', value: 'player'},\n ],\n },\n hidden: getFieldHiddenFunction('twitterCard', config),\n initialValue: 'summary_large_image', // good default\n }),\n defineField({\n name: 'site',\n ...getFieldInfo('twitterSite', config.fieldOverrides),\n type: 'string',\n hidden: getFieldHiddenFunction('twitterSite', config),\n }),\n defineField({\n name: 'creator',\n type: 'string',\n ...getFieldInfo('twitterCreator', config.fieldOverrides),\n hidden: getFieldHiddenFunction('twitterCreator', config),\n }),\n defineField({\n name: 'title',\n type: 'string',\n ...getFieldInfo('twitterTitle', config.fieldOverrides),\n hidden: getFieldHiddenFunction('twitterTitle', config),\n components: {\n input: TwitterTitle,\n },\n }),\n defineField({\n name: 'description',\n type: 'text',\n rows: 3,\n ...getFieldInfo('twitterDescription', config.fieldOverrides),\n hidden: getFieldHiddenFunction('twitterDescription', config),\n components: {\n input: TwitterDescription,\n },\n }),\n defineField({\n name: 'imageType',\n ...getFieldInfo('twitterImageType', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Upload Image', value: 'upload'},\n {title: 'Image URL', value: 'url'},\n ],\n },\n hidden: getFieldHiddenFunction('twitterImage', config),\n initialValue: 'upload',\n }),\n defineField({\n name: 'image',\n ...getFieldInfo('twitterImage', config.fieldOverrides),\n type: 'image',\n options: {\n hotspot: true,\n },\n components: {\n input: TwitterImage,\n },\n fields: [\n defineField({\n name: 'alt',\n title: 'Image Alt Text',\n type: 'string',\n description: 'A description of the image for accessibility purposes.',\n }),\n ],\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'upload') return true\n const hiddenFn = getFieldHiddenFunction('twitterImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n defineField({\n name: 'imageUrl',\n ...getFieldInfo('twitterImageUrl', config.fieldOverrides),\n type: 'url',\n components: {\n input: TwitterImageUrl,\n },\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'url') return true\n const hiddenFn = getFieldHiddenFunction('twitterImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n ],\n })\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterDescriptionValidation} from '../../utils/seoUtils'\n\nconst TwitterDescription = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getTwitterDescriptionValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterDescription\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {ObjectInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterImageValidation} from '../../utils/seoUtils'\n\nconst TwitterImage = (props: ObjectInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n const imgValue = value as Record<string, unknown> | undefined\n const hasImage = !!imgValue?.asset\n const altText = imgValue?.alt as string | undefined\n\n const feedbackItems = useMemo(\n () => getTwitterImageValidation(hasImage, altText, seoParent),\n [hasImage, altText, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterImage\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterImageUrlValidation} from '../../utils/seoUtils'\n\nconst TwitterImageUrl = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n\n const feedbackItems = useMemo(\n () => getTwitterImageUrlValidation(value, seoParent),\n [value, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterImageUrl\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterTitleValidation} from '../../utils/seoUtils'\n\nconst TwitterTitle = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getTwitterTitleValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterTitle\n","import {defineField, defineType} from 'sanity'\n\nexport default defineType({\n name: 'metaAttribute',\n title: 'Meta Attribute',\n type: 'object',\n fields: [\n defineField({\n name: 'key',\n title: 'Attribute Name',\n type: 'string',\n }),\n defineField({\n name: 'type',\n title: 'Attribute Value Type',\n type: 'string',\n options: {\n list: [\n {title: 'String', value: 'string'},\n {title: 'Image', value: 'image'},\n ],\n },\n initialValue: 'string',\n }),\n defineField({\n name: 'value',\n title: 'Attribute Value',\n type: 'string',\n hidden: ({parent}) => parent?.type === 'image',\n }),\n defineField({\n name: 'image',\n title: 'Attribute Image Value',\n type: 'image',\n hidden: ({parent}) => parent?.type === 'string',\n }),\n ],\n preview: {\n select: {\n attributeName: 'key',\n attributeValueString: 'value',\n attributeValueImage: 'image',\n },\n prepare({attributeName, attributeValueString, attributeValueImage}) {\n let subtitle = ''\n if (attributeValueString) {\n subtitle = `Value: ${attributeValueString}`\n } else if (attributeValueImage) {\n subtitle = 'Value: [Image]'\n } else {\n subtitle = 'No Attribute Value'\n }\n return {\n title: attributeName || 'No Attribute Name',\n subtitle: subtitle,\n media: attributeValueImage,\n }\n },\n },\n})\n","import {defineType} from 'sanity'\n\nexport default defineType({\n name: 'metaTag',\n title: 'Meta Tag',\n type: 'object',\n fields: [\n {\n name: 'metaAttributes',\n title: 'Meta Attributes',\n type: 'array',\n of: [{type: 'metaAttribute'}],\n description:\n 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',\n },\n ],\n})\n","import {defineField, defineType} from 'sanity'\n\nexport default defineType({\n name: 'robots',\n title: 'Robots Settings',\n type: 'object',\n fields: [\n defineField({\n name: 'noIndex',\n title: 'No Index',\n type: 'boolean',\n initialValue: false,\n description:\n 'Enable this to prevent search engines from indexing this page. The page will not appear in search results.',\n }),\n defineField({\n name: 'noFollow',\n title: 'No Follow',\n type: 'boolean',\n initialValue: false,\n description:\n 'Enable this to prevent search engines from following links on this page. Links will not pass SEO value.',\n }),\n ],\n description: 'Select how search engines should index and follow links on this page.',\n})\n","import {SchemaTypeDefinition} from 'sanity'\n\nimport {SeoFieldsPluginConfig} from '../../plugin'\nimport seoFields from '..'\nimport metaAttribute from './metaAttribute'\nimport metaTag from './metaTag'\nimport openGraph from './openGraph'\nimport robots from './robots'\nimport twitter from './twitter'\n\nexport default function types(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition[] {\n return [\n seoFields(config), // pass config here\n openGraph(config), // pass config here\n twitter(config), // pass config here\n metaAttribute as SchemaTypeDefinition,\n metaTag,\n robots,\n ]\n}\n","import React from 'react'\nimport type {ComponentBuilder, StructureBuilder} from 'sanity/structure'\n\nimport SeoHealthDashboard, {SeoHealthDashboardProps} from './SeoHealthDashboard'\n\n/**\n * Options accepted by `createSeoHealthPane`.\n * All props from `SeoHealthDashboardProps` are supported.\n *\n * `licenseKey` is **required** — the dashboard will not render without it.\n */\nexport interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuery'> {\n /** Required license key (format: `SEOF-XXXX-XXXX-XXXX`). */\n licenseKey: string\n /**\n * A fully custom GROQ query used to fetch documents for the dashboard.\n * The query must return documents with at least: `_id`, `_type`, `title`, `seo`, `_updatedAt`.\n *\n * Takes precedence over `queryTypes` when both are provided.\n *\n * @example\n * query: `*[_type in [\"post\",\"page\"] && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`\n */\n query?: string\n}\n\n// function isStructureBuilder(arg: unknown): arg is StructureBuilder {\n// return (\n// arg !== null &&\n// typeof arg === 'object' &&\n// typeof (arg as StructureBuilder).component === 'function' &&\n// typeof (arg as StructureBuilder).document === 'function'\n// )\n// }\n\n/**\n * Creates a desk-structure pane for the SEO Health Dashboard.\n *\n * Returns a **`ComponentBuilder`** with a built-in `.child()` resolver so that\n * clicking any document row opens the document editor as a split pane to the right.\n *\n * Use it **directly** as the `.child()` value — do **not** wrap it in `S.component()`.\n *\n * ```ts\n * // sanity.config.ts\n * structure: (S) =>\n * S.list().items([\n * S.listItem()\n * .title('SEO Health')\n * .child(\n * createSeoHealthPane(S, {\n * licenseKey: 'SEOF-XXXX-XXXX-XXXX',\n * query: `*[_type == \"post\" && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`,\n * })\n * ),\n * ])\n * ```\n */\nexport function createSeoHealthPane(\n optionsOrS: StructureBuilder,\n optionsWhenS: SeoHealthPaneOptions,\n): ComponentBuilder {\n // ── Two-arg form: structure builder passed as first arg ──────────────────\n const S = optionsOrS\n const {query, openInPane = true, title: paneTitle, ...rest} = optionsWhenS ?? {}\n\n const SeoHealthPane: React.FC = () => (\n <SeoHealthDashboard customQuery={query} openInPane={openInPane} title={paneTitle} {...rest} />\n )\n SeoHealthPane.displayName = 'SeoHealthPane'\n\n // Wire up the child resolver so ChildLink URLs resolve to the document editor\n return (S.component(SeoHealthPane) as ComponentBuilder)\n .title(paneTitle ?? 'SEO Health')\n .child((docId: string, {params}: {params: Record<string, string | undefined>}) => {\n const builder = S.document().documentId(docId)\n return params?.type ? builder.schemaType(params.type) : builder\n })\n}\n\nexport default createSeoHealthPane\n","// Import the plugin\nimport seofields from './plugin'\n\n// Default export the plugin\nexport default seofields\n\n// Re-export everything from plugin.ts\nexport * from './plugin'\n\n// Export schema types for external use\nexport {default as seoFieldsSchema} from './schemas'\nexport {default as allSchemas} from './schemas/types'\nexport {default as metaAttributeSchema} from './schemas/types/metaAttribute'\nexport {default as metaTagSchema} from './schemas/types/metaTag'\nexport {default as openGraphSchema} from './schemas/types/openGraph'\nexport {default as robotsSchema} from './schemas/types/robots'\nexport {default as twitterSchema} from './schemas/types/twitter'\n\n// Export dashboard components and types\nexport {default as SeoHealthDashboard} from './components/SeoHealthDashboard'\nexport type {SeoHealthPaneOptions} from './components/SeoHealthPane'\nexport {createSeoHealthPane} from './components/SeoHealthPane'\nexport {default as SeoHealthTool} from './components/SeoHealthTool'\n\n// Export types\nexport type {DocumentWithSeoHealth, SeoHealthMetrics, SeoHealthStatus} from './types'\n"],"mappings":"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","names":["React","openGraph","twitter","types","jsx","defineField","defineType","useMemo","jsx","jsxs","useMemo","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","useFormValue","styled","jsx","jsxs","styled","useFormValue","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","defineField","defineType","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","defineType","defineField","defineType","defineField","defineField","defineType","defineType","defineField","defineType","React","jsx"]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/components/SeoHealthDashboard.tsx","../src/components/SeoHealthTool.tsx","../src/schemas/index.ts","../src/components/meta/MetaDescription.tsx","../src/utils/seoUtils.ts","../src/components/meta/MetaImage.tsx","../src/components/meta/MetaTitle.tsx","../src/components/SeoPreview.tsx","../src/utils/fieldsUtils.ts","../src/utils/utils.ts","../src/schemas/types/openGraph/index.ts","../src/components/openGraph/OgDescription.tsx","../src/components/openGraph/OgImage.tsx","../src/components/openGraph/OgImageUrl.tsx","../src/components/openGraph/OgTitle.tsx","../src/schemas/types/twitter/index.ts","../src/components/twitter/twitterDescription.tsx","../src/components/twitter/TwitterImage.tsx","../src/components/twitter/TwitterImageUrl.tsx","../src/components/twitter/twitterTitle.tsx","../src/schemas/types/metaAttribute/index.ts","../src/schemas/types/metaTag/index.ts","../src/schemas/types/robots/index.ts","../src/schemas/types/index.ts","../src/components/SeoHealthPane.tsx","../src/index.ts"],"sourcesContent":["// plugin.ts\nimport React from 'react'\nimport {definePlugin} from 'sanity'\n\nimport SeoHealthTool from './components/SeoHealthTool'\nimport types from './schemas/types'\nimport type {DeprecationWarning, DocumentWithSeoHealth} from './types'\n\nexport interface SeoFieldConfig {\n title?: string\n description?: string\n}\n\nexport type SeoFieldKeys =\n | 'title'\n | 'description'\n | 'canonicalUrl'\n | 'metaImage'\n | 'keywords'\n | 'metaAttributes'\n | 'robots'\n\nexport type openGraphFieldKeys =\n | 'openGraphUrl'\n | 'openGraphTitle'\n | 'openGraphDescription'\n | 'openGraphSiteName'\n | 'openGraphType'\n | 'openGraphImageType'\n | 'openGraphImage'\n | 'openGraphImageUrl'\n\nexport type twitterFieldKeys =\n | 'twitterCard'\n | 'twitterSite'\n | 'twitterCreator'\n | 'twitterTitle'\n | 'twitterDescription'\n | 'twitterImageType'\n | 'twitterImage'\n | 'twitterImageUrl'\n\nexport type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys\n\nexport type ValidHiddenFieldKeys = Exclude<\n AllFieldKeys,\n 'openGraphImageUrl' | 'twitterImageUrl' | 'openGraphImageType' | 'twitterImageType'\n>\n\nexport interface FieldVisibilityConfig {\n hiddenFields?: ValidHiddenFieldKeys[]\n}\n\nexport interface SeoFieldsPluginConfig {\n /**\n * Enable or configure the SEO preview feature.\n * If set to `true`, the SEO preview will be enabled with default settings.\n * If set to an object, you can provide a custom prefix function to modify the URL prefix in the preview.\n * The prefix function receives the current document as an argument and should return a string.\n * Example:\n * ```\n * seoPreview: {\n * prefix: (doc) => `/${doc.slug?.current || 'untitled'}`\n * }\n * ```\n */\n seoPreview?:\n | boolean\n | {\n prefix?: (doc: {_type?: string} & Record<string, unknown>) => string\n }\n\n /**\n * A mapping of field keys to their configuration settings.\n * This allows customization of field titles and descriptions.\n * For example, to change the title of the 'title' field:\n */\n fieldOverrides?: Partial<Record<AllFieldKeys, SeoFieldConfig>>\n /**\n * A mapping of document types to field visibility configurations.\n * This allows you to specify which fields should be hidden for specific document types.\n */\n fieldVisibility?: Record<string, FieldVisibilityConfig>\n\n /**\n * A list of fields that should be hidden by default in all document types.\n * This can be overridden by specific document type settings in `fieldVisibility`.\n */\n defaultHiddenFields?: ValidHiddenFieldKeys[]\n /**\n * The base URL of your website, used for generating full URLs in the SEO preview.\n * Defaults to 'https://www.example.com' if not provided.\n */\n baseUrl?: string\n /**\n * Enable or configure the SEO Health Dashboard tool.\n * If set to `true`, the dashboard is enabled with all defaults.\n * If set to an object, you can customise the tool and dashboard settings.\n * Defaults to `true`.\n * Example:\n * ```\n * healthDashboard: {\n * toolTitle: 'SEO Overview', // Studio nav tab label\n * content: {\n * icon: '🔍', // Emoji icon shown before the page heading\n * title: 'My SEO Dashboard',// Page heading inside the tool (no emoji)\n * description: 'Track SEO across all documents', // Subtitle under the heading\n * },\n * display: {\n * typeColumn: false, // Hide the document type column (default: true)\n * documentId: false, // Hide the document ID under titles (default: true)\n * },\n * query: {\n * // Option 1 – filter by specific document types\n * types: ['post', 'page'],\n * // Option 2 – provide a full custom GROQ query (takes precedence over `types`)\n * // Must return documents with at least: _id, _type, title, seo, _updatedAt\n * groq: `*[seo != null && defined(slug.current)]{ _id, _type, title, slug, seo, _updatedAt }`,\n * },\n * }\n * ```\n */\n healthDashboard?:\n | boolean\n | {\n tool?: {\n title?: string\n name?: string\n }\n toolTitle?: string\n content?: {\n icon?: string\n title?: string\n description?: string\n /** Text shown while the license key is being verified. Defaults to \"Verifying license…\" */\n loadingLicense?: string\n /** Text shown while documents are being fetched. Defaults to \"Loading documents…\" */\n loadingDocuments?: string\n /** Text shown when the query returns zero results. Defaults to \"No documents found\" */\n noDocuments?: string\n }\n /**\n * @deprecated Use `showTypeColumn` instead. Will be removed in a future major version.\n * @see https://github.com/hardik-143/sanity-plugin-seofields/blob/main/CHANGELOG.md#132--2026-03-23\n */\n display?: {\n /** @deprecated Use top-level `showTypeColumn` instead. */\n typeColumn?: boolean\n /** @deprecated Use top-level `showDocumentId` instead. */\n documentId?: boolean\n }\n /**\n * Show or hide the document type column in the results table.\n * Replaces the deprecated `display.typeColumn`.\n * Defaults to `true`.\n */\n showTypeColumn?: boolean\n /**\n * Show or hide the Sanity document `_id` under each title.\n * Replaces the deprecated `display.documentId`.\n * Defaults to `true`.\n */\n showDocumentId?: boolean\n query?: {\n /**\n * Limit the dashboard to specific document types.\n * Example: `['post', 'page']`\n */\n types?: string[]\n /**\n * When using `types`, also require the `seo` field to be non-null.\n * Set to `false` to include documents of those types even if `seo` is missing.\n * Defaults to `true`.\n */\n requireSeo?: boolean\n /**\n * Provide a fully custom GROQ query. Takes precedence over `types`.\n * The query must return documents with at least: _id, _type, title, seo, _updatedAt\n */\n groq?: string\n }\n /**\n * The Sanity API version to use for the client (e.g. '2023-01-01').\n * Defaults to '2023-01-01'.\n */\n apiVersion?: string\n /**\n * License key for the SEO Health Dashboard pro feature.\n * Obtain a license at https://sanity-plugin-seofields.thehardik.in\n */\n licenseKey?: string\n /**\n * Map raw `_type` values to human-readable display labels.\n * Used in both the Type column and the Type filter dropdown.\n * Any type without an entry falls back to the raw `_type` string.\n *\n * @deprecated Use `typeDisplayLabels` instead. Will be removed in a future major version.\n * @see https://github.com/hardik-143/sanity-plugin-seofields/blob/main/CHANGELOG.md#132--2026-03-23\n *\n * @example\n * typeLabels: { productDrug: 'Products', singleCondition: 'Condition' }\n */\n typeLabels?: Record<string, string>\n /**\n * Map raw `_type` values to human-readable display labels.\n * Replaces the deprecated `typeLabels`.\n * Used in both the Type column and the Type filter dropdown.\n * Any type without an entry falls back to the raw `_type` string.\n *\n * @example\n * typeDisplayLabels: { productDrug: 'Products', singleCondition: 'Condition' }\n */\n typeDisplayLabels?: Record<string, string>\n /**\n * Controls how the document type is rendered in the Type column.\n * - `'badge'` (default) — coloured pill\n * - `'text'` — plain text, useful for dense layouts\n */\n typeColumnMode?: 'badge' | 'text'\n /**\n * The document field to use as the display title in the dashboard.\n *\n * - `string` — use this field for every document type (e.g. `'name'`)\n * - `Record<string, string>` — per-type mapping; unmapped types fall back to `title`\n *\n * @example\n * titleField: 'name'\n *\n * @example\n * titleField: { post: 'title', product: 'name', category: 'label' }\n */\n titleField?: string | Record<string, string>\n /**\n * Callback function to render a custom badge next to the document title.\n * Receives the full document and should return badge data or undefined.\n *\n * @deprecated Use `getDocumentBadge` instead. Will be removed in a future major version.\n * @see https://github.com/hardik-143/sanity-plugin-seofields/blob/main/CHANGELOG.md#132--2026-03-23\n *\n * @example\n * docBadge: (doc) => {\n * if (doc.services === 'NHS')\n * return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }\n * }\n */\n docBadge?: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n /**\n * Callback function to render a custom badge next to the document title.\n * Replaces the deprecated `docBadge`.\n * Receives the full document and should return badge data or undefined.\n *\n * @example\n * getDocumentBadge: (doc) => {\n * if (doc.services === 'NHS')\n * return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }\n * if (doc.services === 'Private')\n * return { label: 'Private', bgColor: '#fef3c7', textColor: '#92400e' }\n * }\n */\n getDocumentBadge?: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n /**\n * The `name` of the Sanity structure tool that contains the monitored documents.\n * Required when you have multiple structure tools and the documents live in a\n * non-default one. Clicking a title will navigate to\n * `/{basePath}/{structureTool}/intent/edit/…` directly.\n *\n * @example\n * structureTool: 'common'\n */\n structureTool?: string\n /**\n * Enable preview/demo mode to show dummy data.\n * Useful for testing, documentation, or showcasing the dashboard.\n * When enabled, displays realistic sample documents with various SEO scores.\n * Defaults to `false`.\n *\n * @example\n * previewMode: true\n */\n previewMode?: boolean\n }\n}\n\nconst V132 = 'v1.3.2'\nconst CHANGELOG_V132 = `https://github.com/hardik-143/sanity-plugin-seofields/blob/main/CHANGELOG.md#132--2026-03-23`\n\ninterface ResolvedDashboardConfig {\n enabled: boolean\n toolTitle: string\n toolName: string\n icon: string | undefined\n title: string | undefined\n description: string | undefined\n showTypeColumn: boolean | undefined\n showDocumentId: boolean | undefined\n queryTypes: string[] | undefined\n queryRequireSeo: boolean | undefined\n queryGroq: string | undefined\n apiVersion: string | undefined\n licenseKey: string | undefined\n typeDisplayLabels: Record<string, string> | undefined\n typeColumnMode: 'badge' | 'text' | undefined\n titleField: string | Record<string, string> | undefined\n getDocumentBadge:\n | ((\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined)\n | undefined\n loadingLicense: string | undefined\n loadingDocuments: string | undefined\n noDocuments: string | undefined\n previewMode: boolean | undefined\n structureTool: string | undefined\n /** @internal — deprecated keys detected at config-resolution time, forwarded to the UI banner */\n deprecationWarnings: DeprecationWarning[]\n}\n\nconst resolveDashboardConfig = (\n healthDashboard: SeoFieldsPluginConfig['healthDashboard'],\n): ResolvedDashboardConfig => {\n const cfg = typeof healthDashboard === 'object' ? healthDashboard : undefined\n // Detect deprecated plugin-level keys and emit console warnings with guidance on updating to the new config structure. Warnings are collected in an array and also passed to the dashboard component for display in a banner.\n const deprecationWarnings: DeprecationWarning[] = []\n\n if (cfg?.display?.typeColumn !== undefined) {\n deprecationWarnings.push({\n key: 'display.typeColumn → showTypeColumn',\n version: V132,\n changelogUrl: CHANGELOG_V132,\n })\n if (cfg.showTypeColumn) {\n console.warn(\n `[sanity-plugin-seofields] Both \"healthDashboard.display.typeColumn\" and \"healthDashboard.showTypeColumn\" are set. \"showTypeColumn\" will take precedence. Please remove \"healthDashboard.display.typeColumn\". See ${CHANGELOG_V132}`,\n )\n } else {\n console.warn(\n `[sanity-plugin-seofields] \"healthDashboard.display.typeColumn\" is deprecated. Use \"healthDashboard.showTypeColumn\" instead. See ${CHANGELOG_V132}`,\n )\n }\n }\n if (cfg?.display?.documentId !== undefined) {\n deprecationWarnings.push({\n key: 'display.documentId → showDocumentId',\n version: V132,\n changelogUrl: CHANGELOG_V132,\n })\n if (cfg.showDocumentId) {\n console.warn(\n `[sanity-plugin-seofields] Both \"healthDashboard.display.documentId\" and \"healthDashboard.showDocumentId\" are set. \"showDocumentId\" will take precedence. Please remove \"healthDashboard.display.documentId\". See ${CHANGELOG_V132}`,\n )\n } else {\n console.warn(\n `[sanity-plugin-seofields] \"healthDashboard.display.documentId\" is deprecated. Use \"healthDashboard.showDocumentId\" instead. See ${CHANGELOG_V132}`,\n )\n }\n }\n if (cfg?.typeLabels) {\n deprecationWarnings.push({\n key: 'typeLabels → typeDisplayLabels',\n version: V132,\n changelogUrl: CHANGELOG_V132,\n })\n if (cfg.typeDisplayLabels) {\n console.warn(\n `[sanity-plugin-seofields] Both \"healthDashboard.typeLabels\" and \"healthDashboard.typeDisplayLabels\" are set. \"typeDisplayLabels\" will take precedence. Please remove \"typeLabels\". See ${CHANGELOG_V132}`,\n )\n } else {\n console.warn(\n `[sanity-plugin-seofields] \"healthDashboard.typeLabels\" is deprecated. Use \"healthDashboard.typeDisplayLabels\" instead. See ${CHANGELOG_V132}`,\n )\n }\n }\n if (cfg?.docBadge) {\n deprecationWarnings.push({\n key: 'docBadge → getDocumentBadge',\n version: V132,\n changelogUrl: CHANGELOG_V132,\n })\n if (cfg?.getDocumentBadge) {\n console.warn(\n `[sanity-plugin-seofields] Both \"healthDashboard.docBadge\" and \"healthDashboard.getDocumentBadge\" are set. \"getDocumentBadge\" will take precedence. Please remove \"docBadge\". See ${CHANGELOG_V132}`,\n )\n } else {\n console.warn(\n `[sanity-plugin-seofields] \"healthDashboard.docBadge\" is deprecated. Use \"healthDashboard.getDocumentBadge\" instead. See ${CHANGELOG_V132}`,\n )\n }\n }\n\n return {\n enabled: healthDashboard !== false,\n toolTitle: cfg?.tool?.title ?? 'SEO Health',\n toolName: cfg?.tool?.name ?? 'seo-health-dashboard',\n icon: cfg?.content?.icon,\n title: cfg?.content?.title,\n description: cfg?.content?.description,\n // New flat keys take precedence; fall back to deprecated display.* for backwards compat\n showTypeColumn: cfg?.showTypeColumn ?? cfg?.display?.typeColumn,\n showDocumentId: cfg?.showDocumentId ?? cfg?.display?.documentId,\n queryTypes: cfg?.query?.types,\n queryRequireSeo: cfg?.query?.requireSeo,\n queryGroq: cfg?.query?.groq,\n apiVersion: cfg?.apiVersion,\n licenseKey: cfg?.licenseKey,\n // New key takes precedence; fall back to deprecated key for backwards compat\n typeDisplayLabels: cfg?.typeDisplayLabels ?? cfg?.typeLabels,\n typeColumnMode: cfg?.typeColumnMode,\n titleField: cfg?.titleField,\n // New key takes precedence; fall back to deprecated key for backwards compat\n getDocumentBadge: cfg?.getDocumentBadge ?? cfg?.docBadge,\n loadingLicense: cfg?.content?.loadingLicense,\n loadingDocuments: cfg?.content?.loadingDocuments,\n noDocuments: cfg?.content?.noDocuments,\n previewMode: cfg?.previewMode,\n structureTool: cfg?.structureTool,\n deprecationWarnings,\n }\n}\n\nconst seofields = definePlugin<SeoFieldsPluginConfig | void>((config = {}) => {\n const {healthDashboard = true} = config as SeoFieldsPluginConfig\n const dash = resolveDashboardConfig(healthDashboard)\n\n const BoundSeoHealthTool = () =>\n React.createElement(SeoHealthTool, {\n icon: dash.icon,\n title: dash.title,\n description: dash.description,\n showTypeColumn: dash.showTypeColumn,\n showDocumentId: dash.showDocumentId,\n queryTypes: dash.queryTypes,\n queryRequireSeo: dash.queryRequireSeo,\n customQuery: dash.queryGroq,\n apiVersion: dash.apiVersion,\n licenseKey: dash.licenseKey,\n typeDisplayLabels: dash.typeDisplayLabels,\n typeColumnMode: dash.typeColumnMode,\n titleField: dash.titleField,\n getDocumentBadge: dash.getDocumentBadge,\n loadingLicense: dash.loadingLicense,\n loadingDocuments: dash.loadingDocuments,\n noDocuments: dash.noDocuments,\n previewMode: dash.previewMode,\n structureTool: dash.structureTool,\n _deprecationWarnings: dash.deprecationWarnings,\n })\n\n return {\n name: 'sanity-plugin-seofields',\n schema: {\n types: types(config as SeoFieldsPluginConfig),\n },\n ...(dash.enabled && {\n tools: [\n {\n name: dash.toolName,\n title: dash.toolTitle,\n component: BoundSeoHealthTool,\n icon: () => '📊',\n },\n ],\n }),\n }\n})\n\nexport default seofields\n","import React, {useCallback, useEffect, useMemo, useState} from 'react'\nimport {useClient, useWorkspace} from 'sanity'\nimport {useIntentLink} from 'sanity/router'\nimport {usePaneRouter} from 'sanity/structure'\nimport styled, {css, keyframes} from 'styled-components'\n\nimport {DeprecationWarning, DocumentWithSeoHealth, SeoHealthMetrics} from '../types'\n\nconst DashboardContainer = styled.div`\n width: 100%;\n min-height: 100%;\n background: #f0f2f5;\n padding: 28px 32px;\n box-sizing: border-box;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n`\n\nconst PageHeader = styled.div`\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 28px;\n`\n\nconst PageTitle = styled.h1`\n margin: 0 0 6px 0;\n font-size: 22px;\n font-weight: 700;\n color: #111827;\n letter-spacing: -0.3px;\n display: flex;\n align-items: center;\n gap: 10px;\n`\n\nconst PreviewBadge = styled.span`\n display: inline-block;\n background: #fef3c7;\n color: #92400e;\n font-size: 11px;\n font-weight: 600;\n padding: 4px 8px;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-left: 8px;\n`\n\nconst PageSubtitle = styled.p`\n margin: 0;\n font-size: 13px;\n color: #6b7280;\n`\n\nconst StatsGrid = styled.div`\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));\n gap: 14px;\n margin-bottom: 20px;\n`\n\nconst StatCard = styled.div<{$accent?: string}>`\n background: #ffffff;\n border-radius: 10px;\n padding: 16px 18px;\n box-shadow:\n 0 1px 3px rgba(0, 0, 0, 0.07),\n 0 1px 2px rgba(0, 0, 0, 0.05);\n border-left: ${(p) => (p.$accent ? `4px solid ${p.$accent}` : '4px solid transparent')};\n transition: box-shadow 0.15s ease;\n\n &:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n }\n`\n\nconst StatLabel = styled.div`\n font-size: 11px;\n font-weight: 500;\n color: #9ca3af;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n`\n\nconst StatValue = styled.div`\n font-size: 26px;\n font-weight: 700;\n color: #111827;\n line-height: 1;\n`\n\nconst ControlsBar = styled.div`\n background: #ffffff;\n border-radius: 10px;\n padding: 14px 18px;\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n margin-bottom: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);\n`\n\nconst SearchWrapper = styled.div`\n position: relative;\n flex: 1;\n min-width: 220px;\n`\n\nconst SearchIconSvg = styled.span`\n position: absolute;\n left: 11px;\n top: 50%;\n transform: translateY(-50%);\n color: #9ca3af;\n display: flex;\n align-items: center;\n pointer-events: none;\n`\n\nconst SearchInput = styled.input`\n width: 100%;\n height: 36px;\n padding: 0 12px 0 34px;\n border: 1px solid #e5e7eb;\n border-radius: 7px;\n font-size: 13px;\n color: #111827;\n background: #f9fafb;\n box-sizing: border-box;\n outline: none;\n transition:\n border-color 0.15s,\n background 0.15s;\n\n &::placeholder {\n color: #9ca3af;\n }\n\n &:focus {\n border-color: #6366f1;\n background: #fff;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n`\n\nconst StyledSelect = styled.select`\n height: 36px;\n padding: 0 32px 0 12px;\n border: 1px solid #e5e7eb;\n border-radius: 7px;\n font-size: 13px;\n color: #374151;\n background: #f9fafb\n url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E\")\n no-repeat right 10px center;\n appearance: none;\n outline: none;\n cursor: pointer;\n transition: border-color 0.15s;\n\n &:focus {\n border-color: #6366f1;\n background-color: #fff;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n`\n\nconst TableCard = styled.div`\n background: #ffffff;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);\n overflow: hidden;\n`\n\nconst TableHeader = styled.div`\n display: flex;\n align-items: center;\n padding: 11px 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n font-size: 11px;\n font-weight: 600;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n gap: 12px;\n`\n\nconst TableRow = styled.div`\n display: flex;\n align-items: center;\n padding: 13px 20px;\n border-bottom: 1px solid #f3f4f6;\n gap: 12px;\n transition: background 0.1s;\n\n &:last-child {\n border-bottom: none;\n }\n\n &:hover {\n background: #fafafa;\n }\n`\n\nconst ColTitle = styled.div`\n flex: 2;\n min-width: 0;\n`\n\nconst TitleWrapper = styled.div`\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n min-width: 0;\n`\n\n/* Constrains the title + doc-id block so text-overflow works inside flex */\nconst TitleCell = styled.div`\n min-width: 0;\n overflow: hidden;\n flex: 1;\n`\n\nconst ColType = styled.div`\n flex: 0.8;\n min-width: 80px;\n`\n\nconst ColScore = styled.div`\n flex: 0.6;\n min-width: 70px;\n`\n\nconst ColIssues = styled.div`\n flex: 2;\n min-width: 0;\n`\n\nconst DocTitleLink = styled.a`\n font-size: 13px;\n font-weight: 600;\n color: #4f46e5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n text-decoration: none;\n display: block;\n transition: color 0.15s;\n\n &:hover {\n color: #4338ca;\n text-decoration: underline;\n }\n`\n\nconst DocId = styled.div`\n font-size: 11px;\n color: #9ca3af;\n margin-top: 2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`\n\nconst TypeBadge = styled.span<{$bgColor?: string; $textColor?: string}>`\n display: inline-block;\n padding: 3px 8px;\n border-radius: 5px;\n font-size: 11px;\n font-weight: 500;\n background: ${(p) => p.$bgColor || '#ede9fe'};\n color: ${(p) => p.$textColor || '#5b21b6'};\n`\n\nconst TypeText = styled.span`\n font-size: 12px;\n font-weight: 500;\n color: #374151;\n`\n\nconst CustomBadge = styled.span<{$bgColor?: string; $textColor?: string; $fontSize?: string}>`\n display: inline-block;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: ${(p) => p.$fontSize || '10px'};\n font-weight: 600;\n background: ${(p) => p.$bgColor || '#e0e7ff'};\n color: ${(p) => p.$textColor || '#3730a3'};\n white-space: nowrap;\n`\n\nconst ScoreBadge = styled.span<{$score: number}>`\n display: inline-block;\n padding: 4px 10px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 700;\n background: ${(p) => {\n if (p.$score >= 80) return '#d1fae5'\n if (p.$score >= 60) return '#fef3c7'\n if (p.$score >= 40) return '#ffedd5'\n return '#fee2e2'\n }};\n color: ${(p) => {\n if (p.$score >= 80) return '#065f46'\n if (p.$score >= 60) return '#92400e'\n if (p.$score >= 40) return '#9a3412'\n return '#991b1b'\n }};\n`\n\nconst IssueTag = styled.div`\n font-size: 11px;\n color: #ef4444;\n line-height: 1.5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`\n\nconst NonStringTitleWarning = styled.div`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 2px 7px;\n border-radius: 4px;\n background: #fef3c7;\n border: 1px solid #fcd34d;\n font-size: 10px;\n font-weight: 600;\n color: #92400e;\n line-height: 1.4;\n cursor: default;\n white-space: normal;\n`\n\nconst MoreIssues = styled.div`\n font-size: 11px;\n color: #6b7280;\n cursor: pointer;\n transition: color 0.15s;\n\n &:hover {\n color: #374151;\n }\n`\n\nconst MoreIssuesWrapper = styled.div`\n position: relative;\n display: inline-block;\n`\n\nconst IssuesPopover = styled.div<{\n $left?: number\n}>`\n position: absolute;\n bottom: auto;\n left: 0;\n transform: translateY(calc(-100% - 14px));\n background: #1f2937;\n color: #ffffff;\n padding: 12px;\n border-radius: 8px;\n font-size: 12px;\n z-index: 50;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);\n width: 280px;\n word-break: break-word;\n line-height: 1.5;\n\n &::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 12px;\n width: 0;\n height: 0;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid #1f2937;\n }\n`\n\nconst PopoverIssueItem = styled.div`\n display: flex;\n gap: 6px;\n margin-bottom: 6px;\n\n &:last-child {\n margin-bottom: 0;\n }\n`\n\nconst UpgradeContainer = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100%;\n padding: 60px 24px;\n`\n\nconst UpgradeBox = styled.div`\n background: #ffffff;\n border-radius: 16px;\n padding: 48px 40px;\n max-width: 480px;\n width: 100%;\n text-align: center;\n box-shadow:\n 0 4px 24px rgba(0, 0, 0, 0.08),\n 0 1px 4px rgba(0, 0, 0, 0.05);\n border: 1px solid #e5e7eb;\n`\n\nconst UpgradeLock = styled.div`\n font-size: 40px;\n margin-bottom: 16px;\n`\n\nconst UpgradeTitle = styled.h2`\n margin: 0 0 10px;\n font-size: 20px;\n font-weight: 700;\n color: #111827;\n`\n\nconst UpgradeText = styled.p`\n margin: 0 0 20px;\n font-size: 14px;\n color: #6b7280;\n line-height: 1.6;\n`\n\nconst UpgradeCode = styled.pre`\n background: #f3f4f6;\n border-radius: 8px;\n padding: 14px 16px;\n font-size: 12px;\n color: #374151;\n text-align: left;\n margin: 0 0 24px;\n overflow-x: auto;\n line-height: 1.6;\n border: 1px solid #e5e7eb;\n`\n\nconst UpgradeButton = styled.a`\n display: inline-block;\n background: #4f46e5;\n color: #ffffff;\n font-size: 14px;\n font-weight: 600;\n padding: 10px 24px;\n border-radius: 8px;\n text-decoration: none;\n transition: background 0.15s;\n\n &:hover {\n background: #4338ca;\n }\n`\n\nconst ReloadButton = styled.button`\n display: inline-block;\n background: transparent;\n color: #6b7280;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 20px;\n border-radius: 8px;\n border: 1px solid #d1d5db;\n cursor: pointer;\n margin-top: 10px;\n transition:\n background 0.15s,\n color 0.15s,\n border-color 0.15s;\n\n &:hover {\n background: #f3f4f6;\n color: #374151;\n border-color: #9ca3af;\n }\n`\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst DashboardRefreshButton = styled.button<{$spinning?: boolean}>`\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: #ffffff;\n color: #374151;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 14px;\n border-radius: 8px;\n border: 1px solid #d1d5db;\n cursor: pointer;\n flex-shrink: 0;\n transition:\n background 0.15s,\n color 0.15s,\n border-color 0.15s,\n box-shadow 0.15s;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n\n svg {\n animation: ${(p) =>\n p.$spinning\n ? css`\n ${spin} 0.7s linear infinite\n `\n : 'none'};\n }\n\n &:hover {\n background: #f3f4f6;\n border-color: #9ca3af;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);\n }\n\n &:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n`\n\n// Sub-component so useIntentLink can be called at the top level of a component (not inside .map)\nconst DocTitleAnchor: React.FC<{\n id: string\n type: string\n structureTool?: string\n children: React.ReactNode\n}> = ({id, type, structureTool, children}) => {\n const {basePath} = useWorkspace()\n const {onClick: intentOnClick, href: intentHref} = useIntentLink({\n intent: 'edit',\n params: {id, type},\n })\n // When a specific structure tool name is provided, build a tool-scoped intent URL so that\n // Sanity routes directly to that tool instead of letting the router pick the first match.\n const href = structureTool\n ? `${basePath}/${structureTool}/intent/edit/id=${id};type=${type}/`\n : intentHref\n const onClick = structureTool ? undefined : intentOnClick\n return (\n <DocTitleLink href={href} onClick={onClick} title=\"Open document\">\n {children}\n </DocTitleLink>\n )\n}\n\n// Wrapper that applies DocTitleLink styles to the ChildLink <a> rendered by Sanity's pane router\nconst PaneLinkWrapper = styled.span`\n display: block;\n min-width: 0;\n overflow: hidden;\n\n a {\n font-size: 13px;\n font-weight: 600;\n color: #4f46e5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n text-decoration: none;\n display: block;\n transition: color 0.15s;\n\n &:hover {\n color: #4338ca;\n text-decoration: underline;\n }\n }\n`\n\n// Sub-component for desk-structure split-pane navigation.\n// Uses ChildLink from usePaneRouter to open the document editor to the right\n// while keeping the SEO Health pane visible on the left.\nconst DocTitleAnchorPane: React.FC<{id: string; type: string; children: React.ReactNode}> = ({\n id,\n type,\n children,\n}) => {\n const {ChildLink} = usePaneRouter()\n return (\n <PaneLinkWrapper>\n <ChildLink childId={id} childParameters={{type}}>\n {children}\n </ChildLink>\n </PaneLinkWrapper>\n )\n}\n\n// Sub-component to safely call docBadge outside a .map expression\nconst DocBadgeRenderer: React.FC<{\n doc: DocumentWithSeoHealth & Record<string, unknown>\n docBadge: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n}> = ({doc, docBadge}) => {\n const badge = docBadge(doc)\n if (!badge) return null\n return (\n <CustomBadge $bgColor={badge.bgColor} $textColor={badge.textColor} $fontSize={badge.fontSize}>\n {badge.label}\n </CustomBadge>\n )\n}\n\nconst Spinner = styled.div`\n width: 28px;\n height: 28px;\n border: 3px solid #e5e7eb;\n border-top-color: #6366f1;\n border-radius: 50%;\n animation: ${spin} 0.7s linear infinite;\n margin: 0 auto 12px;\n`\n\nconst LoadingState = styled.div`\n padding: 48px 24px;\n text-align: center;\n color: #6b7280;\n font-size: 13px;\n`\n\nconst EmptyState = styled.div`\n padding: 48px 24px;\n text-align: center;\n color: #9ca3af;\n font-size: 13px;\n`\n\nconst DeprecationBanner = styled.div`\n background: #fffbeb;\n border: 1px solid #fcd34d;\n border-radius: 8px;\n padding: 10px 14px;\n font-size: 12px;\n color: #78350f;\n margin-bottom: 16px;\n line-height: 1.6;\n`\n\nconst DeprecationBannerLink = styled.a`\n color: #92400e;\n font-weight: 600;\n text-decoration: underline;\n &:hover {\n color: #78350f;\n }\n`\n\n/**\n * Color palette for dynamic document type badges\n * Colors are randomly assigned based on type hash for visual variety\n * while maintaining consistency across sessions\n */\nconst TYPE_COLOR_PALETTE: Array<{bg: string; text: string}> = [\n {bg: '#dbeafe', text: '#0c4a6e'}, // Blue\n {bg: '#dcfce7', text: '#14532d'}, // Green\n {bg: '#fce7f3', text: '#500724'}, // Pink\n {bg: '#fed7aa', text: '#7c2d12'}, // Orange\n {bg: '#e9d5ff', text: '#581c87'}, // Purple\n {bg: '#f3e8ff', text: '#3f0f5c'}, // Deep Purple\n {bg: '#ccfbf1', text: '#134e4a'}, // Teal\n {bg: '#ddd6fe', text: '#3730a3'}, // Indigo\n {bg: '#fca5a5', text: '#7f1d1d'}, // Red\n {bg: '#a7f3d0', text: '#065f46'}, // Emerald\n {bg: '#fbbf24', text: '#78350f'}, // Amber\n {bg: '#c4b5fd', text: '#3b0764'}, // Violet\n {bg: '#f0fdf4', text: '#15803d'}, // Light Green\n {bg: '#fef2f2', text: '#991b1b'}, // Light Red\n {bg: '#f5f3ff', text: '#5b21b6'}, // Light Purple\n {bg: '#fffbeb', text: '#92400e'}, // Light Amber\n]\n\n/**\n * Get dynamic color for a document type based on type name hash\n * Same type always gets the same color, but assignment is not fixed\n */\nconst getTypeColor = (type: string): {bg: string; text: string} => {\n // Generate consistent hash from type string using simple arithmetic\n let hash = 0\n for (let i = 0; i < type.length; i += 1) {\n const char = type.charCodeAt(i)\n hash = Math.abs(hash * 31 + char)\n }\n\n // Use modulo to get index within palette range\n const colorIndex = hash % TYPE_COLOR_PALETTE.length\n return TYPE_COLOR_PALETTE[colorIndex]\n}\n\nconst getStatusCategory = (score: number): SeoHealthMetrics['status'] => {\n if (score >= 80) return 'excellent'\n if (score >= 60) return 'good'\n if (score >= 40) return 'fair'\n if (score > 0) return 'poor'\n return 'missing'\n}\n\nconst scoreMetaTitle = (title?: string): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (title && title.length >= 50 && title.length <= 60) {\n score = 15\n } else if (title && title.length > 0) {\n score = 10\n if (title.length < 50) issues.push('Meta title too short (< 50 chars)')\n if (title.length > 60) issues.push('Meta title too long (> 60 chars)')\n } else {\n issues.push('Missing meta title')\n }\n\n return {score, issues}\n}\n\nconst scoreMetaDescription = (description?: string): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (description && description.length >= 120 && description.length <= 160) {\n score = 15\n } else if (description && description.length > 0) {\n score = 10\n if (description.length < 120) issues.push('Meta description too short (< 120 chars)')\n if (description.length > 160) issues.push('Meta description too long (> 160 chars)')\n } else {\n issues.push('Missing meta description')\n }\n\n return {score, issues}\n}\n\nconst scoreOpenGraph = (openGraph?: Record<string, unknown>): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (openGraph) {\n if (openGraph.title) score += 6\n else issues.push('Missing OG title')\n\n if (openGraph.description) score += 6\n else issues.push('Missing OG description')\n\n if (openGraph.image) score += 6\n else issues.push('Missing OG image')\n\n if (openGraph.type) score += 7\n else issues.push('Missing OG type')\n } else {\n issues.push('Open Graph not configured')\n }\n\n return {score, issues}\n}\n\nconst scoreTwitterCard = (twitter?: Record<string, unknown>): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (twitter) {\n if (twitter.title) score += 5\n else issues.push('Missing Twitter title')\n\n if (twitter.description) score += 5\n else issues.push('Missing Twitter description')\n\n if (twitter.image) score += 5\n else issues.push('Missing Twitter image')\n } else {\n issues.push('Twitter Card not configured')\n }\n\n return {score, issues}\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst calculateHealthScore = (doc: any): SeoHealthMetrics => {\n if (!doc.seo) {\n return {score: 0, status: 'missing', issues: ['SEO fields not configured']}\n }\n\n const {title, description, keywords, robots, canonicalUrl, openGraph, twitter} = doc.seo\n let score = 0\n const issues: string[] = []\n\n const titleResult = scoreMetaTitle(title)\n score += titleResult.score\n issues.push(...titleResult.issues)\n\n const descResult = scoreMetaDescription(description)\n score += descResult.score\n issues.push(...descResult.issues)\n\n // Image\n if (doc.seo.metaImage) score += 10\n else issues.push('Missing meta image')\n\n // Keywords\n if (keywords && keywords.length > 0) score += 10\n else issues.push('No keywords defined')\n\n // Robots\n if (robots && !robots.noIndex) score += 5\n else if (!robots) score += 5\n\n // Canonical URL\n if (canonicalUrl) score += 0 // bonus, not counted in base\n\n const ogResult = scoreOpenGraph(openGraph)\n score += ogResult.score\n issues.push(...ogResult.issues)\n\n const twResult = scoreTwitterCard(twitter)\n score += twResult.score\n issues.push(...twResult.issues)\n\n // Image Completeness bonus (+5 pts when all three images are present)\n const hasMetaImage = !!doc.seo.metaImage\n const hasOgImage = !!(openGraph && openGraph.image)\n const hasTwitterImage = !!(twitter && twitter.image)\n if (hasMetaImage && hasOgImage && hasTwitterImage) {\n score += 5\n } else {\n const missingImages: string[] = []\n if (!hasMetaImage) missingImages.push('meta image')\n if (!hasOgImage) missingImages.push('OG image')\n if (!hasTwitterImage) missingImages.push('Twitter image')\n issues.push(`Missing images for full score: ${missingImages.join(', ')}`)\n }\n\n const status = getStatusCategory(score)\n return {score, status, issues}\n}\n\nconst resolveTypeLabel = (type: string, typeLabels?: Record<string, string>): string =>\n typeLabels?.[type] ?? type\n\n/**\n * Builds the GROQ projection snippet for the title field.\n * - undefined / 'title' → `title`\n * - 'name' → `\"title\": name`\n * - { post: 'title', product: 'name' } → `\"title\": select(_type == \"post\" => title, _type == \"product\" => name, title)`\n */\nconst buildTitleProjection = (titleField?: string | Record<string, string>): string => {\n if (!titleField || titleField === 'title') return 'title'\n if (typeof titleField === 'string') return `\"title\": ${titleField}`\n const cases = Object.entries(titleField)\n .map(([type, field]) => `_type == \"${type}\" => ${field}`)\n .join(', ')\n return `\"title\": select(${cases}, title)`\n}\n\nexport interface SeoHealthDashboardProps {\n icon?: string\n title?: string\n description?: string\n showTypeColumn?: boolean\n showDocumentId?: boolean\n /**\n * Limit the dashboard to specific document type names.\n * If both queryTypes and customQuery are provided, customQuery takes precedence.\n */\n queryTypes?: string[]\n /**\n * When using `queryTypes`, also filter by `seo != null`.\n * Set to `false` to include documents of those types even without an seo field.\n * Defaults to `true`.\n */\n queryRequireSeo?: boolean\n /**\n * A fully custom GROQ query used to fetch documents.\n * Must return objects with at least: _id, _type, title, seo, _updatedAt\n * Takes precedence over queryTypes.\n */\n customQuery?: string\n /**\n * The Sanity API version to use for the client (e.g. '2023-01-01').\n * Defaults to '2023-01-01'.\n */\n apiVersion?: string\n /**\n * License key for the SEO Health Dashboard.\n * Obtain a key at https://sanity-plugin-seofields.thehardik.in\n */\n licenseKey?: string\n /**\n * Map raw `_type` values to human-readable display labels used in the\n * Type column and the Type filter dropdown.\n * Replaces the deprecated `typeLabels`.\n * Any type without an entry falls back to the raw `_type` string.\n *\n * @example\n * typeDisplayLabels={{ productDrug: 'Products', singleCondition: 'Condition' }}\n */\n typeDisplayLabels?: Record<string, string>\n /**\n * Controls how the type is rendered in the Type column.\n * - `'badge'` (default) — coloured pill, consistent with score badges\n * - `'text'` — plain text, useful for dense layouts\n */\n typeColumnMode?: 'badge' | 'text'\n /**\n * The document field to use as the display title.\n *\n * - `string` — use this field for every document type (e.g. `'name'`)\n * - `Record<string, string>` — per-type mapping; unmapped types fall back to `title`\n *\n * @example\n * // Same field for all types\n * titleField: 'name'\n *\n * @example\n * // Different field per type\n * titleField: { post: 'title', product: 'name', category: 'label' }\n */\n titleField?: string | Record<string, string>\n /**\n * Callback function to render a custom badge next to the document title.\n * Replaces the deprecated `docBadge`.\n * Receives the full document and should return badge data or undefined.\n *\n * @example\n * getDocumentBadge: (doc) => {\n * if (doc.services === 'NHS')\n * return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }\n * if (doc.services === 'Private')\n * return { label: 'Private', bgColor: '#fef3c7', textColor: '#92400e' }\n * }\n */\n getDocumentBadge?: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n /**\n * Custom text shown while the license key is being verified.\n * Defaults to `\"Verifying license…\"`.\n */\n loadingLicense?: React.ReactNode\n /**\n * Custom text shown while documents are being fetched.\n * Defaults to `\"Loading documents…\"`.\n */\n loadingDocuments?: React.ReactNode\n /**\n * Custom text shown when the query returns zero results.\n * Defaults to `\"No documents found\"`.\n */\n noDocuments?: React.ReactNode\n /**\n * Enable preview/demo mode to show dummy data.\n * Useful for testing, documentation, or showcasing the dashboard.\n * When enabled, displays realistic sample documents with various SEO scores.\n * Defaults to `false`.\n */\n previewMode?: boolean\n /**\n * When `true`, clicking a document title opens the document editor as a split\n * pane to the right, keeping the SEO Health pane visible on the left.\n * This uses Sanity's pane router and requires the component to be rendered\n * inside a desk-structure pane context (i.e. via `createSeoHealthPane`).\n *\n * When `false` (default), clicking navigates to the document via the standard\n * intent-link system (full navigation).\n *\n * This is set to `true` automatically by `createSeoHealthPane`.\n */\n openInPane?: boolean\n /**\n * The `name` of the Sanity structure tool that contains the monitored documents.\n * When provided, clicking a document title navigates directly to that tool's\n * intent URL (`/{basePath}/{structureTool}/intent/edit/id=…;type=…/`) instead of\n * using the generic intent resolver, which always picks the first registered tool.\n *\n * Required when you have multiple structure tools and the documents live in a\n * non-default one (e.g. `name: 'common'`).\n *\n * @example\n * structureTool: 'common'\n */\n structureTool?: string\n /**\n * @internal — populated by the plugin when deprecated config keys are detected.\n * Each entry carries the migration hint, the version it was deprecated in, and\n * the matching changelog URL so the banner can group warnings by release.\n */\n _deprecationWarnings?: DeprecationWarning[]\n}\n\n/**\n * Generate dummy data for preview mode showing various SEO health scenarios\n */\nconst generateDummyData = (): DocumentWithSeoHealth[] => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const dummyDocs: any[] = [\n {\n _id: 'preview-post-1',\n _type: 'post',\n title: 'Getting Started with SEO Best Practices',\n slug: {current: 'getting-started-seo'},\n _updatedAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Getting Started with SEO Best Practices | My Blog',\n description:\n 'Learn the fundamentals of SEO optimization to improve your website visibility and search rankings.',\n keywords: ['seo', 'best practices', 'optimization'],\n metaImage: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}},\n openGraph: {\n title: 'SEO Best Practices Guide',\n description: 'Master SEO optimization',\n image: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}, alt: 'SEO Guide'},\n type: 'article',\n },\n twitter: {\n title: 'SEO Best Practices',\n description: 'Learn SEO optimization',\n image: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}, alt: 'Guide'},\n card: 'summary_large_image',\n },\n },\n },\n {\n _id: 'preview-post-2',\n _type: 'post',\n title: 'Advanced Analytics Strategy',\n slug: {current: 'advanced-analytics'},\n _updatedAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Advanced Analytics',\n description: 'Strategy tips',\n keywords: ['analytics', 'data'],\n openGraph: {\n title: 'Analytics Guide',\n },\n },\n },\n {\n _id: 'preview-page-1',\n _type: 'page',\n title: 'About Us',\n slug: {current: 'about'},\n _updatedAt: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'About',\n keywords: ['company', 'team'],\n metaImage: {_type: 'image', asset: {_ref: 'image-456', _type: 'reference'}},\n },\n },\n {\n _id: 'preview-post-3',\n _type: 'post',\n title: 'Content Marketing Trends for 2024',\n slug: {current: 'content-marketing-trends'},\n _updatedAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Content Marketing Trends 2024',\n description:\n 'Discover the latest content marketing trends and strategies to engage your audience effectively.',\n keywords: ['content marketing', 'trends', 'strategy', 'engagement'],\n metaImage: {_type: 'image', asset: {_ref: 'image-789', _type: 'reference'}},\n openGraph: {\n title: 'Content Marketing Trends 2024',\n description: 'Latest trends in content marketing',\n image: {_type: 'image', asset: {_ref: 'image-789', _type: 'reference'}, alt: 'Trends'},\n type: 'article',\n },\n twitter: {\n title: 'Content Marketing Trends',\n description: 'Discover the latest trends',\n card: 'summary',\n },\n },\n },\n {\n _id: 'preview-post-4',\n _type: 'product',\n title: 'Pro Plan',\n slug: {current: 'pro-plan'},\n _updatedAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Pro',\n keywords: ['pricing'],\n },\n },\n {\n _id: 'preview-page-2',\n _type: 'page',\n title: 'Contact',\n slug: {current: 'contact'},\n _updatedAt: new Date(Date.now() - 8 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n openGraph: {\n title: 'Get in Touch',\n },\n },\n },\n {\n _id: 'preview-post-5',\n _type: 'post',\n title: 'Mobile Optimization Guide',\n slug: {current: 'mobile-optimization'},\n _updatedAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Mobile Optimization Guide: Best Practices for Responsive Design',\n description:\n 'Complete guide to mobile optimization including responsive design, performance tips, and user experience best practices for modern web development.',\n keywords: ['mobile', 'optimization', 'responsive', 'performance'],\n metaImage: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}},\n openGraph: {\n title: 'Mobile Optimization Best Practices',\n description: 'Master mobile web optimization',\n image: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}, alt: 'Mobile'},\n type: 'article',\n },\n twitter: {\n title: 'Mobile Optimization Tips',\n description: 'Responsive design best practices',\n image: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}, alt: 'Mobile'},\n card: 'summary_large_image',\n },\n },\n },\n ]\n\n // Calculate health scores and return\n return dummyDocs.map((doc) => ({\n ...doc,\n health: calculateHealthScore(doc),\n }))\n}\n\nconst SeoHealthDashboard: React.FC<SeoHealthDashboardProps> = ({\n icon = '📊',\n title = 'SEO Health Dashboard',\n description = 'Monitor and optimize SEO fields across all your documents',\n showTypeColumn = true,\n showDocumentId = true,\n queryTypes,\n queryRequireSeo = true,\n customQuery,\n apiVersion = '2023-01-01',\n licenseKey,\n typeDisplayLabels,\n typeColumnMode = 'badge',\n titleField,\n getDocumentBadge,\n loadingLicense,\n loadingDocuments,\n noDocuments,\n previewMode = false,\n openInPane = false,\n structureTool,\n _deprecationWarnings,\n}) => {\n // Resolve deprecated prop pairs to their new counterparts, while allowing both to be used simultaneously for backward compatibility.\n const resolvedTypeLabels = typeDisplayLabels\n const resolvedDocBadge = getDocumentBadge\n\n // Collect all deprecation warnings to display in the UI banner\n const allDeprecationWarnings = useMemo(() => _deprecationWarnings ?? [], [_deprecationWarnings])\n\n // Group warnings by version so the banner renders one changelog link per release.\n const deprecationGroups = useMemo(() => {\n const groups = new Map<string, {version: string; changelogUrl: string; keys: string[]}>()\n for (const w of allDeprecationWarnings) {\n if (!groups.has(w.version)) {\n groups.set(w.version, {version: w.version, changelogUrl: w.changelogUrl, keys: []})\n }\n groups.get(w.version)!.keys.push(w.key)\n }\n return Array.from(groups.values())\n }, [allDeprecationWarnings])\n const client = useClient({apiVersion})\n const [licenseStatus, setLicenseStatus] = useState<'loading' | 'valid' | 'invalid'>('loading')\n const [documents, setDocuments] = useState<DocumentWithSeoHealth[]>([])\n const [loading, setLoading] = useState(true)\n const [isRefreshing, setIsRefreshing] = useState(false)\n const [searchQuery, setSearchQuery] = useState('')\n const [filterStatus, setFilterStatus] = useState<string>('all')\n const [filterType, setFilterType] = useState<string>('all')\n const [sortBy, setSortBy] = useState<'score' | 'title'>('score')\n const [activePopover, setActivePopover] = useState<{\n top: number\n left: number\n issues: string[]\n } | null>(null)\n\n const VALIDATION_ENDPOINT = 'https://sanity-plugin-seofields.thehardik.in/api/validate-license'\n const CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour\n\n const validateLicense = useCallback(\n async (forceRefresh = false) => {\n // Preview mode bypasses license validation\n if (previewMode) {\n setLicenseStatus('valid')\n return\n }\n\n // No key provided\n if (!licenseKey) {\n setLicenseStatus('invalid')\n return\n }\n\n const projectId = client.config().projectId ?? ''\n const cacheKey = `seofields_license_${projectId}`\n\n if (forceRefresh) {\n try {\n sessionStorage.removeItem(cacheKey)\n } catch {\n // ignore storage errors\n }\n }\n\n // Check sessionStorage cache\n if (!forceRefresh) {\n try {\n const cached = sessionStorage.getItem(cacheKey)\n if (cached) {\n const {valid, ts} = JSON.parse(cached) as {valid: boolean; ts: number}\n if (Date.now() - ts < CACHE_TTL_MS) {\n setLicenseStatus(valid ? 'valid' : 'invalid')\n return\n }\n }\n } catch {\n // ignore storage errors\n }\n }\n\n setLicenseStatus('loading')\n\n try {\n const res = await fetch(VALIDATION_ENDPOINT, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify({licenseKey, projectId}),\n })\n const valid = res.ok\n setLicenseStatus(valid ? 'valid' : 'invalid')\n try {\n sessionStorage.setItem(cacheKey, JSON.stringify({valid, ts: Date.now()}))\n } catch {\n // ignore storage errors\n }\n } catch {\n // Network error — fail open to avoid blocking legitimate users\n setLicenseStatus('valid')\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [licenseKey, previewMode],\n )\n\n useEffect(() => {\n validateLicense()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [licenseKey, previewMode])\n\n const handleMouseEnterIssues = (el: HTMLDivElement | null, issues: string[]) => {\n if (!el) return\n const rect = el.getBoundingClientRect()\n const popoverWidth = 280\n const viewportWidth = window.innerWidth\n\n // Align popover left edge to trigger left edge, clamp within viewport\n let left = rect.left\n if (left + popoverWidth > viewportWidth - 10) left = viewportWidth - popoverWidth - 10\n if (left < 10) left = 10\n\n setActivePopover({top: rect.top, left, issues})\n }\n\n const JSONStringifiedQueryTypes = JSON.stringify(queryTypes)\n const JSONStringifiedTitleField = JSON.stringify(titleField)\n\n const fetchDocuments = useCallback(\n async (isManualRefresh = false) => {\n try {\n if (isManualRefresh) {\n setIsRefreshing(true)\n } else {\n setLoading(true)\n }\n\n // Use dummy data in preview mode\n if (previewMode) {\n setDocuments(generateDummyData())\n return\n }\n\n let groqQuery: string\n let params: Record<string, unknown> = {}\n\n if (customQuery) {\n // Mode 3: fully custom GROQ (user-provided)\n groqQuery = customQuery\n } else if (queryTypes && queryTypes.length > 0) {\n // Mode 2: filter by specific document types (excluding drafts)\n const seoFilter = queryRequireSeo ? ' && seo != null' : ''\n const titleProj = buildTitleProjection(titleField)\n groqQuery = `*[_type in $types${seoFilter} && !(_id in path(\"drafts.**\"))]{\n _id,\n _type,\n ${titleProj},\n slug,\n seo,\n _updatedAt\n }`\n params = {types: queryTypes}\n } else {\n // Mode 1: default — all documents with an seo field (excluding drafts)\n const titleProj = buildTitleProjection(titleField)\n groqQuery = `*[seo != null && !(_id in path(\"drafts.**\"))]{\n _id,\n _type,\n ${titleProj},\n slug,\n seo,\n _updatedAt\n }`\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await client.fetch(groqQuery, params, {perspective: 'published'})\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const docsWithHealth: DocumentWithSeoHealth[] = result.map((doc: any) => ({\n ...doc,\n health: calculateHealthScore(doc),\n }))\n\n setDocuments(docsWithHealth)\n } catch (error) {\n console.error('Error fetching documents:', error)\n } finally {\n setLoading(false)\n setIsRefreshing(false)\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n client,\n customQuery,\n queryRequireSeo,\n JSONStringifiedQueryTypes,\n JSONStringifiedTitleField,\n previewMode,\n ],\n )\n\n useEffect(() => {\n fetchDocuments()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n client,\n customQuery,\n queryRequireSeo,\n JSONStringifiedQueryTypes,\n JSONStringifiedTitleField,\n previewMode,\n ])\n\n const handleRefresh = useCallback(() => {\n fetchDocuments(true)\n }, [fetchDocuments])\n\n const uniqueDocumentTypes = useMemo(() => {\n const types = new Set(documents.map((doc) => doc._type))\n return Array.from(types).sort()\n }, [documents])\n\n const filteredAndSortedDocs = useMemo(() => {\n let filtered = documents\n\n if (searchQuery) {\n filtered = filtered.filter(\n (doc) =>\n doc.title?.toLowerCase().includes(searchQuery.toLowerCase()) ||\n doc._id?.toLowerCase().includes(searchQuery.toLowerCase()),\n )\n }\n\n if (filterStatus !== 'all') {\n filtered = filtered.filter((doc) => doc.health.status === filterStatus)\n }\n\n if (filterType !== 'all') {\n filtered = filtered.filter((doc) => doc._type === filterType)\n }\n\n const sorted = [...filtered].sort((a, b) => {\n if (sortBy === 'score') {\n return b.health.score - a.health.score\n }\n return (a.title || '').localeCompare(b.title || '')\n })\n\n return sorted\n }, [documents, searchQuery, filterStatus, filterType, sortBy])\n\n const stats = useMemo(() => {\n const total = documents.length\n const excellent = documents.filter((d) => d.health.score >= 80).length\n const good = documents.filter((d) => d.health.score >= 60 && d.health.score < 80).length\n const fair = documents.filter((d) => d.health.score >= 40 && d.health.score < 60).length\n const poor = documents.filter((d) => d.health.score > 0 && d.health.score < 40).length\n const missing = documents.filter((d) => d.health.score === 0).length\n\n const avgScore =\n total > 0 ? Math.round(documents.reduce((sum, d) => sum + d.health.score, 0) / total) : 0\n\n return {total, excellent, good, fair, poor, missing, avgScore}\n }, [documents])\n\n const handleMouseLeave = useCallback(() => {\n setActivePopover(null)\n }, [])\n\n return (\n <DashboardContainer>\n {licenseStatus === 'loading' && (\n <LoadingState style={{padding: '80px 24px'}}>\n <Spinner />\n {loadingLicense ?? 'Verifying license…'}\n </LoadingState>\n )}\n {licenseStatus === 'invalid' && (\n <UpgradeContainer>\n <UpgradeBox>\n {licenseKey ? (\n <>\n <UpgradeLock>❌</UpgradeLock>\n <UpgradeTitle>Invalid License Key</UpgradeTitle>\n <UpgradeText>\n The license key you provided is invalid or has been revoked. Please check your key\n and update it in the plugin config.\n </UpgradeText>\n <UpgradeCode>{`seofields({\n healthDashboard: {\n licenseKey: 'YOUR_LICENSE_KEY', // ← replace with a valid key\n },\n})`}</UpgradeCode>\n <UpgradeButton\n href=\"https://sanity-plugin-seofields.thehardik.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Get a New License Key →\n </UpgradeButton>\n <br />\n {/* eslint-disable-next-line react/jsx-no-bind */}\n <ReloadButton onClick={() => validateLicense(true)}>\n Click here If You Just Updated Your Key\n </ReloadButton>\n </>\n ) : (\n <>\n <UpgradeLock>🔒</UpgradeLock>\n <UpgradeTitle>SEO Health Dashboard</UpgradeTitle>\n <UpgradeText>\n This feature requires a license key. Add your key to the plugin config to unlock\n the full dashboard.\n </UpgradeText>\n <UpgradeCode>{`// sanity.config.ts\nimport { seofields } from 'sanity-plugin-seofields'\n\nexport default defineConfig({\n plugins: [\n seofields({\n healthDashboard: {\n licenseKey: 'SEOF-XXXX-XXXX-XXXX',\n },\n }),\n ],\n})`}</UpgradeCode>\n <UpgradeButton\n href=\"https://sanity-plugin-seofields.thehardik.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Get a License Key →\n </UpgradeButton>\n </>\n )}\n </UpgradeBox>\n </UpgradeContainer>\n )}\n {licenseStatus === 'valid' && (\n <>\n {/* Header */}\n <PageHeader>\n <div>\n <PageTitle>\n <span>\n {icon} {title}\n </span>\n {previewMode && <PreviewBadge>Preview Mode</PreviewBadge>}\n </PageTitle>\n <PageSubtitle>{description}</PageSubtitle>\n </div>\n <DashboardRefreshButton\n onClick={handleRefresh}\n disabled={loading || isRefreshing}\n $spinning={isRefreshing}\n title=\"Refresh documents\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"23 4 23 10 17 10\" />\n <polyline points=\"1 20 1 14 7 14\" />\n <path d=\"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15\" />\n </svg>\n Refresh\n </DashboardRefreshButton>\n </PageHeader>\n {/* Deprecation warning banner */}\n {deprecationGroups.length > 0 && (\n <DeprecationBanner>\n <strong>⚠️ Deprecated config keys detected:</strong>{' '}\n {deprecationGroups.map((group, gi) => (\n <span key={group.version}>\n {group.keys.map((w, i) => (\n <span key={w}>\n <code style={{background: '#fef9c3', padding: '1px 4px', borderRadius: 3}}>\n {w.split('→')[0].trim()}\n </code>\n {' → '}\n <code style={{background: '#dcfce7', padding: '1px 4px', borderRadius: 3}}>\n {w.split('→')[1].trim()}\n </code>\n {i < group.keys.length - 1 ? ' · ' : ''}\n </span>\n ))}{' '}\n (\n <DeprecationBannerLink\n href={group.changelogUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {group.version} changelog\n </DeprecationBannerLink>\n ){gi < deprecationGroups.length - 1 ? ' · ' : ''}\n </span>\n ))}{' '}\n — Please update your config.\n </DeprecationBanner>\n )}\n {/* Stats Grid */}\n {!loading && (\n <StatsGrid>\n <StatCard>\n <StatLabel>Total Docs</StatLabel>\n <StatValue>{stats.total}</StatValue>\n </StatCard>\n <StatCard>\n <StatLabel>Avg Score</StatLabel>\n <StatValue>{stats.avgScore}%</StatValue>\n </StatCard>\n <StatCard $accent=\"#10b981\">\n <StatLabel>Excellent (80+)</StatLabel>\n <StatValue>{stats.excellent}</StatValue>\n </StatCard>\n <StatCard $accent=\"#f59e0b\">\n <StatLabel>Good (60–79)</StatLabel>\n <StatValue>{stats.good}</StatValue>\n </StatCard>\n <StatCard $accent=\"#f97316\">\n <StatLabel>Fair (40–59)</StatLabel>\n <StatValue>{stats.fair}</StatValue>\n </StatCard>\n <StatCard $accent=\"#ef4444\">\n <StatLabel>Poor / Missing</StatLabel>\n <StatValue>{stats.poor + stats.missing}</StatValue>\n </StatCard>\n </StatsGrid>\n )}\n {/* Controls */}\n <ControlsBar>\n <SearchWrapper>\n <SearchIconSvg>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </SearchIconSvg>\n <SearchInput\n placeholder=\"Search documents...\"\n value={searchQuery}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setSearchQuery(e.currentTarget.value)}\n />\n </SearchWrapper>\n <StyledSelect\n value={filterStatus}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setFilterStatus(e.currentTarget.value)}\n >\n <option value=\"all\">All Status</option>\n <option value=\"excellent\">Excellent</option>\n <option value=\"good\">Good</option>\n <option value=\"fair\">Fair</option>\n <option value=\"poor\">Poor</option>\n <option value=\"missing\">Missing</option>\n </StyledSelect>\n {uniqueDocumentTypes.length > 1 && (\n <StyledSelect\n value={filterType}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setFilterType(e.currentTarget.value)}\n >\n <option value=\"all\">All Types</option>\n {uniqueDocumentTypes.map((type) => (\n <option key={type} value={type}>\n {resolveTypeLabel(type, resolvedTypeLabels)}\n </option>\n ))}\n </StyledSelect>\n )}\n <StyledSelect\n value={sortBy}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setSortBy(e.currentTarget.value as 'score' | 'title')}\n >\n <option value=\"score\">Sort by Score</option>\n <option value=\"title\">Sort by Title</option>\n </StyledSelect>\n </ControlsBar>\n {/* Documents Table */}\n <TableCard>\n {loading && (\n <LoadingState>\n <Spinner />\n {loadingDocuments ?? 'Loading documents…'}\n </LoadingState>\n )}\n {!loading &&\n (filteredAndSortedDocs.length === 0 ? (\n <EmptyState>{noDocuments ?? 'No documents found'}</EmptyState>\n ) : (\n <>\n <TableHeader>\n <ColTitle>Title</ColTitle>\n {showTypeColumn && <ColType>Type</ColType>}\n <ColScore>Score</ColScore>\n <ColIssues>Top Issues</ColIssues>\n </TableHeader>\n {filteredAndSortedDocs.map((doc) => {\n return (\n <TableRow key={doc._id}>\n <ColTitle>\n <TitleWrapper>\n <TitleCell>\n {doc.title !== null && typeof doc.title !== 'string' ? (\n <NonStringTitleWarning title=\"title is not a string — use pt::text(title) in your query.groq projection to convert Portable Text to a plain string\">\n ⚠ title is not a string — use pt::text(title) in query.groq\n </NonStringTitleWarning>\n ) : (\n <>\n {openInPane ? (\n <DocTitleAnchorPane id={doc._id} type={doc._type}>\n {typeof doc.title === 'string'\n ? doc.title || 'Untitled'\n : 'Untitled'}\n </DocTitleAnchorPane>\n ) : (\n <DocTitleAnchor\n id={doc._id}\n type={doc._type}\n structureTool={structureTool}\n >\n {typeof doc.title === 'string'\n ? doc.title || 'Untitled'\n : 'Untitled'}\n </DocTitleAnchor>\n )}\n </>\n )}\n {showDocumentId && <DocId>{doc._id}</DocId>}\n {resolvedDocBadge && (\n <DocBadgeRenderer\n doc={doc as DocumentWithSeoHealth & Record<string, unknown>}\n docBadge={resolvedDocBadge}\n />\n )}\n </TitleCell>\n </TitleWrapper>\n </ColTitle>\n {showTypeColumn && (\n <ColType>\n {typeColumnMode === 'text' ? (\n <TypeText>{resolveTypeLabel(doc._type, resolvedTypeLabels)}</TypeText>\n ) : (\n (() => {\n const typeColor = getTypeColor(doc._type)\n return (\n <TypeBadge $bgColor={typeColor.bg} $textColor={typeColor.text}>\n {resolveTypeLabel(doc._type, resolvedTypeLabels)}\n </TypeBadge>\n )\n })()\n )}\n </ColType>\n )}\n <ColScore>\n <ScoreBadge $score={doc.health.score}>{doc.health.score}%</ScoreBadge>\n </ColScore>\n <ColIssues>\n {doc.health.issues.slice(0, 2).map((issue) => (\n <IssueTag key={`issue-${doc._id}-${issue}`}>• {issue}</IssueTag>\n ))}\n {doc.health.issues.length > 2 && (\n <MoreIssuesWrapper\n // eslint-disable-next-line react/jsx-no-bind\n onMouseEnter={function (e) {\n handleMouseEnterIssues(\n e.currentTarget as HTMLDivElement,\n doc.health.issues.slice(2),\n )\n }}\n onMouseLeave={handleMouseLeave}\n >\n <MoreIssues>+{doc.health.issues.length - 2} more issues</MoreIssues>\n </MoreIssuesWrapper>\n )}\n </ColIssues>\n </TableRow>\n )\n })}\n </>\n ))}\n </TableCard>\n {/* Single shared popover rendered outside the table */}\n {activePopover && (\n <IssuesPopover\n style={{\n top: activePopover.top,\n left: activePopover.left,\n transform: 'translateY(calc(-100% - 10px))',\n }}\n >\n {activePopover.issues.map((issue) => (\n <PopoverIssueItem key={issue}>⚠️ {issue}</PopoverIssueItem>\n ))}\n </IssuesPopover>\n )}{' '}\n </>\n )}{' '}\n </DashboardContainer>\n )\n}\n\nexport default SeoHealthDashboard\n","import SeoHealthDashboard, {SeoHealthDashboardProps} from './SeoHealthDashboard'\n\n/**\n * Sanity Tool component for the SEO Health Dashboard\n * This component wraps the SeoHealthDashboard for use as a custom tool in Sanity Studio\n */\nconst SeoHealthTool = (props: SeoHealthDashboardProps) => {\n return <SeoHealthDashboard {...props} />\n}\n\nexport default SeoHealthTool\n","import {defineField, defineType, FieldDefinition, SchemaTypeDefinition} from 'sanity'\n\nimport MetaDescription from '../components/meta/MetaDescription'\nimport MetaImage from '../components/meta/MetaImage'\nimport MetaTitle from '../components/meta/MetaTitle'\nimport SeoPreview from '../components/SeoPreview'\nimport {SeoFieldsPluginConfig} from '../plugin'\nimport {getFieldHiddenFunction, getFieldInfo} from '../utils/fieldsUtils'\nimport {isEmpty} from '../utils/utils'\nimport openGraph from './types/openGraph'\nimport twitter from './types/twitter'\n\nexport default function seoFieldsSchema(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition {\n return defineType({\n name: 'seoFields',\n title: 'SEO Fields',\n type: 'object',\n fields: [\n defineField({\n name: 'robots',\n title: 'Robots Settings',\n type: 'robots', // Use the separate robots type here\n hidden: getFieldHiddenFunction('robots', config),\n }),\n // 👇 conditionally spread preview field\n ...((typeof config.seoPreview === 'boolean' && config.seoPreview) ||\n (typeof config.seoPreview === 'object' && !isEmpty(config.seoPreview))\n ? [\n defineField({\n name: 'preview',\n title: 'SEO Preview',\n type: 'string',\n components: {input: SeoPreview},\n options: {\n baseUrl: config.baseUrl || 'https://www.example.com',\n ...(typeof config.seoPreview === 'object' &&\n config.seoPreview &&\n config.seoPreview.prefix\n ? {prefix: config.seoPreview.prefix}\n : {}),\n } as Record<string, unknown>,\n // Use a readOnly field to prevent editing\n // This field is just for preview purposes\n initialValue: '' as string, // Set an initial value\n readOnly: true,\n }),\n ]\n : []),\n\n defineField({\n name: 'title',\n ...getFieldInfo('title', config.fieldOverrides),\n // title: 'Meta Title',\n type: 'string',\n // description:\n // 'The meta title is displayed in search engine results as the clickable headline for a given result. It should be concise and accurately reflect the content of the page.',\n components: {\n input: MetaTitle,\n },\n // validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),\n hidden: getFieldHiddenFunction('title', config),\n }),\n defineField({\n name: 'description',\n ...getFieldInfo('description', config.fieldOverrides),\n // title: 'Meta Description',\n // description:\n // 'Provide a concise summary of the page content. This description may be used by search engines in search results.',\n type: 'text',\n rows: 3,\n components: {\n input: MetaDescription,\n },\n // validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),\n hidden: getFieldHiddenFunction('description', config),\n }),\n defineField({\n name: 'metaImage',\n ...getFieldInfo('metaImage', config.fieldOverrides),\n // title: 'Meta Image',\n // description:\n // 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',\n type: 'image',\n options: {\n hotspot: true,\n },\n components: {\n input: MetaImage,\n },\n hidden: getFieldHiddenFunction('metaImage', config),\n }),\n defineField({\n name: 'metaAttributes',\n // title: 'Additional Meta Attributes',\n ...getFieldInfo('metaAttributes', config.fieldOverrides),\n type: 'array',\n of: [{type: 'metaAttribute'}],\n // description:\n // 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',\n hidden: getFieldHiddenFunction('metaAttributes', config),\n }),\n defineField({\n name: 'keywords',\n ...getFieldInfo('keywords', config.fieldOverrides),\n title: 'Keywords',\n type: 'array',\n of: [{type: 'string'}],\n description:\n 'Add relevant keywords for this page. These keywords will be used for SEO purposes.',\n hidden: getFieldHiddenFunction('keywords', config),\n }),\n defineField({\n name: 'canonicalUrl',\n ...getFieldInfo('canonicalUrl', config.fieldOverrides),\n title: 'Canonical URL',\n type: 'url',\n description:\n 'Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.',\n hidden: getFieldHiddenFunction('canonicalUrl', config),\n }),\n openGraph(config) as unknown as FieldDefinition,\n twitter(config) as unknown as FieldDefinition,\n ],\n })\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getMetaDescriptionValidationMessages} from '../../utils/seoUtils'\n\nconst MetaDescription = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getMetaDescriptionValidationMessages(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{width: 10, height: 10, borderRadius: '50%', backgroundColor: item.color}}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default MetaDescription\n","import {FeedbackType} from '../types'\n\nexport const stopWords = ['the', 'a', 'an', 'and', 'or', 'but']\n\nexport const hasMatchingKeyword = (title: string, keywordList: string[]): boolean => {\n if (!title || keywordList.length === 0) return false\n const lowerTitle = title.toLowerCase()\n return keywordList.some((keyword) => keyword && lowerTitle.includes(keyword.toLowerCase()))\n}\n\nexport const hasKeywordOveruse = (\n title: string,\n keywordList: string[],\n maxOccurrences = 3,\n): boolean => {\n if (!title || keywordList.length === 0) return false\n const lowerTitle = title.toLowerCase()\n return keywordList.some((keyword) => {\n if (!keyword) return false\n const matches = lowerTitle.match(new RegExp(keyword.toLowerCase(), 'g'))\n return matches ? matches.length > maxOccurrences : false\n })\n}\n\nexport const startsWithStopWord = (title: string): boolean => {\n if (!title) return false\n const firstWord = title.trim().split(' ')[0].toLowerCase()\n return stopWords.includes(firstWord)\n}\n\nexport const primaryKeywordAtStart = (title: string, keywords: string[]): boolean => {\n if (!title || keywords.length === 0) return true\n return title.toLowerCase().startsWith(keywords[0].toLowerCase())\n}\n\nexport const truncate = (text: string, maxLength: number): string =>\n text.length > maxLength ? `${text.slice(0, maxLength)}…` : text\n\nexport const hasExcessivePunctuation = (title: string): boolean => /[!@#$%^&*]{2,}/.test(title)\n\nexport const getMetaTitleValidationMessages = (\n title: string,\n keywords: string[],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n const minChar = 50\n const maxChar = 60\n const charCount = title?.length || 0\n\n // Empty check\n if (!title?.trim()) {\n feedback.push({text: 'Meta Title is empty. Add content to improve SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (charCount < minChar)\n feedback.push({\n text: `Title is ${charCount} characters — below recommended ${minChar}.`,\n color: 'orange',\n })\n else if (charCount > maxChar)\n feedback.push({\n text: `Title is ${charCount} characters — exceeds recommended ${maxChar}.`,\n color: 'red',\n })\n else feedback.push({text: `Title length (${charCount}) looks good for SEO.`, color: 'green'})\n\n // Keyword checks\n if (isParentseoField) {\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(title, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in title — good job!'\n : 'Keywords defined but missing in title.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(title, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Stop word check\n if (startsWithStopWord(title))\n feedback.push({text: 'Title starts with a stop word — consider rephrasing.', color: 'orange'})\n\n // Punctuation check\n if (hasExcessivePunctuation(title))\n feedback.push({text: 'Title contains excessive punctuation — simplify it.', color: 'orange'})\n\n return feedback\n}\n\nexport const getMetaDescriptionValidationMessages = (\n description: string,\n keywords: string[],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n const minChar = 120\n const maxChar = 160\n const charCount = description?.length || 0\n\n if (!description?.trim()) {\n feedback.push({text: 'Meta description is empty. Add content to improve SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (charCount < minChar)\n feedback.push({\n text: `Description is ${charCount} chars — below recommended ${minChar}.`,\n color: 'orange',\n })\n else if (charCount > maxChar)\n feedback.push({\n text: `Description is ${charCount} chars — exceeds recommended ${maxChar}.`,\n color: 'red',\n })\n else\n feedback.push({text: `Description length (${charCount}) looks good for SEO.`, color: 'green'})\n\n // Keyword checks\n if (isParentseoField) {\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(description, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in description — good job!'\n : 'Keywords defined but missing in description.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(description, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Stop word / filler check\n if (startsWithStopWord(description))\n feedback.push({\n text: 'Description starts with a stop word — consider rephrasing.',\n color: 'orange',\n })\n\n // Punctuation / special characters\n if (hasExcessivePunctuation(description))\n feedback.push({\n text: 'Description contains excessive punctuation — simplify it.',\n color: 'orange',\n })\n\n return feedback\n}\n\nexport const getOgTitleValidation = (\n title: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 40\n const max = 60\n const count = title?.length || 0\n\n // Empty check\n if (!title?.trim()) {\n feedback.push({text: 'OG Title is empty. Add content for better social preview.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `OG Title is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({text: `OG Title is ${count} chars — exceeds recommended ${max}.`, color: 'red'})\n else feedback.push({text: `OG Title length (${count}) looks good.`, color: 'green'})\n\n if (isParentseoField) {\n // Keyword checks\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(title, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in OG title — good job!'\n : 'Keywords defined but missing in OG title.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(title, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times in OG title — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Additional OG-specific checks\n if (startsWithStopWord(title))\n feedback.push({\n text: 'OG Title starts with a stop word — consider rephrasing.',\n color: 'orange',\n })\n\n if (hasExcessivePunctuation(title))\n feedback.push({text: 'OG Title contains excessive punctuation — simplify it.', color: 'orange'})\n\n return feedback\n}\n\nexport const getOgDescriptionValidation = (\n desc: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 90\n const max = 120\n const count = desc?.length || 0\n\n // Empty check\n if (!desc?.trim()) {\n feedback.push({\n text: 'OG Description is empty. Add content for better social preview.',\n color: 'red',\n })\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `OG Description is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({\n text: `OG Description is ${count} chars — exceeds recommended ${max}.`,\n color: 'red',\n })\n else feedback.push({text: `OG Description length (${count}) looks good.`, color: 'green'})\n\n // Keyword checks\n if (isParentseoField) {\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(desc, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in OG description — good job!'\n : 'Keywords defined but missing in OG description.',\n color: hasKeyword ? 'green' : 'red',\n })\n\n if (hasKeywordOveruse(desc, keywords)) {\n feedback.push({\n text: 'Keyword appears too many times in OG description — avoid keyword stuffing.',\n color: 'orange',\n })\n }\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Additional OG-specific checks\n if (startsWithStopWord(desc))\n feedback.push({\n text: 'OG Description starts with a stop word — consider rephrasing.',\n color: 'orange',\n })\n\n if (hasExcessivePunctuation(desc))\n feedback.push({\n text: 'OG Description contains excessive punctuation — simplify it.',\n color: 'orange',\n })\n\n return feedback\n}\n\nexport const getTwitterTitleValidation = (\n title: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 30\n const max = 70\n const count = title?.length || 0\n\n if (!title?.trim()) {\n feedback.push({text: 'X Title is empty. Add content for better SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `X Title is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({\n text: `X Title is ${count} chars — exceeds recommended ${max}.`,\n color: 'red',\n })\n else feedback.push({text: `X Title length (${count}) looks good.`, color: 'green'})\n\n if (isParentseoField) {\n // Keyword checks\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(title, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in X title — good job!'\n : 'Keywords defined but missing in X title.',\n color: hasKeyword ? 'green' : 'red',\n })\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Punctuation check\n if (/[!@#$%^&*]{2,}/.test(title))\n feedback.push({text: 'X Title has excessive punctuation — simplify it.', color: 'orange'})\n\n return feedback\n}\n\nexport const getTwitterDescriptionValidation = (\n desc: string,\n keywords: string[] = [],\n isParentseoField: boolean,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n const min = 50\n const max = 200\n const count = desc?.length || 0\n\n if (!desc?.trim()) {\n feedback.push({text: 'X Description is empty. Add content for better SEO.', color: 'red'})\n return feedback\n }\n\n // Length check\n if (count < min)\n feedback.push({\n text: `X Description is ${count} chars — shorter than recommended ${min}.`,\n color: 'orange',\n })\n else if (count > max)\n feedback.push({\n text: `X Description is ${count} chars — exceeds recommended ${max}.`,\n color: 'red',\n })\n else feedback.push({text: `X Description length (${count}) looks good.`, color: 'green'})\n\n if (isParentseoField) {\n // Keyword checks\n if (keywords.length > 0) {\n const hasKeyword = hasMatchingKeyword(desc, keywords)\n feedback.push({\n text: hasKeyword\n ? 'Keyword found in X description — good job!'\n : 'Keywords defined but missing in X description.',\n color: hasKeyword ? 'green' : 'red',\n })\n } else {\n feedback.push({\n text: 'No keywords defined. Consider adding relevant keywords.',\n color: 'orange',\n })\n }\n }\n\n // Punctuation check\n if (/[!@#$%^&*]{2,}/.test(desc))\n feedback.push({\n text: 'X Description has excessive punctuation — simplify it.',\n color: 'orange',\n })\n\n return feedback\n}\n\n// ── Image Validation Helpers ──\n\n/** Check if an image is set in an OG/Twitter sub-object (handles upload vs URL) */\nexport const isSubImageSet = (subObj: Record<string, unknown> | null | undefined): boolean => {\n if (!subObj) return false\n if (subObj.imageType === 'url') return !!(subObj.imageUrl as string)?.trim()\n const img = subObj.image as Record<string, unknown> | undefined\n return !!img?.asset\n}\n\n/** Check if metaImage asset is set */\nconst isMetaImageSet = (seoParent: Record<string, unknown> | null | undefined): boolean => {\n if (!seoParent) return false\n const metaImage = seoParent.metaImage as Record<string, unknown> | undefined\n return !!metaImage?.asset\n}\n\nexport const getMetaImageValidation = (\n hasImage: boolean,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!hasImage) {\n feedback.push({\n text: 'No meta image provided. Adding an image improves click-through rates.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'Meta image is set — great for SEO and social sharing.', color: 'green'})\n\n const ogSet = isSubImageSet(seoParent?.openGraph as Record<string, unknown> | undefined)\n const twSet = isSubImageSet(seoParent?.twitter as Record<string, unknown> | undefined)\n\n if (!ogSet && !twSet) {\n feedback.push({\n text: 'OG and Twitter images are missing — add them for full social coverage.',\n color: 'orange',\n })\n } else if (!ogSet) {\n feedback.push({\n text: 'OG image is missing — add it for better Facebook/LinkedIn previews.',\n color: 'orange',\n })\n } else if (twSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n feedback.push({\n text: 'Twitter image is missing — add it for better X (Twitter) cards.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n\nexport const getOgImageValidation = (\n hasImage: boolean,\n altText: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!hasImage) {\n feedback.push({\n text: 'No OG image provided. Social shares will lack a visual preview.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'OG image is set — good for social sharing.', color: 'green'})\n\n if (altText?.trim()) {\n feedback.push({text: 'Alt text is set — good for accessibility.', color: 'green'})\n } else {\n feedback.push({text: 'Consider adding alt text for better accessibility.', color: 'orange'})\n }\n\n const metaSet = isMetaImageSet(seoParent)\n const twSet = isSubImageSet(seoParent?.twitter as Record<string, unknown> | undefined)\n\n if (metaSet && twSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!twSet)\n feedback.push({\n text: 'Twitter image is missing — add it for X (Twitter) cards.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n\nexport const getOgImageUrlValidation = (\n imageUrl: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!imageUrl?.trim()) {\n feedback.push({\n text: 'No OG image URL provided. Social shares will lack a visual preview.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'OG image URL is set — good for social sharing.', color: 'green'})\n\n const metaSet = isMetaImageSet(seoParent)\n const twSet = isSubImageSet(seoParent?.twitter as Record<string, unknown> | undefined)\n\n if (metaSet && twSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!twSet)\n feedback.push({\n text: 'Twitter image is missing — add it for X (Twitter) cards.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n\nexport const getTwitterImageValidation = (\n hasImage: boolean,\n altText: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!hasImage) {\n feedback.push({\n text: 'No Twitter image provided. Posts on X will lack a visual.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'Twitter image is set — good for X sharing.', color: 'green'})\n\n if (altText?.trim()) {\n feedback.push({text: 'Alt text is set — good for accessibility.', color: 'green'})\n } else {\n feedback.push({text: 'Consider adding alt text for better accessibility.', color: 'orange'})\n }\n\n const metaSet = isMetaImageSet(seoParent)\n const ogSet = isSubImageSet(seoParent?.openGraph as Record<string, unknown> | undefined)\n\n if (metaSet && ogSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!ogSet)\n feedback.push({\n text: 'OG image is missing — add it for Facebook/LinkedIn sharing.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n\nexport const getTwitterImageUrlValidation = (\n imageUrl: string | undefined,\n seoParent: Record<string, unknown> | null | undefined,\n): FeedbackType[] => {\n const feedback: FeedbackType[] = []\n\n if (!imageUrl?.trim()) {\n feedback.push({\n text: 'No Twitter image URL provided. Posts on X will lack a visual.',\n color: 'red',\n })\n return feedback\n }\n\n feedback.push({text: 'Twitter image URL is set — good for X sharing.', color: 'green'})\n\n const metaSet = isMetaImageSet(seoParent)\n const ogSet = isSubImageSet(seoParent?.openGraph as Record<string, unknown> | undefined)\n\n if (metaSet && ogSet) {\n feedback.push({text: 'All images set (Meta, OG, Twitter) — full coverage!', color: 'green'})\n } else {\n if (!metaSet)\n feedback.push({\n text: 'Meta image is missing — add it for search engine results.',\n color: 'orange',\n })\n if (!ogSet)\n feedback.push({\n text: 'OG image is missing — add it for Facebook/LinkedIn sharing.',\n color: 'orange',\n })\n }\n\n return feedback\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {ObjectInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getMetaImageValidation} from '../../utils/seoUtils'\n\nconst MetaImage = (props: ObjectInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n const hasImage = !!(value as Record<string, unknown> | undefined)?.asset\n\n const feedbackItems = useMemo(\n () => getMetaImageValidation(hasImage, seoParent),\n [hasImage, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default MetaImage\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getMetaTitleValidationMessages} from '../../utils/seoUtils'\n\nconst MetaTitle = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getMetaTitleValidationMessages(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default MetaTitle\n","import {Box, Stack, Text} from '@sanity/ui'\nimport React from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\nimport styled from 'styled-components'\n\nimport {truncate} from '../utils/seoUtils'\n\nconst PreviewContainer = styled.div`\n max-width: 600px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #ffffff;\n border: 1px solid #dadce0;\n border-radius: 8px;\n overflow: hidden;\n`\n\nconst PreviewHeader = styled.div`\n background: #f8f9fa;\n padding: 12px 16px;\n border-bottom: 1px solid #dadce0;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n`\n\nconst PreviewBody = styled.div`\n padding: 16px;\n`\n\nconst SerpUrl = styled.p`\n margin: 0 0 4px;\n color: #006621;\n font-size: 13px;\n line-height: 1.4;\n word-break: break-word;\n`\n\nconst SerpTitle = styled.h3`\n margin: 0 0 8px;\n color: #1a0dab;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.4;\n word-break: break-word;\n\n &:hover {\n text-decoration: underline;\n }\n`\n\nconst SerpDescription = styled.p`\n margin: 0;\n color: #545454;\n font-size: 14px;\n line-height: 1.6;\n word-break: break-word;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n`\n\nconst LiveIndicator = styled.span`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: #4f46e5;\n background: #f0f4ff;\n padding: 4px 8px;\n border-radius: 4px;\n`\n\nconst SeoPreview = (props: StringInputProps): React.ReactElement => {\n const {path, schemaType} = props\n const {options} = schemaType as {\n options?: {\n baseUrl?: string\n prefix?: ((doc: {_type?: string} & Record<string, unknown>) => string) | string\n }\n }\n const baseUrl = options?.baseUrl || 'https://www.example.com'\n const prefixFunction = options?.prefix as\n | ((doc: {_type?: string} & Record<string, unknown>) => string)\n | undefined\n const parent = useFormValue([path[0]]) || {\n title: '',\n description: '',\n canonicalUrl: '',\n }\n const rootDoc: {\n slug?: {current: string}\n } = useFormValue([]) || {\n slug: {current: ''},\n }\n const slug: string = rootDoc?.slug?.current || ''\n\n const {\n title,\n description,\n canonicalUrl: url,\n } = parent as {\n title?: string\n description?: string\n canonicalUrl?: string\n }\n\n // Build full URL\n const base = (url || baseUrl)?.replace(/\\/+$/, '')\n const slugStr = String(slug || '').replace(/^\\/+/, '')\n const pref = String(\n prefixFunction ? prefixFunction(rootDoc as {slug?: {current: string}}) : '',\n ).replace(/^\\/+|\\/+$/g, '')\n const urlPath = [pref, slugStr].filter(Boolean).join('/')\n const finalUrl = urlPath ? `${base}/${urlPath}` : base\n\n // Extract domain for display\n const domain = (() => {\n try {\n const u = new URL(finalUrl || base)\n return u.hostname\n } catch {\n return 'example.com'\n }\n })()\n\n // Format URL display with › separator\n const urlDisplay = `${domain}${urlPath ? ` › ${urlPath.split('/').slice(-1)[0]}` : ''}`\n\n return (\n <Box padding={3}>\n <PreviewContainer>\n <PreviewHeader>\n <span\n style={{\n fontSize: '11px',\n color: '#5f6368',\n textTransform: 'uppercase',\n letterSpacing: '0.05em',\n }}\n >\n Search Preview\n </span>\n <LiveIndicator>\n <span\n style={{\n width: '4px',\n height: '4px',\n borderRadius: '50%',\n backgroundColor: '#4f46e5',\n display: 'inline-block',\n }}\n />\n Live\n </LiveIndicator>\n </PreviewHeader>\n\n <PreviewBody>\n <SerpUrl>{finalUrl ? urlDisplay : 'example.com › page-url'}</SerpUrl>\n <SerpTitle>\n {title && title.length > 0 ? truncate(title, 60) : 'Your SEO Title will appear here'}\n </SerpTitle>\n <SerpDescription>\n {description && description.length > 0\n ? truncate(description, 160)\n : 'Your meta description will show up here. Make it compelling!'}\n </SerpDescription>\n </PreviewBody>\n </PreviewContainer>\n </Box>\n )\n}\n\nexport default SeoPreview\n","import {AllFieldKeys, SeoFieldsPluginConfig, ValidHiddenFieldKeys} from '../plugin'\n\nconst DEFAULT_FIELD_INFO: Record<AllFieldKeys, {title: string; description: string}> = {\n title: {\n title: 'Meta Title',\n description:\n 'The meta title is displayed in search engine results as the clickable headline for a given result. It should be concise and accurately reflect the content of the page.',\n },\n description: {\n title: 'Meta Description',\n description:\n 'Provide a concise summary of the page content. This description may be used by search engines in search results.',\n },\n metaImage: {\n title: 'Meta Image',\n description:\n 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',\n },\n keywords: {\n title: 'Keywords',\n description:\n 'Add relevant keywords for this page. These keywords will be used for SEO purposes.',\n },\n canonicalUrl: {\n title: 'Canonical URL',\n description:\n 'Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.',\n },\n robots: {\n title: 'Robots Settings',\n description: 'Configure how search engine crawlers should index and follow links on this page.',\n },\n metaAttributes: {\n title: 'Additional Meta Attributes',\n description:\n 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',\n },\n openGraphTitle: {\n title: 'Open Graph Title',\n description: '',\n },\n openGraphUrl: {\n title: 'Open Graph URL',\n description:\n 'The canonical URL of the page. This should be the full URL including protocol (https://).',\n },\n openGraphDescription: {\n title: 'Open Graph Description',\n description: '',\n },\n openGraphSiteName: {\n title: 'Open Graph Site Name',\n description: 'The name of your website. This is often the site title.',\n },\n openGraphType: {\n title: 'Open Graph Type',\n description: 'Select the type of content for Open Graph.',\n },\n openGraphImageType: {\n title: 'Image Type',\n description: 'Choose whether to upload an image or provide an image URL for Open Graph.',\n },\n openGraphImage: {\n title: 'Open Graph Image',\n description:\n 'Recommended size: 1200x630px (minimum 600x315px). Max file size: 5MB. Aspect ratio 1.91:1.',\n },\n openGraphImageUrl: {\n title: 'Open Graph Image URL',\n description:\n 'Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px).',\n },\n twitterCard: {\n title: 'X Card Type',\n description: '',\n },\n twitterSite: {\n title: 'Site X Handle',\n description: 'The X (formerly Twitter) handle of the website (e.g., @example)',\n },\n twitterCreator: {\n title: 'X Creator Handle',\n description: 'The X (formerly Twitter) handle of the content creator (e.g., @creator)',\n },\n twitterTitle: {\n title: 'X Title',\n description: 'The title of the content as it should appear on X (formerly Twitter).',\n },\n twitterDescription: {\n title: 'X Description',\n description: 'A brief description of the content for X (formerly Twitter).',\n },\n twitterImageType: {\n title: 'X Image Type',\n description:\n 'Choose whether to upload an image or provide an image URL for X (formerly Twitter).',\n },\n twitterImage: {\n title: 'X Image',\n description:\n 'An image URL which should be at least 120x120px for \"summary\" card and 280x150px for \"summary_large_image\" card.',\n },\n twitterImageUrl: {\n title: 'X Image URL',\n description:\n 'Enter the full URL of the image for X (formerly Twitter). Ensure the image is accessible and meets the recommended size.',\n },\n}\n\nexport const getFieldInfo = (\n fieldName: string,\n fieldOverrides: SeoFieldsPluginConfig['fieldOverrides'],\n): {title: string; description: string} => {\n const fieldInfo =\n (fieldOverrides && fieldOverrides[fieldName as keyof typeof fieldOverrides]) ||\n DEFAULT_FIELD_INFO[fieldName as keyof typeof DEFAULT_FIELD_INFO]\n return fieldInfo\n ? {title: fieldInfo.title || '', description: fieldInfo.description || ''}\n : {title: '', description: ''}\n}\n\n/**\n * Check if a field should be hidden based on the current document type\n */\nexport const isFieldHidden = (\n fieldName: ValidHiddenFieldKeys,\n config: SeoFieldsPluginConfig,\n documentType?: string,\n): boolean => {\n // Check if field is in default hidden fields\n if (config.defaultHiddenFields?.includes(fieldName)) {\n return true\n }\n\n // Check if field is hidden for specific post type\n if (documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)) {\n return true\n }\n\n return false\n}\n\n/**\n * Get the hidden function for any field\n */\nexport const getFieldHiddenFunction = (\n fieldName: ValidHiddenFieldKeys,\n config: SeoFieldsPluginConfig,\n) => {\n return ({\n document,\n }: {\n document?: {\n _type?: string\n }\n }): boolean => {\n const documentType = document?._type\n return isFieldHidden(fieldName, config, documentType)\n }\n}\n","export const isEmpty = (value: unknown): boolean => {\n return (\n value === null ||\n value === undefined ||\n (typeof value === 'string' && value.trim() === '') ||\n (Array.isArray(value) && value.length === 0) ||\n (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0)\n )\n}\n","import {defineField, defineType, SchemaTypeDefinition} from 'sanity'\n\nimport OgDescription from '../../../components/openGraph/OgDescription'\nimport OgImage from '../../../components/openGraph/OgImage'\nimport OgImageUrl from '../../../components/openGraph/OgImageUrl'\nimport OgTitle from '../../../components/openGraph/OgTitle'\nimport {SeoFieldsPluginConfig} from '../../../plugin'\nimport {getFieldHiddenFunction, getFieldInfo} from '../../../utils/fieldsUtils'\n\nexport default function openGraph(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition {\n return defineType({\n name: 'openGraph',\n title: 'Open Graph Settings',\n type: 'object',\n fields: [\n defineField({\n name: 'url',\n type: 'url',\n ...getFieldInfo('openGraphUrl', config.fieldOverrides),\n hidden: getFieldHiddenFunction('openGraphUrl', config),\n description:\n 'The canonical URL of the page. This should be the full URL including protocol (https://).',\n }),\n defineField({\n name: 'title',\n ...getFieldInfo('openGraphTitle', config.fieldOverrides),\n type: 'string',\n hidden: getFieldHiddenFunction('openGraphTitle', config),\n components: {\n input: OgTitle, // Can also wrap with a string input + preview\n },\n }),\n defineField({\n name: 'description',\n ...getFieldInfo('openGraphDescription', config.fieldOverrides),\n type: 'text',\n rows: 3,\n hidden: getFieldHiddenFunction('openGraphDescription', config),\n components: {\n input: OgDescription, // Can also wrap with a text area + preview\n },\n }),\n defineField({\n name: 'siteName',\n ...getFieldInfo('openGraphSiteName', config.fieldOverrides),\n type: 'string',\n hidden: getFieldHiddenFunction('openGraphSiteName', config),\n }),\n defineField({\n name: 'type',\n ...getFieldInfo('openGraphType', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Website', value: 'website'},\n {title: 'Article', value: 'article'},\n {title: 'Profile', value: 'profile'},\n {title: 'Book', value: 'book'},\n {title: 'Music', value: 'music'},\n {title: 'Video', value: 'video'},\n {title: 'Product', value: 'product'},\n ],\n // layout: 'radio', // Display as radio buttons\n },\n hidden: getFieldHiddenFunction('openGraphType', config),\n initialValue: 'website',\n }),\n defineField({\n name: 'imageType',\n ...getFieldInfo('openGraphImageType', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Upload Image', value: 'upload'},\n {title: 'Image URL', value: 'url'},\n ],\n },\n hidden: getFieldHiddenFunction('openGraphImage', config),\n initialValue: 'upload',\n }),\n defineField({\n name: 'image',\n ...getFieldInfo('openGraphImage', config.fieldOverrides),\n type: 'image',\n options: {\n hotspot: true,\n },\n components: {\n input: OgImage,\n },\n fields: [\n defineField({\n name: 'alt',\n title: 'Image Alt Text',\n type: 'string',\n description: 'A description of the image for accessibility purposes.',\n }),\n ],\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'upload') return true\n const hiddenFn = getFieldHiddenFunction('openGraphImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n defineField({\n name: 'imageUrl',\n ...getFieldInfo('openGraphImageUrl', config.fieldOverrides),\n type: 'url',\n components: {\n input: OgImageUrl,\n },\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'url') return true\n const hiddenFn = getFieldHiddenFunction('openGraphImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n ],\n })\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgDescriptionValidation} from '../../utils/seoUtils'\n\nconst OgDescription = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getOgDescriptionValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n {/* Validation */}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgDescription\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {ObjectInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgImageValidation} from '../../utils/seoUtils'\n\nconst OgImage = (props: ObjectInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n const imgValue = value as Record<string, unknown> | undefined\n const hasImage = !!imgValue?.asset\n const altText = imgValue?.alt as string | undefined\n\n const feedbackItems = useMemo(\n () => getOgImageValidation(hasImage, altText, seoParent),\n [hasImage, altText, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgImage\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgImageUrlValidation} from '../../utils/seoUtils'\n\nconst OgImageUrl = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n\n const feedbackItems = useMemo(() => getOgImageUrlValidation(value, seoParent), [value, seoParent])\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgImageUrl\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getOgTitleValidation} from '../../utils/seoUtils'\n\nconst OgTitle: React.FC<StringInputProps> = (props) => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getOgTitleValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default OgTitle\n","import {defineField, defineType, SchemaTypeDefinition} from 'sanity'\n\nimport TwitterDescription from '../../../components/twitter/twitterDescription'\nimport TwitterImage from '../../../components/twitter/TwitterImage'\nimport TwitterImageUrl from '../../../components/twitter/TwitterImageUrl'\nimport TwitterTitle from '../../../components/twitter/twitterTitle'\nimport {SeoFieldsPluginConfig} from '../../../plugin'\nimport {getFieldHiddenFunction, getFieldInfo} from '../../../utils/fieldsUtils'\n\nexport default function twitter(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition {\n return defineType({\n name: 'twitter',\n title: 'X (Formerly Twitter)',\n type: 'object',\n fields: [\n defineField({\n name: 'card',\n ...getFieldInfo('twitterCard', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Summary', value: 'summary'},\n {title: 'Summary with Large Image', value: 'summary_large_image'},\n {title: 'App', value: 'app'},\n {title: 'Player', value: 'player'},\n ],\n },\n hidden: getFieldHiddenFunction('twitterCard', config),\n initialValue: 'summary_large_image', // good default\n }),\n defineField({\n name: 'site',\n ...getFieldInfo('twitterSite', config.fieldOverrides),\n type: 'string',\n hidden: getFieldHiddenFunction('twitterSite', config),\n }),\n defineField({\n name: 'creator',\n type: 'string',\n ...getFieldInfo('twitterCreator', config.fieldOverrides),\n hidden: getFieldHiddenFunction('twitterCreator', config),\n }),\n defineField({\n name: 'title',\n type: 'string',\n ...getFieldInfo('twitterTitle', config.fieldOverrides),\n hidden: getFieldHiddenFunction('twitterTitle', config),\n components: {\n input: TwitterTitle,\n },\n }),\n defineField({\n name: 'description',\n type: 'text',\n rows: 3,\n ...getFieldInfo('twitterDescription', config.fieldOverrides),\n hidden: getFieldHiddenFunction('twitterDescription', config),\n components: {\n input: TwitterDescription,\n },\n }),\n defineField({\n name: 'imageType',\n ...getFieldInfo('twitterImageType', config.fieldOverrides),\n type: 'string',\n options: {\n list: [\n {title: 'Upload Image', value: 'upload'},\n {title: 'Image URL', value: 'url'},\n ],\n },\n hidden: getFieldHiddenFunction('twitterImage', config),\n initialValue: 'upload',\n }),\n defineField({\n name: 'image',\n ...getFieldInfo('twitterImage', config.fieldOverrides),\n type: 'image',\n options: {\n hotspot: true,\n },\n components: {\n input: TwitterImage,\n },\n fields: [\n defineField({\n name: 'alt',\n title: 'Image Alt Text',\n type: 'string',\n description: 'A description of the image for accessibility purposes.',\n }),\n ],\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'upload') return true\n const hiddenFn = getFieldHiddenFunction('twitterImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n defineField({\n name: 'imageUrl',\n ...getFieldInfo('twitterImageUrl', config.fieldOverrides),\n type: 'url',\n components: {\n input: TwitterImageUrl,\n },\n hidden: (context) => {\n const {parent} = context\n if (parent?.imageType !== 'url') return true\n const hiddenFn = getFieldHiddenFunction('twitterImage', config)\n return typeof hiddenFn === 'function' ? hiddenFn(context) : hiddenFn\n },\n }),\n ],\n })\n}\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterDescriptionValidation} from '../../utils/seoUtils'\n\nconst TwitterDescription = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getTwitterDescriptionValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterDescription\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {ObjectInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterImageValidation} from '../../utils/seoUtils'\n\nconst TwitterImage = (props: ObjectInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n const imgValue = value as Record<string, unknown> | undefined\n const hasImage = !!imgValue?.asset\n const altText = imgValue?.alt as string | undefined\n\n const feedbackItems = useMemo(\n () => getTwitterImageValidation(hasImage, altText, seoParent),\n [hasImage, altText, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterImage\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterImageUrlValidation} from '../../utils/seoUtils'\n\nconst TwitterImageUrl = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n const seoParent = useFormValue([path[0]]) as Record<string, unknown> | null\n\n const feedbackItems = useMemo(\n () => getTwitterImageUrlValidation(value, seoParent),\n [value, seoParent],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterImageUrl\n","import {Stack, Text} from '@sanity/ui'\nimport React, {useMemo} from 'react'\nimport {StringInputProps, useFormValue} from 'sanity'\n\nimport {FeedbackType} from '../../types'\nimport {getTwitterTitleValidation} from '../../utils/seoUtils'\n\nconst TwitterTitle = (props: StringInputProps): React.ReactElement => {\n const {value, renderDefault, path} = props\n\n // Access parent object to get keywords\n const parent = useFormValue([path[0]]) as {keywords?: string[]; _type?: string}\n const isParentseoField = parent && parent?._type === 'seoFields'\n const keywords = useMemo(() => parent?.keywords || [], [parent?.keywords])\n\n const feedbackItems = useMemo(\n () => getTwitterTitleValidation(value || '', keywords, isParentseoField),\n [value, keywords, isParentseoField],\n )\n\n return (\n <Stack space={3}>\n {renderDefault(props)}\n <Stack space={2}>\n {feedbackItems.map((item: FeedbackType) => (\n <div key={item.text} style={{display: 'flex', alignItems: 'center', gap: 7}}>\n <div\n style={{\n minWidth: 10,\n height: 10,\n borderRadius: '50%',\n backgroundColor: item.color,\n }}\n />\n <Text weight=\"bold\" muted size={14}>\n {item.text}\n </Text>\n </div>\n ))}\n </Stack>\n </Stack>\n )\n}\n\nexport default TwitterTitle\n","import {defineField, defineType} from 'sanity'\n\nexport default defineType({\n name: 'metaAttribute',\n title: 'Meta Attribute',\n type: 'object',\n fields: [\n defineField({\n name: 'key',\n title: 'Attribute Name',\n type: 'string',\n }),\n defineField({\n name: 'type',\n title: 'Attribute Value Type',\n type: 'string',\n options: {\n list: [\n {title: 'String', value: 'string'},\n {title: 'Image', value: 'image'},\n ],\n },\n initialValue: 'string',\n }),\n defineField({\n name: 'value',\n title: 'Attribute Value',\n type: 'string',\n hidden: ({parent}) => parent?.type === 'image',\n }),\n defineField({\n name: 'image',\n title: 'Attribute Image Value',\n type: 'image',\n hidden: ({parent}) => parent?.type === 'string',\n }),\n ],\n preview: {\n select: {\n attributeName: 'key',\n attributeValueString: 'value',\n attributeValueImage: 'image',\n },\n prepare({attributeName, attributeValueString, attributeValueImage}) {\n let subtitle = ''\n if (attributeValueString) {\n subtitle = `Value: ${attributeValueString}`\n } else if (attributeValueImage) {\n subtitle = 'Value: [Image]'\n } else {\n subtitle = 'No Attribute Value'\n }\n return {\n title: attributeName || 'No Attribute Name',\n subtitle: subtitle,\n media: attributeValueImage,\n }\n },\n },\n})\n","import {defineType} from 'sanity'\n\nexport default defineType({\n name: 'metaTag',\n title: 'Meta Tag',\n type: 'object',\n fields: [\n {\n name: 'metaAttributes',\n title: 'Meta Attributes',\n type: 'array',\n of: [{type: 'metaAttribute'}],\n description:\n 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',\n },\n ],\n})\n","import {defineField, defineType} from 'sanity'\n\nexport default defineType({\n name: 'robots',\n title: 'Robots Settings',\n type: 'object',\n fields: [\n defineField({\n name: 'noIndex',\n title: 'No Index',\n type: 'boolean',\n initialValue: false,\n description:\n 'Enable this to prevent search engines from indexing this page. The page will not appear in search results.',\n }),\n defineField({\n name: 'noFollow',\n title: 'No Follow',\n type: 'boolean',\n initialValue: false,\n description:\n 'Enable this to prevent search engines from following links on this page. Links will not pass SEO value.',\n }),\n ],\n description: 'Select how search engines should index and follow links on this page.',\n})\n","import {SchemaTypeDefinition} from 'sanity'\n\nimport {SeoFieldsPluginConfig} from '../../plugin'\nimport seoFields from '..'\nimport metaAttribute from './metaAttribute'\nimport metaTag from './metaTag'\nimport openGraph from './openGraph'\nimport robots from './robots'\nimport twitter from './twitter'\n\nexport default function types(config: SeoFieldsPluginConfig = {}): SchemaTypeDefinition[] {\n return [\n seoFields(config), // pass config here\n openGraph(config), // pass config here\n twitter(config), // pass config here\n metaAttribute as SchemaTypeDefinition,\n metaTag,\n robots,\n ]\n}\n","import React from 'react'\nimport type {ComponentBuilder, StructureBuilder} from 'sanity/structure'\n\nimport SeoHealthDashboard, {SeoHealthDashboardProps} from './SeoHealthDashboard'\n\n/**\n * Options accepted by `createSeoHealthPane`.\n * All props from `SeoHealthDashboardProps` are supported.\n *\n * `licenseKey` is **required** — the dashboard will not render without it.\n */\nexport interface SeoHealthPaneOptions extends Omit<SeoHealthDashboardProps, 'customQuery'> {\n /** Required license key (format: `SEOF-XXXX-XXXX-XXXX`). */\n licenseKey: string\n /**\n * A fully custom GROQ query used to fetch documents for the dashboard.\n * The query must return documents with at least: `_id`, `_type`, `title`, `seo`, `_updatedAt`.\n *\n * Takes precedence over `queryTypes` when both are provided.\n *\n * @example\n * query: `*[_type in [\"post\",\"page\"] && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`\n */\n query?: string\n}\n\n// function isStructureBuilder(arg: unknown): arg is StructureBuilder {\n// return (\n// arg !== null &&\n// typeof arg === 'object' &&\n// typeof (arg as StructureBuilder).component === 'function' &&\n// typeof (arg as StructureBuilder).document === 'function'\n// )\n// }\n\n/**\n * Creates a desk-structure pane for the SEO Health Dashboard.\n *\n * Returns a **`ComponentBuilder`** with a built-in `.child()` resolver so that\n * clicking any document row opens the document editor as a split pane to the right.\n *\n * Use it **directly** as the `.child()` value — do **not** wrap it in `S.component()`.\n *\n * ```ts\n * // sanity.config.ts\n * structure: (S) =>\n * S.list().items([\n * S.listItem()\n * .title('SEO Health')\n * .child(\n * createSeoHealthPane(S, {\n * licenseKey: 'SEOF-XXXX-XXXX-XXXX',\n * query: `*[_type == \"post\" && defined(seo)]{ _id, _type, title, slug, seo, _updatedAt }`,\n * })\n * ),\n * ])\n * ```\n */\nexport function createSeoHealthPane(\n optionsOrS: StructureBuilder,\n optionsWhenS: SeoHealthPaneOptions,\n): ComponentBuilder {\n // ── Two-arg form: structure builder passed as first arg ──────────────────\n const S = optionsOrS\n const {query, openInPane = true, title: paneTitle, ...rest} = optionsWhenS ?? {}\n\n const SeoHealthPane: React.FC = () => (\n <SeoHealthDashboard customQuery={query} openInPane={openInPane} title={paneTitle} {...rest} />\n )\n SeoHealthPane.displayName = 'SeoHealthPane'\n\n // Wire up the child resolver so ChildLink URLs resolve to the document editor\n return (S.component(SeoHealthPane) as ComponentBuilder)\n .title(paneTitle ?? 'SEO Health')\n .child((docId: string, {params}: {params: Record<string, string | undefined>}) => {\n const builder = S.document().documentId(docId)\n return params?.type ? builder.schemaType(params.type) : builder\n })\n}\n\nexport default createSeoHealthPane\n","// Import the plugin\nimport seofields from './plugin'\n\n// Default export the plugin\nexport default seofields\n\n// Re-export everything from plugin.ts\nexport * from './plugin'\n\n// Export schema types for external use\nexport {default as seoFieldsSchema} from './schemas'\nexport {default as allSchemas} from './schemas/types'\nexport {default as metaAttributeSchema} from './schemas/types/metaAttribute'\nexport {default as metaTagSchema} from './schemas/types/metaTag'\nexport {default as openGraphSchema} from './schemas/types/openGraph'\nexport {default as robotsSchema} from './schemas/types/robots'\nexport {default as twitterSchema} from './schemas/types/twitter'\n\n// Export dashboard components and types\nexport {default as SeoHealthDashboard} from './components/SeoHealthDashboard'\nexport type {SeoHealthPaneOptions} from './components/SeoHealthPane'\nexport {createSeoHealthPane} from './components/SeoHealthPane'\nexport {default as SeoHealthTool} from './components/SeoHealthTool'\n\n// Export types\nexport type {DocumentWithSeoHealth, SeoHealthMetrics, SeoHealthStatus} from './types'\n"],"mappings":"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","names":["React","openGraph","twitter","types","jsx","defineField","defineType","useMemo","jsx","jsxs","useMemo","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","useFormValue","styled","jsx","jsxs","styled","useFormValue","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","defineField","defineType","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","Stack","Text","useMemo","useFormValue","jsx","jsxs","useFormValue","useMemo","Stack","Text","defineType","defineField","defineType","defineField","defineField","defineType","defineType","defineField","defineType","React","jsx"]}