sanity-plugin-seofields 1.0.8 → 1.0.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), react = require("react"), ui = require("@sanity/ui");
3
+ var sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), react = require("react");
4
4
  const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (title, keywordList) => {
5
5
  if (!title || keywordList.length === 0) return !1;
6
6
  const lowerTitle = title.toLowerCase();
@@ -17,7 +17,7 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
17
17
  if (!title) return !1;
18
18
  const firstWord = title.trim().split(" ")[0].toLowerCase();
19
19
  return stopWords.includes(firstWord);
20
- }, truncate = (text, maxLength) => text.length > maxLength ? text.slice(0, maxLength) + "\u2026" : text, hasExcessivePunctuation = (title) => /[!@#$%^&*]{2,}/.test(title), getMetaTitleValidationMessages = (title, keywords, isParentseoField) => {
20
+ }, truncate = (text, maxLength) => text.length > maxLength ? `${text.slice(0, maxLength)}\u2026` : text, hasExcessivePunctuation = (title) => /[!@#$%^&*]{2,}/.test(title), getMetaTitleValidationMessages = (title, keywords, isParentseoField) => {
21
21
  const feedback = [], charCount = title?.length || 0;
22
22
  if (!title?.trim())
23
23
  return feedback.push({ text: "Meta Title is empty. Add content to improve SEO.", color: "red" }), feedback;
@@ -185,10 +185,9 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
185
185
  text: "X Description has excessive punctuation \u2014 simplify it.",
186
186
  color: "orange"
187
187
  }), feedback;
188
- }, MetaTitle = (props) => {
189
- sanity.useClient({ apiVersion: "2024-05-05" });
190
- const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
191
- () => getMetaTitleValidationMessages(value || "", keywords, isParentseoField),
188
+ }, MetaDescription = (props) => {
189
+ const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
190
+ () => getMetaDescriptionValidationMessages(value || "", keywords, isParentseoField),
192
191
  [value, keywords, isParentseoField]
193
192
  );
194
193
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
@@ -197,21 +196,15 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
197
196
  /* @__PURE__ */ jsxRuntime.jsx(
198
197
  "div",
199
198
  {
200
- style: {
201
- minWidth: 10,
202
- height: 10,
203
- borderRadius: "50%",
204
- backgroundColor: item.color
205
- }
199
+ style: { width: 10, height: 10, borderRadius: "50%", backgroundColor: item.color }
206
200
  }
207
201
  ),
208
202
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
209
203
  ] }, item.text)) })
210
204
  ] });
211
- }, MetaDescription = (props) => {
212
- sanity.useClient({ apiVersion: "2024-05-05" });
213
- const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
214
- () => getMetaDescriptionValidationMessages(value || "", keywords, isParentseoField),
205
+ }, MetaTitle = (props) => {
206
+ const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
207
+ () => getMetaTitleValidationMessages(value || "", keywords, isParentseoField),
215
208
  [value, keywords, isParentseoField]
216
209
  );
217
210
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
@@ -220,7 +213,12 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
220
213
  /* @__PURE__ */ jsxRuntime.jsx(
221
214
  "div",
222
215
  {
223
- style: { width: 10, height: 10, borderRadius: "50%", backgroundColor: item.color }
216
+ style: {
217
+ minWidth: 10,
218
+ height: 10,
219
+ borderRadius: "50%",
220
+ backgroundColor: item.color
221
+ }
224
222
  }
225
223
  ),
226
224
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
@@ -248,10 +246,9 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
248
246
  },
249
247
  children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
