diff --git a/studio/schemas/builders/pageBuilder.ts b/studio/schemas/builders/pageBuilder.ts index 0384ae7e0..8fc82c4d9 100644 --- a/studio/schemas/builders/pageBuilder.ts +++ b/studio/schemas/builders/pageBuilder.ts @@ -11,6 +11,7 @@ import testimonals from "../objects/sections/testimonials"; import imageSection from "../objects/sections/image"; import grid from "../objects/sections/grid"; import contactForm from "../objects/sections/form"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export const pageBuilderID = "pageBuilder"; @@ -26,6 +27,10 @@ const pageBuilder = defineType({ "Enter a distinctive name for the dynamic page to help content editors easily identify and manage it. This name is used internally and is not visible on your website.", type: "string", validation: (Rule) => Rule.required().max(30), + components: { + input: (props) => + StringInputWithCharacterCount({ ...props, maxCount: 30 }), + }, }), pageSlug, seo, diff --git a/studio/schemas/documents/blog.ts b/studio/schemas/documents/blog.ts index fba1bb82b..4d74eadba 100644 --- a/studio/schemas/documents/blog.ts +++ b/studio/schemas/documents/blog.ts @@ -2,6 +2,7 @@ import { defineField, defineType } from "sanity"; import seo from "../objects/seo"; import { pageSlug } from "../schemaTypes/slug"; import { title } from "../fields/text"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export const blogId = "blog"; @@ -17,6 +18,10 @@ const blog = defineType({ "Enter a distinctive name for the page to help content editors easily identify and manage it. This name is used internally and is not visible on your website.", type: "string", validation: (Rule) => Rule.required().max(30), + components: { + input: (props) => + StringInputWithCharacterCount({ ...props, maxCount: 30 }), + }, }), pageSlug, seo, @@ -28,7 +33,11 @@ const blog = defineType({ "Enter the label used to refer to all posts regardless of their category. This label will be displayed in the filter section on the main blog page. Examples include 'news', 'stories', or 'posts'.", type: "string", initialValue: "All posts", - validation: (Rule) => Rule.required(), + validation: (Rule) => Rule.required().max(20), + components: { + input: (props) => + StringInputWithCharacterCount({ ...props, maxCount: 20 }), + }, }), defineField({ name: "categories", @@ -49,6 +58,10 @@ const blog = defineType({ "The name of the category. This will be displayed on the website and used for organizing blog posts.", type: "string", validation: (Rule) => Rule.required().min(1).max(100), + components: { + input: (props) => + StringInputWithCharacterCount({ ...props, maxCount: 100 }), + }, }), ], }), diff --git a/studio/schemas/documents/companyInfo.ts b/studio/schemas/documents/companyInfo.ts index 3108ed8c9..ad937c796 100644 --- a/studio/schemas/documents/companyInfo.ts +++ b/studio/schemas/documents/companyInfo.ts @@ -1,5 +1,6 @@ import { defineType, defineField } from "sanity"; import seo from "../objects/seo"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export const companyInfoID = "companyInfo"; @@ -24,6 +25,11 @@ const companyInfo = defineType({ type: "string", title: "Site Name", description: "The name of your website.", + validation: (rule) => rule.max(60), + components: { + input: (props) => + StringInputWithCharacterCount({ ...props, maxCount: 60 }), + }, }), defineField({ name: "defaultLanguage", diff --git a/studio/schemas/documents/companyLocation.ts b/studio/schemas/documents/companyLocation.ts index 91352c7c7..47a01f569 100644 --- a/studio/schemas/documents/companyLocation.ts +++ b/studio/schemas/documents/companyLocation.ts @@ -1,4 +1,5 @@ import { defineField, defineType } from "sanity"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export const companyLocationID = "companyLocation"; export const companyLocationNameID = "companyLocationName"; @@ -13,6 +14,11 @@ const companyLocation = defineType({ name: companyLocationNameID, type: "string", title: "Location", + validation: (rule) => rule.max(50), + components: { + input: (props) => + StringInputWithCharacterCount({ ...props, maxCount: 50 }), + }, }), ], }); diff --git a/studio/schemas/fields/categories.ts b/studio/schemas/fields/categories.ts index ea7c07d9a..0fc2f6d6e 100644 --- a/studio/schemas/fields/categories.ts +++ b/studio/schemas/fields/categories.ts @@ -1,4 +1,5 @@ -import { defineField } from "sanity"; +import { defineField, StringInputProps } from "sanity"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export const categoriesId = "categories"; @@ -12,6 +13,10 @@ const categories = defineField({ type: "string", title: "Category", validation: (Rule) => Rule.required().min(1).max(100), + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 100 }), + }, }, ], }); diff --git a/studio/schemas/fields/media.ts b/studio/schemas/fields/media.ts index e1e7fa403..86bc8b0f9 100644 --- a/studio/schemas/fields/media.ts +++ b/studio/schemas/fields/media.ts @@ -1,4 +1,5 @@ -import { defineField } from "sanity"; +import { defineField, StringInputProps } from "sanity"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export enum ImageAlignment { Left = "left", @@ -15,20 +16,25 @@ const alignmentOptions = [ { title: "Right", value: ImageAlignment.Right }, ]; +const imageAltField = defineField({ + name: "alt", + type: "string", + title: "Alternative Text", + description: + "Provide a description of the image for accessibility. Leave empty if the image is purely decorative.", + validation: (rule) => rule.max(100), + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 100 }), + }, +}); + const image = defineField({ name: "image", title: "Image", type: "image", options: { hotspot: true }, - fields: [ - { - name: "alt", - type: "string", - title: "Alternative Text", - description: - "Provide a description of the image for accessibility. Leave empty if the image is purely decorative.", - }, - ], + fields: [imageAltField], }); export const imageExtended = defineField({ @@ -37,13 +43,7 @@ export const imageExtended = defineField({ type: "image", options: { hotspot: true }, fields: [ - { - name: "alt", - type: "string", - title: "Alternative Text", - description: - "Provide a description of the image for accessibility. Leave empty if the image is purely decorative.", - }, + imageAltField, { name: "imageAlignment", title: "Image Alignment", diff --git a/studio/schemas/fields/text.ts b/studio/schemas/fields/text.ts index d0df65def..449387a60 100644 --- a/studio/schemas/fields/text.ts +++ b/studio/schemas/fields/text.ts @@ -1,4 +1,5 @@ import { StringRule, defineField } from "sanity"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; enum titleID { basic = "basicTitle", @@ -35,6 +36,10 @@ const createField = ({ title, type: "string", validation: validationRules, + components: { + input: (props) => + StringInputWithCharacterCount({ ...props, maxCount: maxLength }), + }, }); }; @@ -54,6 +59,9 @@ export const optionalSubtitle = defineField({ title: "Subtitle", type: "string", validation: (Rule) => Rule.max(60), + components: { + input: (props) => StringInputWithCharacterCount({ ...props, maxCount: 60 }), + }, }); export const richTextID = "richText"; diff --git a/studio/schemas/objects/footerSection.ts b/studio/schemas/objects/footerSection.ts index 57d7aab7e..fd10a9a76 100644 --- a/studio/schemas/objects/footerSection.ts +++ b/studio/schemas/objects/footerSection.ts @@ -1,7 +1,8 @@ -import { defineType } from "sanity"; +import { defineType, StringInputProps } from "sanity"; import { linkID } from "./link"; import { soMeLinksID } from "../documents/socialMediaProfiles"; import { richText, richTextID } from "../fields/text"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export const footerSectionID = { main: "footerSection", @@ -32,7 +33,14 @@ export const footerSection = defineType({ type: "string", description: "Enter the title for this footer section. This will help identify the section within the footer.", - validation: (Rule) => Rule.required().error("Section title is required"), + validation: (Rule) => [ + Rule.required().error("Section title is required"), + Rule.max(60), + ], + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 60 }), + }, }, { name: footerSectionID.type, diff --git a/studio/schemas/objects/link.ts b/studio/schemas/objects/link.ts index 3ed110cd0..32411039e 100644 --- a/studio/schemas/objects/link.ts +++ b/studio/schemas/objects/link.ts @@ -1,7 +1,8 @@ -import { defineField } from "sanity"; +import { defineField, StringInputProps } from "sanity"; import AnchorSelect from "../../components/AnchorSelect"; import LinkTypeSelector from "../../components/LinkTypeSelector"; import NewTabSelector from "../../components/NewTabSelector"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; export const linkID = "link"; @@ -34,6 +35,11 @@ export const link = defineField({ title: "Provide a link title", type: "string", description: "Enter the link text that will be displayed on the website.", + validation: (rule) => rule.max(60), + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 60 }), + }, }, { name: "linkType", diff --git a/studio/schemas/objects/sections/article.ts b/studio/schemas/objects/sections/article.ts index 69bdcc294..80122a44c 100644 --- a/studio/schemas/objects/sections/article.ts +++ b/studio/schemas/objects/sections/article.ts @@ -1,7 +1,8 @@ -import { defineField } from "sanity"; +import { defineField, StringInputProps } from "sanity"; import { richText, title } from "../../../schemas/fields/text"; import { imageExtended } from "../../../schemas/fields/media"; import { link } from "../link"; +import { StringInputWithCharacterCount } from "../../../components/StringInputWithCharacterCount"; export const articleID = "article"; @@ -14,6 +15,11 @@ export const article = defineField({ name: "tag", title: "Tag", type: "string", + validation: (rule) => rule.max(60), + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 60 }), + }, }, title, richText, diff --git a/studio/schemas/objects/sections/hero.ts b/studio/schemas/objects/sections/hero.ts index c21fed68f..449ff919f 100644 --- a/studio/schemas/objects/sections/hero.ts +++ b/studio/schemas/objects/sections/hero.ts @@ -1,8 +1,9 @@ // hero.ts -import { defineField } from "sanity"; +import { defineField, StringInputProps } from "sanity"; import callToActionField from "../../fields/callToActionFields"; import CustomCallToActions from "../../../components/CustomCallToActions"; import { title } from "studio/schemas/fields/text"; +import { StringInputWithCharacterCount } from "../../../components/StringInputWithCharacterCount"; export const heroID = "hero"; @@ -17,6 +18,10 @@ export const hero = defineField({ title: "Description", type: "string", validation: (Rule) => Rule.max(200), + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 200 }), + }, }, { name: "callToActions", diff --git a/studio/schemas/objects/sections/logoSalad.ts b/studio/schemas/objects/sections/logoSalad.ts index 4c04e22b0..83d790b87 100644 --- a/studio/schemas/objects/sections/logoSalad.ts +++ b/studio/schemas/objects/sections/logoSalad.ts @@ -1,6 +1,7 @@ -import { defineField } from "sanity"; +import { defineField, StringInputProps } from "sanity"; import image from "studio/schemas/fields/media"; import { richText } from "studio/schemas/fields/text"; +import { StringInputWithCharacterCount } from "../../../components/StringInputWithCharacterCount"; export const logoSaladID = "logoSalad"; @@ -21,8 +22,14 @@ export const logoSalad = defineField({ type: "string", description: "Required text displayed in a smaller body text style. Use it to provide additional context or details about the logos.", - validation: (Rule) => + validation: (Rule) => [ Rule.required().error("Logo description is required."), + Rule.max(100), + ], + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 100 }), + }, }, { name: "logos", diff --git a/studio/schemas/objects/seo.ts b/studio/schemas/objects/seo.ts index 0aa9b1bda..b225a8cec 100644 --- a/studio/schemas/objects/seo.ts +++ b/studio/schemas/objects/seo.ts @@ -1,4 +1,4 @@ -import { defineField } from "sanity"; +import { defineField, StringInputProps } from "sanity"; import { StringInputWithCharacterCount } from "studio/components/StringInputWithCharacterCount"; const seoFieldID = { @@ -59,6 +59,9 @@ const seo = defineField({ title: "SEO & Social Media Keywords", description: "Enter targeted keywords to enhance your content’s visibility in search engines and social media platforms. Use relevant and specific keywords that describe your content, helping to attract the right audience and improve your SEO performance", + components: { + input: StringInputWithCharacterCount, + }, }), defineField({ name: seoFieldID.image, diff --git a/studio/schemas/objects/testimony.ts b/studio/schemas/objects/testimony.ts index ac16166a1..97d3ad022 100644 --- a/studio/schemas/objects/testimony.ts +++ b/studio/schemas/objects/testimony.ts @@ -1,5 +1,7 @@ import { richText, title } from "../fields/text"; import image from "../fields/media"; +import { StringInputWithCharacterCount } from "../../components/StringInputWithCharacterCount"; +import { StringInputProps, StringRule } from "sanity"; export const testimony = { name: "testimony", @@ -11,6 +13,11 @@ export const testimony = { name: "subTitle", type: "string", title: "Subtitle", + validation: (rule: StringRule) => rule.max(100), + components: { + input: (props: StringInputProps) => + StringInputWithCharacterCount({ ...props, maxCount: 100 }), + }, }, image, richText,