From 89fe79229e283255b5ef9ed531083d3eae085aa0 Mon Sep 17 00:00:00 2001 From: Mathias Oterhals Myklebust Date: Thu, 17 Oct 2024 10:55:17 +0200 Subject: [PATCH] feat(customerCase): image block --- studio/schemas/fields/media.ts | 35 +++++++++++++++ studioShared/lib/queries/customerCases.ts | 7 ++- .../schemas/documents/customerCase.ts | 10 ++++- studioShared/schemas/objects/imageBlock.ts | 44 +++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 studioShared/schemas/objects/imageBlock.ts diff --git a/studio/schemas/fields/media.ts b/studio/schemas/fields/media.ts index fa35f0ff6..7a6450c9e 100644 --- a/studio/schemas/fields/media.ts +++ b/studio/schemas/fields/media.ts @@ -1,6 +1,8 @@ import { StringInputProps, defineField } from "sanity"; import { StringInputWithCharacterCount } from "studio/components/stringInputWithCharacterCount/StringInputWithCharacterCount"; +import { isInternationalizedString } from "studio/lib/interfaces/global"; +import { firstTranslation } from "studio/utils/i18n"; export enum ImageAlignment { Left = "left", @@ -30,6 +32,14 @@ const imageAltField = defineField({ }, }); +const internationalizedImageAltField = defineField({ + name: "alt", + type: "internationalizedArrayString", + title: "Alternative Text", + description: + "Provide a description of the image for accessibility. Leave empty if the image is purely decorative.", +}); + const image = defineField({ name: "image", title: "Image", @@ -38,6 +48,31 @@ const image = defineField({ fields: [imageAltField], }); +export const internationalizedImage = defineField({ + name: "image", + title: "Image", + type: "image", + options: { hotspot: true }, + fields: [internationalizedImageAltField], + preview: { + select: { + alt: "alt", + media: "asset", + }, + prepare({ alt, media }) { + if (!isInternationalizedString(alt)) { + throw new TypeError( + `Expected 'alt' to be InternationalizedString, was ${typeof alt}`, + ); + } + return { + title: firstTranslation(alt) ?? undefined, + media, + }; + }, + }, +}); + export const imageExtended = defineField({ name: "imageExtended", title: "Extended Image", diff --git a/studioShared/lib/queries/customerCases.ts b/studioShared/lib/queries/customerCases.ts index 2ead1314f..b4f71bdc0 100644 --- a/studioShared/lib/queries/customerCases.ts +++ b/studioShared/lib/queries/customerCases.ts @@ -32,8 +32,13 @@ export const CUSTOMER_CASE_QUERY = groq` "sections": sections[] { _type, _type == "richTextBlock" => { - ..., "richText": ${translatedFieldFragment("richText")}, + }, + _type == "imageBlock" => { + "images": images[] { + asset, + "alt": ${translatedFieldFragment("alt")} + } } } } diff --git a/studioShared/schemas/documents/customerCase.ts b/studioShared/schemas/documents/customerCase.ts index c86997b15..6cf08f1e7 100644 --- a/studioShared/schemas/documents/customerCase.ts +++ b/studioShared/schemas/documents/customerCase.ts @@ -5,6 +5,7 @@ import { richTextID, titleID } from "studio/schemas/fields/text"; import { titleSlug } from "studio/schemas/schemaTypes/slug"; import { firstTranslation } from "studio/utils/i18n"; import { customerCaseProjectInfo } from "studioShared/schemas/fields/customerCaseProjectInfo"; +import imageBlock from "studioShared/schemas/objects/imageBlock"; import richTextBlock from "studioShared/schemas/objects/richTextBlock"; export const customerCaseID = "customerCase"; @@ -30,13 +31,18 @@ const customerCase = defineType({ description: "Short paragraph displayed at the top of the customer case page", }), - customerCaseProjectInfo, + defineField({ + ...customerCaseProjectInfo, + options: { + collapsible: true, + }, + }), defineField({ name: "sections", title: "Sections", description: "Add sections here", type: "array", - of: [richTextBlock], + of: [richTextBlock, imageBlock], }), defineField({ name: richTextID, diff --git a/studioShared/schemas/objects/imageBlock.ts b/studioShared/schemas/objects/imageBlock.ts new file mode 100644 index 000000000..065bc41e6 --- /dev/null +++ b/studioShared/schemas/objects/imageBlock.ts @@ -0,0 +1,44 @@ +import { defineField } from "sanity"; + +import { isInternationalizedString } from "studio/lib/interfaces/global"; +import { internationalizedImage } from "studio/schemas/fields/media"; +import { firstTranslation } from "studio/utils/i18n"; + +const imageBlock = defineField({ + name: "imageBlock", + title: "Image Block", + type: "object", + fields: [ + { + name: "images", + title: "Images", + type: "array", + of: [internationalizedImage], + }, + ], + preview: { + select: { + images: "images", + }, + prepare: ({ images }) => { + const count = Object.keys(images).length; + const firstImage = count > 0 ? images[0] : undefined; + let firstImageAlt = null; + if (firstImage !== undefined) { + const imageAlt = firstImage.alt; + if (!isInternationalizedString(imageAlt)) { + throw new TypeError( + `Expected image 'alt' to be InternationalizedString, was ${typeof firstImage.alt}`, + ); + } + firstImageAlt = firstTranslation(imageAlt); + } + return { + title: count > 1 ? `${count} images` : (firstImageAlt ?? undefined), + media: firstImage, + }; + }, + }, +}); + +export default imageBlock;