250
248
  /* @__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;
249
+ const base = (url || baseUrl)?.replace(/\/+$/, ""), slugStr = String(slug || "").replace(/^\/+/, ""), urlPath = [String(
250
+ prefixFunction ? prefixFunction(rootDoc) : ""
251
+ ).replace(/^\/+|\/+$/g, ""), slugStr].filter(Boolean).join("/"), finalUrl = urlPath ? `${base}/${urlPath}` : base;
255
252
  return /* @__PURE__ */ jsxRuntime.jsx(
256
253
  "a",
257
254
  {
@@ -354,7 +351,7 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
354
351
  description: "Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px)."
355
352
  },
356
353
  twitterCard: {
357
- title: "Card Type",
354
+ title: "X Card Type",
358
355
  description: ""
359
356
  },
360
357
  twitterSite: {
@@ -387,179 +384,16 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
387
384
  }
388
385
  }, getFieldInfo = (fieldName, fieldOverrides) => {
389
386
  const fieldInfo = fieldOverrides && fieldOverrides[fieldName] || DEFAULT_FIELD_INFO[fieldName];
390
- return fieldInfo ? { title: fieldInfo.title, description: fieldInfo.description } : { title: "", description: "" };
391
- }, isFieldHidden = (fieldName, config, documentType) => !!(config.defaultHiddenFields?.includes(fieldName) || documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)), getFieldHiddenFunction = (fieldName, config) => ({ document }) => {
387
+ return fieldInfo ? { title: fieldInfo.title || "", description: fieldInfo.description || "" } : { title: "", description: "" };
388
+ }, isFieldHidden = (fieldName, config, documentType) => !!(config.defaultHiddenFields?.includes(fieldName) || documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)), getFieldHiddenFunction = (fieldName, config) => ({
389
+ document
390
+ }) => {
392
391
  const documentType = document?._type;
393
392
  return isFieldHidden(fieldName, config, documentType);
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;
395
- function seoFieldsSchema(config = {}) {
396
- return sanity.defineType({
397
- name: "seoFields",
398
- title: "SEO Fields",
399
- type: "object",
400
- fields: [
401
- sanity.defineField({
402
- name: "robots",
403
- title: "Robots Settings",
404
- type: "robots",
405
- // Use the separate robots type here
406
- hidden: getFieldHiddenFunction("robots", config)
407
- }),
408
- // 👇 conditionally spread preview field
409
- ...typeof config.seoPreview == "boolean" && config.seoPreview || typeof config.seoPreview == "object" && !isEmpty(config.seoPreview) ? [
410
- sanity.defineField({
411
- name: "preview",
412
- title: "SEO Preview",
413
- type: "string",
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
- // Set an initial value
423
- readOnly: !0
424
- })
425
- ] : [],
426
- sanity.defineField({
427
- name: "title",
428
- ...getFieldInfo("title", config.fieldOverrides),
429
- // title: 'Meta Title',
430
- type: "string",
431
- // description:
432
- // '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.',
433
- components: {
434
- input: MetaTitle
435
- },
436
- // validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),
437
- hidden: getFieldHiddenFunction("title", config)
438
- }),
439
- sanity.defineField({
440
- name: "description",
441
- ...getFieldInfo("description", config.fieldOverrides),
442
- // title: 'Meta Description',
443
- // description:
444
- // 'Provide a concise summary of the page content. This description may be used by search engines in search results.',
445
- type: "text",
446
- rows: 3,
447
- components: {
448
- input: MetaDescription
449
- },
450
- // validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),
451
- hidden: getFieldHiddenFunction("description", config)
452
- }),
453
- sanity.defineField({
454
- name: "metaImage",
455
- ...getFieldInfo("metaImage", config.fieldOverrides),
456
- // title: 'Meta Image',
457
- // description:
458
- // 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',
459
- type: "image",
460
- options: {
461
- hotspot: !0
462
- },
463
- hidden: getFieldHiddenFunction("metaImage", config)
464
- }),
465
- sanity.defineField({
466
- name: "metaAttributes",
467
- // title: 'Additional Meta Attributes',
468
- ...getFieldInfo("metaAttributes", config.fieldOverrides),
469
- type: "array",
470
- of: [{ type: "metaAttribute" }],
471
- // description:
472
- // 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',
473
- hidden: getFieldHiddenFunction("metaAttributes", config)
474
- }),
475
- sanity.defineField({
476
- name: "keywords",
477
- ...getFieldInfo("keywords", config.fieldOverrides),
478
- title: "Keywords",
479
- type: "array",
480
- of: [{ type: "string" }],
481
- description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
482
- hidden: getFieldHiddenFunction("keywords", config)
483
- }),
484
- sanity.defineField({
485
- name: "canonicalUrl",
486
- ...getFieldInfo("canonicalUrl", config.fieldOverrides),
487
- title: "Canonical URL",
488
- type: "url",
489
- description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
490
- hidden: getFieldHiddenFunction("canonicalUrl", config)
491
- }),
492
- sanity.defineField({
493
- name: "openGraph",
494
- title: "Open Graph Settings",
495
- type: "openGraph"
496
- }),
497
- sanity.defineField({
498
- name: "twitter",
499
- title: "X (Formerly Twitter) Card Settings",
500
- type: "twitter"
501
- })
502
- ]
503
- });
504
- }
505
- var metaAttribute = sanity.defineType({
506
- name: "metaAttribute",
507
- title: "Meta Attribute",
508
- type: "object",
509
- fields: [
510
- sanity.defineField({
511
- name: "key",
512
- title: "Attribute Name",
513
- type: "string"
514
- }),
515
- sanity.defineField({
516
- name: "type",
517
- title: "Attribute Value Type",
518
- type: "string",
519
- options: {
520
- list: [
521
- { title: "String", value: "string" },
522
- { title: "Image", value: "image" }
523
- ]
524
- },
525
- initialValue: "string"
526
- }),
527
- sanity.defineField({
528
- name: "value",
529
- title: "Attribute Value",
530
- type: "string",
531
- hidden: ({ parent }) => parent?.type === "image"
532
- }),
533
- sanity.defineField({
534
- name: "image",
535
- title: "Attribute Image Value",
536
- type: "image",
537
- hidden: ({ parent }) => parent?.type === "string"
538
- })
539
- ],
540
- preview: {
541
- select: {
542
- attributeName: "key",
543
- attributeValueString: "value",
544
- attributeValueImage: "image"
545
- },
546
- prepare({
547
- attributeName,
548
- attributeValueString,
549
- attributeValueImage
550
- }) {
551
- return {
552
- title: attributeName || "No Attribute Name",
553
- subtitle: attributeValueString ? `Value: ${attributeValueString}` : attributeValueImage ? "Value: [Image]" : "No Attribute Value",
554
- media: attributeValueImage
555
- };
556
- }
557
- }
558
- });
559
- const OgTitle = (props) => {
560
- const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
561
- () => getOgTitleValidation(value || "", keywords, isParentseoField),
562
- [value, keywords]
393
+ }, 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, OgDescription = (props) => {
394
+ const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
395
+ () => getOgDescriptionValidation(value || "", keywords, isParentseoField),
396
+ [value, keywords, isParentseoField]
563
397
  );
564
398
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
565
399
  renderDefault(props),
@@ -578,9 +412,9 @@ const OgTitle = (props) => {
578
412
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
579
413
  ] }, item.text)) })
