sanity-plugin-seofields 1.0.6 → 1.0.7

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://badge.fury.io/js/sanity-plugin-seofields.svg)](https://badge.fury.io/js/sanity-plugin-seofields)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- A comprehensive Sanity Studio v3 plugin to manage SEO fields like meta titles, descriptions, Open Graph tags, and Twitter Cards for structured, search-optimized content.
6
+ A comprehensive Sanity Studio v3 plugin to manage SEO fields like meta titles, descriptions, Open Graph tags, and X (Formerly Twitter) Cards for structured, search-optimized content.
7
7
 
8
8
  ## ✨ Features
9
9
 
@@ -264,7 +264,7 @@ seofields({
264
264
  ```
265
265
 
266
266
  This is particularly useful when you want to:
267
- - Manage sitewide settings (like site name and Twitter handle) in a dedicated Site Settings document
267
+ - Manage sitewide settings (like site name and X handle) in a dedicated Site Settings document
268
268
  - Simplify the editing experience by hiding fields that aren't relevant for certain content types
269
269
  - Create different SEO workflows for different content types
270
270
 
@@ -302,12 +302,12 @@ This is particularly useful when you want to:
302
302
  - **Large Image**: Minimum 280x150px
303
303
  - **Required**: Alt text for accessibility
304
304
 
305
- #### Twitter Card Creator
305
+ #### X (Formerly Twitter) Card Creator
306
306
 
307
- - **Purpose**: Attribution to content creator on Twitter
308
- - **Format**: Twitter handle with @ symbol (e.g., @creator)
307
+ - **Purpose**: Attribution to content creator on X (formerly Twitter)
308
+ - **Format**: X handle with @ symbol (e.g., @creator)
309
309
  - **Usage**: Identifies the individual author of the content
310
- - **Best Practice**: Use actual Twitter handles for proper attribution
310
+ - **Best Practice**: Use actual X handles for proper attribution
311
311
 
312
312
  ## 💻 TypeScript Usage
313
313
 
package/dist/index.d.mts CHANGED
@@ -2,9 +2,15 @@ import {ObjectDefinition} from 'sanity'
2
2
  import {Plugin as Plugin_2} from 'sanity'
3
3
  import {PreviewConfig} from 'sanity'
4
4
 
5
- export declare type AllFieldKeys = SeoFieldKeys | SitewideFieldKeys
5
+ export declare type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys
6
6
 
7
7
  export declare function allSchemas(config?: SeoFieldsPluginConfig): (
8
+ | ({
9
+ type: 'object'
10
+ name: 'twitter'
11
+ } & Omit<ObjectDefinition, 'preview'> & {
12
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
13
+ })
8
14
  | ({
9
15
  type: 'object'
10
16
  name: 'seoFields'
@@ -36,12 +42,6 @@ export declare function allSchemas(config?: SeoFieldsPluginConfig): (
36
42
  } & Omit<ObjectDefinition, 'preview'> & {
37
43
  preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
38
44
  })
39
- | ({
40
- type: 'object'
41
- name: 'twitter'
42
- } & Omit<ObjectDefinition, 'preview'> & {
43
- preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
44
- })
45
45
  | ({
46
46
  type: 'object'
47
47
  name: 'robots'
@@ -106,6 +106,16 @@ export declare const metaTagSchema: {
106
106
  preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
107
107
  }
108
108
 
109
+ export declare type openGraphFieldKeys =
110
+ | 'openGraphUrl'
111
+ | 'openGraphTitle'
112
+ | 'openGraphDescription'
113
+ | 'openGraphSiteName'
114
+ | 'openGraphType'
115
+ | 'openGraphImageType'
116
+ | 'openGraphImage'
117
+ | 'openGraphImageUrl'
118
+
109
119
  export declare function openGraphSchema(config?: SeoFieldsPluginConfig): {
110
120
  type: 'object'
111
121
  name: 'openGraph'
@@ -120,7 +130,7 @@ export declare interface OpenGraphSettings {
120
130
  siteName?: string
121
131
  type?: 'website' | 'article' | 'profile' | 'book' | 'music' | 'video' | 'product'
122
132
  imageType?: 'upload' | 'url'
123
- image?: SanityImage
133
+ image?: SanityImageWithAlt
124
134
  imageUrl?: string
125
135
  }
126
136
 
@@ -192,14 +202,52 @@ declare const seofields: Plugin_2<void | SeoFieldsPluginConfig>
192
202
  export default seofields
193
203
 
194
204
  export declare interface SeoFieldsPluginConfig {
195
- seoPreview?: boolean
205
+ /**
206
+ * Enable or configure the SEO preview feature.
207
+ * If set to `true`, the SEO preview will be enabled with default settings.
208
+ * If set to an object, you can provide a custom prefix function to modify the URL prefix in the preview.
209
+ * The prefix function receives the current document as an argument and should return a string.
210
+ * Example:
211
+ * ```
212
+ * seoPreview: {
213
+ * prefix: (doc) => `/${doc.slug?.current || 'untitled'}`
214
+ * }
215
+ * ```
216
+ */
217
+ seoPreview?:
218
+ | boolean
219
+ | {
220
+ prefix?: (
221
+ doc: {
222
+ _type?: string
223
+ } & Record<string, unknown>,
224
+ ) => string
225
+ }
226
+ /**
227
+ * A mapping of field keys to their configuration settings.
228
+ * This allows customization of field titles and descriptions.
229
+ * For example, to change the title of the 'title' field:
230
+ */
196
231
  fieldOverrides?: {
197
- [key in SeoFieldKeys]?: SeoFieldConfig
232
+ [key in AllFieldKeys]?: SeoFieldConfig
198
233
  }
234
+ /**
235
+ * A mapping of document types to field visibility configurations.
236
+ * This allows you to specify which fields should be hidden for specific document types.
237
+ */
199
238
  fieldVisibility?: {
200
239
  [postType: string]: FieldVisibilityConfig
201
240
  }
241
+ /**
242
+ * A list of fields that should be hidden by default in all document types.
243
+ * This can be overridden by specific document type settings in `fieldVisibility`.
244
+ */
202
245
  defaultHiddenFields?: AllFieldKeys[]
246
+ /**
247
+ * The base URL of your website, used for generating full URLs in the SEO preview.
248
+ * Defaults to 'https://www.example.com' if not provided.
249
+ */
250
+ baseUrl?: string
203
251
  }
204
252
 
205
253
  export declare function seoFieldsSchema(config?: SeoFieldsPluginConfig): {
@@ -232,17 +280,27 @@ export declare interface SeoValidationRules {
232
280
  }
233
281
  }
234
282
 
235
- export declare type SitewideFieldKeys = 'openGraphSiteName' | 'twitterSite'
236
-
237
283
  export declare interface TwitterCardSettings {
238
284
  _type: 'twitter'
239
285
  card?: 'summary' | 'summary_large_image' | 'app' | 'player'
240
286
  site?: string
241
287
  title?: string
242
288
  description?: string
289
+ imageType?: 'upload' | 'url'
243
290
  image?: SanityImageWithAlt
291
+ imageUrl?: string
244
292
  }
245
293
 
294
+ export declare type twitterFieldKeys =
295
+ | 'twitterCard'
296
+ | 'twitterSite'
297
+ | 'twitterCreator'
298
+ | 'twitterTitle'
299
+ | 'twitterDescription'
300
+ | 'twitterImageType'
301
+ | 'twitterImage'
302
+ | 'twitterImageUrl'
303
+
246
304
  export declare function twitterSchema(config?: SeoFieldsPluginConfig): {
247
305
  type: 'object'
248
306
  name: 'twitter'
package/dist/index.d.ts CHANGED
@@ -2,9 +2,15 @@ import {ObjectDefinition} from 'sanity'
2
2
  import {Plugin as Plugin_2} from 'sanity'
3
3
  import {PreviewConfig} from 'sanity'
4
4
 
5
- export declare type AllFieldKeys = SeoFieldKeys | SitewideFieldKeys
5
+ export declare type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys
6
6
 
7
7
  export declare function allSchemas(config?: SeoFieldsPluginConfig): (
8
+ | ({
9
+ type: 'object'
10
+ name: 'twitter'
11
+ } & Omit<ObjectDefinition, 'preview'> & {
12
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
13
+ })
8
14
  | ({
9
15
  type: 'object'
10
16
  name: 'seoFields'
@@ -36,12 +42,6 @@ export declare function allSchemas(config?: SeoFieldsPluginConfig): (
36
42
  } & Omit<ObjectDefinition, 'preview'> & {
37
43
  preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
38
44
  })
39
- | ({
40
- type: 'object'
41
- name: 'twitter'
42
- } & Omit<ObjectDefinition, 'preview'> & {
43
- preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
44
- })
45
45
  | ({
46
46
  type: 'object'
47
47
  name: 'robots'
@@ -106,6 +106,16 @@ export declare const metaTagSchema: {
106
106
  preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
107
107
  }
108
108
 
109
+ export declare type openGraphFieldKeys =
110
+ | 'openGraphUrl'
111
+ | 'openGraphTitle'
112
+ | 'openGraphDescription'
113
+ | 'openGraphSiteName'
114
+ | 'openGraphType'
115
+ | 'openGraphImageType'
116
+ | 'openGraphImage'
117
+ | 'openGraphImageUrl'
118
+
109
119
  export declare function openGraphSchema(config?: SeoFieldsPluginConfig): {
110
120
  type: 'object'
111
121
  name: 'openGraph'
@@ -120,7 +130,7 @@ export declare interface OpenGraphSettings {
120
130
  siteName?: string
121
131
  type?: 'website' | 'article' | 'profile' | 'book' | 'music' | 'video' | 'product'
122
132
  imageType?: 'upload' | 'url'
123
- image?: SanityImage
133
+ image?: SanityImageWithAlt
124
134
  imageUrl?: string
125
135
  }
126
136
 
@@ -192,14 +202,52 @@ declare const seofields: Plugin_2<void | SeoFieldsPluginConfig>
192
202
  export default seofields
193
203
 
194
204
  export declare interface SeoFieldsPluginConfig {
195
- seoPreview?: boolean
205
+ /**
206
+ * Enable or configure the SEO preview feature.
207
+ * If set to `true`, the SEO preview will be enabled with default settings.
208
+ * If set to an object, you can provide a custom prefix function to modify the URL prefix in the preview.
209
+ * The prefix function receives the current document as an argument and should return a string.
210
+ * Example:
211
+ * ```
212
+ * seoPreview: {
213
+ * prefix: (doc) => `/${doc.slug?.current || 'untitled'}`
214
+ * }
215
+ * ```
216
+ */
217
+ seoPreview?:
218
+ | boolean
219
+ | {
220
+ prefix?: (
221
+ doc: {
222
+ _type?: string
223
+ } & Record<string, unknown>,
224
+ ) => string
225
+ }
226
+ /**
227
+ * A mapping of field keys to their configuration settings.
228
+ * This allows customization of field titles and descriptions.
229
+ * For example, to change the title of the 'title' field:
230
+ */
196
231
  fieldOverrides?: {
197
- [key in SeoFieldKeys]?: SeoFieldConfig
232
+ [key in AllFieldKeys]?: SeoFieldConfig
198
233
  }
234
+ /**
235
+ * A mapping of document types to field visibility configurations.
236
+ * This allows you to specify which fields should be hidden for specific document types.
237
+ */
199
238
  fieldVisibility?: {
200
239
  [postType: string]: FieldVisibilityConfig
201
240
  }
241
+ /**
242
+ * A list of fields that should be hidden by default in all document types.
243
+ * This can be overridden by specific document type settings in `fieldVisibility`.
244
+ */
202
245
  defaultHiddenFields?: AllFieldKeys[]
246
+ /**
247
+ * The base URL of your website, used for generating full URLs in the SEO preview.
248
+ * Defaults to 'https://www.example.com' if not provided.
249
+ */
250
+ baseUrl?: string
203
251
  }
204
252
 
205
253
  export declare function seoFieldsSchema(config?: SeoFieldsPluginConfig): {
@@ -232,17 +280,27 @@ export declare interface SeoValidationRules {
232
280
  }
233
281
  }
234
282
 
235
- export declare type SitewideFieldKeys = 'openGraphSiteName' | 'twitterSite'
236
-
237
283
  export declare interface TwitterCardSettings {
238
284
  _type: 'twitter'
239
285
  card?: 'summary' | 'summary_large_image' | 'app' | 'player'
240
286
  site?: string
241
287
  title?: string
242
288
  description?: string
289
+ imageType?: 'upload' | 'url'
243
290
  image?: SanityImageWithAlt
291
+ imageUrl?: string
244
292
  }
245
293
 
294
+ export declare type twitterFieldKeys =
295
+ | 'twitterCard'
296
+ | 'twitterSite'
297
+ | 'twitterCreator'
298
+ | 'twitterTitle'
299
+ | 'twitterDescription'
300
+ | 'twitterImageType'
301
+ | 'twitterImage'
302
+ | 'twitterImageUrl'
303
+
246
304
  export declare function twitterSchema(config?: SeoFieldsPluginConfig): {
247
305
  type: 'object'
248
306
  name: 'twitter'
package/dist/index.js CHANGED
@@ -227,13 +227,13 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
227
227
  ] }, item.text)) })
228
228
  ] });
229
229
  }, SeoPreview = (props) => {
230
- const { path } = props, parent = sanity.useFormValue([path[0]]) || {
230
+ const { path, schemaType } = props, { options } = schemaType, baseUrl = options?.baseUrl || "https://www.example.com", prefixFunction = options?.prefix, parent = sanity.useFormValue([path[0]]) || {
231
231
  title: "",
232
232
  description: "",
233
233
  canonicalUrl: ""
234
- };
235
- console.log("SEO Preview Parent:", parent);
236
- const {
234
+ }, rootDoc = sanity.useFormValue([]) || {
235
+ slug: { current: "" }
236
+ }, slug = rootDoc?.slug?.current || "", {
237
237
  title,
238
238
  description,
239
239
  canonicalUrl: url
@@ -247,7 +247,22 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
247
247
  fontFamily: "Arial, sans-serif"
248
248
  },
249
249
  children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
250
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { color: "#006621", fontSize: 12, lineHeight: 1.3, marginBottom: 3 }, children: url || "https://www.example.com/page-url" }),
250
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { color: "#006621", fontSize: 12, lineHeight: 1.3, marginBottom: 3 }, children: (() => {
251
+ const base = (url || baseUrl)?.replace(/\/+$/, ""), slugStr = String(slug || "").replace(/^\/+/, ""), path2 = [String(prefixFunction ? prefixFunction(rootDoc) : "").replace(
252
+ /^\/+|\/+$/g,
253
+ ""
254
+ ), slugStr].filter(Boolean).join("/"), finalUrl = path2 ? `${base}/${path2}` : base;
255
+ return /* @__PURE__ */ jsxRuntime.jsx(
256
+ "a",
257
+ {
258
+ href: finalUrl || "#",
259
+ target: "_blank",
260
+ rel: "noopener noreferrer",
261
+ style: { color: "inherit", textDecoration: "none" },
262
+ children: finalUrl || "https://www.example.com/page-url"
263
+ }
264
+ );
265
+ })() }),
251
266
  /* @__PURE__ */ jsxRuntime.jsx(
252
267
  ui.Text,
253
268
  {
@@ -305,6 +320,70 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
305
320
  metaAttributes: {
306
321
  title: "Additional Meta Attributes",
307
322
  description: "Add custom meta attributes to the head of the document for additional SEO and social media integration."
323
+ },
324
+ openGraphTitle: {
325
+ title: "Open Graph Title",
326
+ description: ""
327
+ },
328
+ openGraphUrl: {
329
+ title: "Open Graph URL",
330
+ description: "The canonical URL of the page. This should be the full URL including protocol (https://)."
331
+ },
332
+ openGraphDescription: {
333
+ title: "Open Graph Description",
334
+ description: ""
335
+ },
336
+ openGraphSiteName: {
337
+ title: "Open Graph Site Name",
338
+ description: "The name of your website. This is often the site title."
339
+ },
340
+ openGraphType: {
341
+ title: "Open Graph Type",
342
+ description: "Select the type of content for Open Graph."
343
+ },
344
+ openGraphImageType: {
345
+ title: "Image Type",
346
+ description: "Choose whether to upload an image or provide an image URL for Open Graph."
347
+ },
348
+ openGraphImage: {
349
+ title: "Open Graph Image",
350
+ description: "Recommended size: 1200x630px (minimum 600x315px). Max file size: 5MB. Aspect ratio 1.91:1."
351
+ },
352
+ openGraphImageUrl: {
353
+ title: "Open Graph Image URL",
354
+ description: "Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px)."
355
+ },
356
+ twitterCard: {
357
+ title: "Card Type",
358
+ description: ""
359
+ },
360
+ twitterSite: {
361
+ title: "Site X Handle",
362
+ description: "The X (formerly Twitter) handle of the website (e.g., @example)"
363
+ },
364
+ twitterCreator: {
365
+ title: "X Creator Handle",
366
+ description: "The X (formerly Twitter) handle of the content creator (e.g., @creator)"
367
+ },
368
+ twitterTitle: {
369
+ title: "X Title",
370
+ description: "The title of the content as it should appear on X (formerly Twitter)."
371
+ },
372
+ twitterDescription: {
373
+ title: "X Description",
374
+ description: "A brief description of the content for X (formerly Twitter)."
375
+ },
376
+ twitterImageType: {
377
+ title: "X Image Type",
378
+ description: "Choose whether to upload an image or provide an image URL for X (formerly Twitter)."
379
+ },
380
+ twitterImage: {
381
+ title: "X Image",
382
+ description: 'An image URL which should be at least 120x120px for "summary" card and 280x150px for "summary_large_image" card.'
383
+ },
384
+ twitterImageUrl: {
385
+ title: "X Image URL",
386
+ description: "Enter the full URL of the image for X (formerly Twitter). Ensure the image is accessible and meets the recommended size."
308
387
  }
309
388
  }, getFieldInfo = (fieldName, fieldOverrides) => {
310
389
  const fieldInfo = fieldOverrides && fieldOverrides[fieldName] || DEFAULT_FIELD_INFO[fieldName];
@@ -312,7 +391,7 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
312
391
  }, isFieldHidden = (fieldName, config, documentType) => !!(config.defaultHiddenFields?.includes(fieldName) || documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)), getFieldHiddenFunction = (fieldName, config) => ({ document }) => {
313
392
  const documentType = document?._type;
314
393
  return isFieldHidden(fieldName, config, documentType);
315
- };
394
+ }, isEmpty = (value) => value == null || typeof value == "string" && value.trim() === "" || Array.isArray(value) && value.length === 0 || typeof value == "object" && !Array.isArray(value) && Object.keys(value).length === 0;
316
395
  function seoFieldsSchema(config = {}) {
317
396
  return sanity.defineType({
318
397
  name: "seoFields",
@@ -327,15 +406,23 @@ function seoFieldsSchema(config = {}) {
327
406
  hidden: getFieldHiddenFunction("robots", config)
328
407
  }),
329
408
  // 👇 conditionally spread preview field
330
- ...config.seoPreview ? [] : [
409
+ ...typeof config.seoPreview == "boolean" && config.seoPreview || typeof config.seoPreview == "object" && !isEmpty(config.seoPreview) ? [
331
410
  sanity.defineField({
332
411
  name: "preview",
333
412
  title: "SEO Preview",
334
413
  type: "string",
335
414
  components: { input: SeoPreview },
415
+ options: {
416
+ baseUrl: config.baseUrl || "https://www.example.com",
417
+ ...typeof config.seoPreview == "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}
418
+ },
419
+ // Use a readOnly field to prevent editing
420
+ // This field is just for preview purposes
421
+ initialValue: {},
422
+ // TypeScript workaround
336
423
  readOnly: !0
337
424
  })
338
- ],
425
+ ] : [],
339
426
  sanity.defineField({
340
427
  name: "title",
341
428
  ...getFieldInfo("title", config.fieldOverrides),
@@ -522,14 +609,16 @@ function openGraph(config = {}) {
522
609
  fields: [
523
610
  sanity.defineField({
524
611
  name: "url",
525
- title: "Open Graph URL",
526
612
  type: "url",
613
+ ...getFieldInfo("openGraphUrl", config.fieldOverrides),
614
+ hidden: getFieldHiddenFunction("openGraphUrl", config),
527
615
  description: "The canonical URL of the page. This should be the full URL including protocol (https://)."
528
616
  }),
529
617
  sanity.defineField({
530
618
  name: "title",
531
- title: "Open Graph Title",
619
+ ...getFieldInfo("openGraphTitle", config.fieldOverrides),
532
620
  type: "string",
621
+ hidden: getFieldHiddenFunction("openGraphTitle", config),
533
622
  components: {
534
623
  input: OgTitle
535
624
  // Can also wrap with a string input + preview
@@ -537,9 +626,10 @@ function openGraph(config = {}) {
537
626
  }),
538
627
  sanity.defineField({
539
628
  name: "description",
540
- title: "Open Graph Description",
629
+ ...getFieldInfo("openGraphDescription", config.fieldOverrides),
541
630
  type: "text",
542
631
  rows: 3,
632
+ hidden: getFieldHiddenFunction("openGraphDescription", config),
543
633
  components: {
544
634
  input: OgDescription
545
635
  // Can also wrap with a text area + preview
@@ -547,14 +637,13 @@ function openGraph(config = {}) {
547
637
  }),
548
638
  sanity.defineField({
549
639
  name: "siteName",
550
- title: "Open Graph Site Name",
640
+ ...getFieldInfo("openGraphSiteName", config.fieldOverrides),
551
641
  type: "string",
552
- description: "The name of your website. This is often the site title.",
553
642
  hidden: getFieldHiddenFunction("openGraphSiteName", config)
554
643
  }),
555
644
  sanity.defineField({
556
645
  name: "type",
557
- title: "Open Graph Type",
646
+ ...getFieldInfo("openGraphType", config.fieldOverrides),
558
647
  type: "string",
559
648
  options: {
560
649
  list: [
@@ -568,13 +657,12 @@ function openGraph(config = {}) {
568
657
  ]
569
658
  // layout: 'radio', // Display as radio buttons
570
659
  },
571
- initialValue: "website",
572
- description: "Select the type of content for Open Graph."
660
+ hidden: getFieldHiddenFunction("openGraphType", config),
661
+ initialValue: "website"
573
662
  }),
574
- // upload image or ask for url
575
663
  sanity.defineField({
576
664
  name: "imageType",
577
- title: "Image Type",
665
+ ...getFieldInfo("openGraphImageType", config.fieldOverrides),
578
666
  type: "string",
579
667
  options: {
580
668
  list: [
@@ -582,24 +670,31 @@ function openGraph(config = {}) {
582
670
  { title: "Image URL", value: "url" }
583
671
  ]
584
672
  },
673
+ hidden: getFieldHiddenFunction("openGraphImage", config),
585
674
  initialValue: "upload"
586
675
  }),
587
676
  sanity.defineField({
588
677
  name: "image",
589
- title: "Open Graph Image",
678
+ ...getFieldInfo("openGraphImage", config.fieldOverrides),
590
679
  type: "image",
591
680
  options: {
592
681
  hotspot: !0
593
682
  },
594
- hidden: ({ parent }) => parent?.imageType !== "upload",
595
- description: "Recommended size: 1200x630px (minimum 600x315px). Max file size: 5MB. Aspect ratio 1.91:1."
683
+ fields: [
684
+ sanity.defineField({
685
+ name: "alt",
686
+ title: "Image Alt Text",
687
+ type: "string",
688
+ description: "A description of the image for accessibility purposes."
689
+ })
690
+ ],
691
+ hidden: ({ parent }) => parent?.imageType !== "upload"
596
692
  }),
597
693
  sanity.defineField({
598
694
  name: "imageUrl",
599
- title: "Open Graph Image URL",
695
+ ...getFieldInfo("openGraphImageUrl", config.fieldOverrides),
600
696
  type: "url",
601
- hidden: ({ parent }) => parent?.imageType !== "url",
602
- description: "Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px)."
697
+ hidden: ({ parent }) => parent?.imageType !== "url"
603
698
  })
604
699
  ]
605
700
  });
@@ -657,7 +752,7 @@ function twitter(config = {}) {
657
752
  fields: [
658
753
  sanity.defineField({
659
754
  name: "card",
660
- title: "Card Type",
755
+ ...getFieldInfo("twitterCard", config.fieldOverrides),
661
756
  type: "string",
662
757
  options: {
663
758
  list: [
@@ -667,46 +762,58 @@ function twitter(config = {}) {
667
762
  { title: "Player", value: "player" }
668
763
  ]
669
764
  },
765
+ hidden: getFieldHiddenFunction("twitterCard", config),
670
766
  initialValue: "summary_large_image"
671
767
  // good default
672
768
  }),
673
769
  sanity.defineField({
674
770
  name: "site",
675
- title: "Site X Handle",
771
+ ...getFieldInfo("twitterSite", config.fieldOverrides),
676
772
  type: "string",
677
- description: "The X (formerly Twitter) handle of the website (e.g., @example)",
678
773
  hidden: getFieldHiddenFunction("twitterSite", config)
679
774
  }),
680
775
  sanity.defineField({
681
776
  name: "creator",
682
- title: "X Creator Handle",
683
777
  type: "string",
684
- description: "The X (formerly Twitter) handle of the content creator (e.g., @creator)"
778
+ ...getFieldInfo("twitterCreator", config.fieldOverrides),
779
+ hidden: getFieldHiddenFunction("twitterCreator", config)
685
780
  }),
686
781
  sanity.defineField({
687
782
  name: "title",
688
- title: "X Title",
689
783
  type: "string",
690
- description: "The title of the content as it should appear on X (formerly Twitter).",
784
+ ...getFieldInfo("twitterTitle", config.fieldOverrides),
785
+ hidden: getFieldHiddenFunction("twitterTitle", config),
691
786
  components: {
692
787
  input: TwitterTitle
693
788
  }
694
789
  }),
695
790
  sanity.defineField({
696
791
  name: "description",
697
- title: "X Description",
698
792
  type: "text",
699
793
  rows: 3,
700
- description: "A brief description of the content for X (formerly Twitter).",
794
+ ...getFieldInfo("twitterDescription", config.fieldOverrides),
795
+ hidden: getFieldHiddenFunction("twitterDescription", config),
701
796
  components: {
702
797
  input: TwitterDescription
703
798
  }
704
799
  }),
800
+ sanity.defineField({
801
+ name: "imageType",
802
+ ...getFieldInfo("twitterImageType", config.fieldOverrides),
803
+ type: "string",
804
+ options: {
805
+ list: [
806
+ { title: "Upload Image", value: "upload" },
807
+ { title: "Image URL", value: "url" }
808
+ ]
809
+ },
810
+ hidden: getFieldHiddenFunction("twitterImage", config),
811
+ initialValue: "upload"
812
+ }),
705
813
  sanity.defineField({
706
814
  name: "image",
707
- title: "X Image",
815
+ ...getFieldInfo("twitterImage", config.fieldOverrides),
708
816
  type: "image",
709
- description: 'An image URL which should be at least 120x120px for "summary" card and 280x150px for "summary_large_image" card.',
710
817
  options: {
711
818
  hotspot: !0
712
819
  },
@@ -715,9 +822,15 @@ function twitter(config = {}) {
715
822
  name: "alt",
716
823
  title: "Image Alt Text",
717
824
  type: "string",
718
- description: "Short alt text describing the image"
825
+ description: "A description of the image for accessibility purposes."
719
826
  })
720
827
  ]
828
+ }),
829
+ sanity.defineField({
830
+ name: "imageUrl",
831
+ ...getFieldInfo("twitterImageUrl", config.fieldOverrides),
832
+ type: "url",
833
+ hidden: ({ parent }) => parent?.imageType !== "url"
721
834
  })
722
835
  ]
723
836
  });