580
414
  ] });
581
- }, OgDescription = (props) => {
582
- const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
583
- () => getOgDescriptionValidation(value || "", keywords, isParentseoField),
415
+ }, OgTitle = (props) => {
416
+ const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
417
+ () => getOgTitleValidation(value || "", keywords, isParentseoField),
584
418
  [value, keywords, isParentseoField]
585
419
  );
586
420
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
@@ -688,21 +522,31 @@ function openGraph(config = {}) {
688
522
  description: "A description of the image for accessibility purposes."
689
523
  })
690
524
  ],
691
- hidden: ({ parent }) => parent?.imageType !== "upload"
525
+ hidden: (context) => {
526
+ const { parent } = context;
527
+ if (parent?.imageType !== "upload") return !0;
528
+ const hiddenFn = getFieldHiddenFunction("openGraphImage", config);
529
+ return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
530
+ }
692
531
  }),
693
532
  sanity.defineField({
694
533
  name: "imageUrl",
695
534
  ...getFieldInfo("openGraphImageUrl", config.fieldOverrides),
696
535
  type: "url",
697
- hidden: ({ parent }) => parent?.imageType !== "url"
536
+ hidden: (context) => {
537
+ const { parent } = context;
538
+ if (parent?.imageType !== "url") return !0;
539
+ const hiddenFn = getFieldHiddenFunction("openGraphImage", config);
540
+ return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
541
+ }
698
542
  })
699
543
  ]
700
544
  });
701
545
  }
702
- const TwitterTitle = (props) => {
703
- const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
704
- () => getTwitterTitleValidation(value || "", keywords, isParentseoField),
705
- [value, keywords]
546
+ const TwitterDescription = (props) => {
547
+ const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
548
+ () => getTwitterDescriptionValidation(value || "", keywords, isParentseoField),
549
+ [value, keywords, isParentseoField]
706
550
  );
707
551
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
708
552
  renderDefault(props),
@@ -721,10 +565,10 @@ const TwitterTitle = (props) => {
721
565
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
722
566
  ] }, item.text)) })
723
567
  ] });
724
- }, TwitterDescription = (props) => {
725
- const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
726
- () => getTwitterDescriptionValidation(value || "", keywords, isParentseoField),
727
- [value, keywords]
568
+ }, TwitterTitle = (props) => {
569
+ const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
570
+ () => getTwitterTitleValidation(value || "", keywords, isParentseoField),
571
+ [value, keywords, isParentseoField]
728
572
  );
729
573
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
730
574
  renderDefault(props),
@@ -824,38 +668,180 @@ function twitter(config = {}) {
824
668
  type: "string",
825
669
  description: "A description of the image for accessibility purposes."
826
670
  })
827
- ]
671
+ ],
672
+ hidden: (context) => {
673
+ const { parent } = context;
674
+ if (parent?.imageType !== "upload") return !0;
675
+ const hiddenFn = getFieldHiddenFunction("twitterImage", config);
676
+ return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
677
+ }
828
678
  }),
829
679
  sanity.defineField({
830
680
  name: "imageUrl",
831
681
  ...getFieldInfo("twitterImageUrl", config.fieldOverrides),
832
682
  type: "url",
833
- hidden: ({ parent }) => parent?.imageType !== "url"
683
+ hidden: (context) => {
684
+ const { parent } = context;
685
+ if (parent?.imageType !== "url") return !0;
686
+ const hiddenFn = getFieldHiddenFunction("twitterImage", config);
687
+ return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
688
+ }
834
689
  })
835
690
  ]
836
691
  });
837
692
  }
838
- var robots = sanity.defineType({
839
- name: "robots",
840
- title: "Robots Settings",
693
+ function seoFieldsSchema(config = {}) {
694
+ return sanity.defineType({
695
+ name: "seoFields",
696
+ title: "SEO Fields",
697
+ type: "object",
698
+ fields: [
699
+ sanity.defineField({
700
+ name: "robots",
701
+ title: "Robots Settings",
702
+ type: "robots",
703
+ // Use the separate robots type here
704
+ hidden: getFieldHiddenFunction("robots", config)
705
+ }),
706
+ // 👇 conditionally spread preview field
707
+ ...typeof config.seoPreview == "boolean" && config.seoPreview || typeof config.seoPreview == "object" && !isEmpty(config.seoPreview) ? [
708
+ sanity.defineField({
709
+ name: "preview",
710
+ title: "SEO Preview",
711
+ type: "string",
712
+ components: { input: SeoPreview },
713
+ options: {
714
+ baseUrl: config.baseUrl || "https://www.example.com",
715
+ ...typeof config.seoPreview == "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}
716
+ },
717
+ // Use a readOnly field to prevent editing
718
+ // This field is just for preview purposes
719
+ initialValue: "",
720
+ // Set an initial value
721
+ readOnly: !0
722
+ })
723
+ ] : [],
724
+ sanity.defineField({
725
+ name: "title",
726
+ ...getFieldInfo("title", config.fieldOverrides),
727
+ // title: 'Meta Title',
728
+ type: "string",
729
+ // description:
730
+ // '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.',
731
+ components: {
732
+ input: MetaTitle
733
+ },
734
+ // validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),
735
+ hidden: getFieldHiddenFunction("title", config)
736
+ }),
737
+ sanity.defineField({
738
+ name: "description",
739
+ ...getFieldInfo("description", config.fieldOverrides),
740
+ // title: 'Meta Description',
741
+ // description:
742
+ // 'Provide a concise summary of the page content. This description may be used by search engines in search results.',
743
+ type: "text",
744
+ rows: 3,
745
+ components: {
746
+ input: MetaDescription
747
+ },
748
+ // validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),
749
+ hidden: getFieldHiddenFunction("description", config)
750
+ }),
751
+ sanity.defineField({
752
+ name: "metaImage",
753
+ ...getFieldInfo("metaImage", config.fieldOverrides),
754
+ // title: 'Meta Image',
755
+ // description:
756
+ // 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',
757
+ type: "image",
758
+ options: {
759
+ hotspot: !0
760
+ },
761
+ hidden: getFieldHiddenFunction("metaImage", config)
762
+ }),
763
+ sanity.defineField({
764
+ name: "metaAttributes",
765
+ // title: 'Additional Meta Attributes',
766
+ ...getFieldInfo("metaAttributes", config.fieldOverrides),
767
+ type: "array",
768
+ of: [{ type: "metaAttribute" }],
769
+ // description:
770
+ // 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',
771
+ hidden: getFieldHiddenFunction("metaAttributes", config)
772
+ }),
773
+ sanity.defineField({
774
+ name: "keywords",
775
+ ...getFieldInfo("keywords", config.fieldOverrides),
776
+ title: "Keywords",
777
+ type: "array",
778
+ of: [{ type: "string" }],
779
+ description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
780
+ hidden: getFieldHiddenFunction("keywords", config)
781
+ }),
782
+ sanity.defineField({
783
+ name: "canonicalUrl",
784
+ ...getFieldInfo("canonicalUrl", config.fieldOverrides),
785
+ title: "Canonical URL",
786
+ type: "url",
787
+ description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
788
+ hidden: getFieldHiddenFunction("canonicalUrl", config)
789
+ }),
790
+ openGraph(config),
791
+ twitter(config)
792
+ ]
793
+ });
794
+ }
795
+ var metaAttribute = sanity.defineType({
796
+ name: "metaAttribute",
797
+ title: "Meta Attribute",
841
798
  type: "object",
842
799
  fields: [
843
800
  sanity.defineField({
844
- name: "noIndex",
845
- title: "No Index",
846
- type: "boolean",
847
- initialValue: !1,
848
- description: "Enable this to prevent search engines from indexing this page. The page will not appear in search results."
801
+ name: "key",
802
+ title: "Attribute Name",
803
+ type: "string"
849
804
  }),
850
805
  sanity.defineField({
851
- name: "noFollow",
852
- title: "No Follow",
853
- type: "boolean",
854
- initialValue: !1,
855
- description: "Enable this to prevent search engines from following links on this page. Links will not pass SEO value."
806
+ name: "type",
807
+ title: "Attribute Value Type",
808
+ type: "string",
809
+ options: {
810
+ list: [
811
+ { title: "String", value: "string" },
812
+ { title: "Image", value: "image" }
813
+ ]
814
+ },
815
+ initialValue: "string"
816
+ }),
817
+ sanity.defineField({
818
+ name: "value",
819
+ title: "Attribute Value",
820
+ type: "string",
821
+ hidden: ({ parent }) => parent?.type === "image"
822
+ }),
823
+ sanity.defineField({
824
+ name: "image",
825
+ title: "Attribute Image Value",
826
+ type: "image",
827
+ hidden: ({ parent }) => parent?.type === "string"
856
828
  })
857
829
  ],
858
- description: "Select how search engines should index and follow links on this page."
830
+ preview: {
831
+ select: {
832
+ attributeName: "key",
833
+ attributeValueString: "value",
834
+ attributeValueImage: "image"
835
+ },
836
+ prepare({ attributeName, attributeValueString, attributeValueImage }) {
837
+ let subtitle = "";
838
+ return attributeValueString ? subtitle = `Value: ${attributeValueString}` : attributeValueImage ? subtitle = "Value: [Image]" : subtitle = "No Attribute Value", {
839
+ title: attributeName || "No Attribute Name",
840
+ subtitle,
841
+ media: attributeValueImage
842
+ };
843
+ }
844
+ }
859
845
  }), metaTag = sanity.defineType({
860
846
  name: "metaTag",
861
847
  title: "Meta Tag",
@@ -869,6 +855,27 @@ var robots = sanity.defineType({
869
855
  description: "Add custom meta attributes to the head of the document for additional SEO and social media integration."
870
856
  }
871
857
  ]
858
+ }), robots = sanity.defineType({
859
+ name: "robots",
860
+ title: "Robots Settings",
861
+ type: "object",
862
+ fields: [
863
+ sanity.defineField({
864
+ name: "noIndex",
865
+ title: "No Index",
866
+ type: "boolean",
867
+ initialValue: !1,
868
+ description: "Enable this to prevent search engines from indexing this page. The page will not appear in search results."
869
+ }),
870
+ sanity.defineField({
871
+ name: "noFollow",
872
+ title: "No Follow",
873
+ type: "boolean",
874
+ initialValue: !1,
875
+ description: "Enable this to prevent search engines from following links on this page. Links will not pass SEO value."
876
+ })
877
+ ],
878
+ description: "Select how search engines should index and follow links on this page."
872
879
  });
873
880
  function types(config = {}) {
874
881
  return [
@@ -889,35 +896,9 @@ const seofields = sanity.definePlugin((config = {}) => ({
889
896
  types: types(config)
890
897
  // pass config down to schemas
891
898
  }
892
- })), isSeoFields = (obj) => obj && obj._type === "seoFields", isOpenGraphSettings = (obj) => obj && obj._type === "openGraph", isTwitterCardSettings = (obj) => obj && obj._type === "twitter", isMetaAttribute = (obj) => obj && obj._type === "metaAttribute", defaultSeoValidationRules = {
893
- title: {
894
- maxLength: 70,
895
- warningLength: 60
896
- },
897
- description: {
898
- maxLength: 160,
899
- warningLength: 150
900
- },
901
- openGraphTitle: {
902
- maxLength: 95
903
- },
904
- openGraphDescription: {
905
- maxLength: 200
906
- },
907
- twitterTitle: {
908
- maxLength: 70
909
- },
910
- twitterDescription: {
911
- maxLength: 200
912
- }
913
- };
899
+ }));
914
900
  exports.allSchemas = types;
915
901
  exports.default = seofields;
916
- exports.defaultSeoValidationRules = defaultSeoValidationRules;
917
- exports.isMetaAttribute = isMetaAttribute;
918
- exports.isOpenGraphSettings = isOpenGraphSettings;
919
- exports.isSeoFields = isSeoFields;
920
- exports.isTwitterCardSettings = isTwitterCardSettings;
921
902
  exports.metaAttributeSchema = metaAttribute;
922
903
  exports.metaTagSchema = metaTag;
923
904
  exports.openGraphSchema = openGraph;