From 885b62bd3027f72d322b7d1a8fc69104148c10f0 Mon Sep 17 00:00:00 2001 From: Ane Date: Wed, 16 Oct 2024 15:21:53 +0200 Subject: [PATCH 1/5] richtextblock for customer cases --- .../schemas/documents/customerCase.ts | 9 ++++++- studioShared/schemas/objects/richTextBlock.ts | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 studioShared/schemas/objects/richTextBlock.ts diff --git a/studioShared/schemas/documents/customerCase.ts b/studioShared/schemas/documents/customerCase.ts index 3f4e8df7e..c86997b15 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 richTextBlock from "studioShared/schemas/objects/richTextBlock"; export const customerCaseID = "customerCase"; @@ -30,7 +31,13 @@ const customerCase = defineType({ "Short paragraph displayed at the top of the customer case page", }), customerCaseProjectInfo, - //TODO: Block section + defineField({ + name: "sections", + title: "Sections", + description: "Add sections here", + type: "array", + of: [richTextBlock], + }), defineField({ name: richTextID, title: "Body", diff --git a/studioShared/schemas/objects/richTextBlock.ts b/studioShared/schemas/objects/richTextBlock.ts new file mode 100644 index 000000000..851a3ee1a --- /dev/null +++ b/studioShared/schemas/objects/richTextBlock.ts @@ -0,0 +1,24 @@ +import { defineField } from "sanity"; + +const richTextBlock = defineField({ + name: "richTextBlock", + title: "Rich Text Block", + type: "object", + fields: [ + { + name: "richText", + title: "Rich Text", + type: "internationalizedArrayRichText", + }, + ], + preview: { + select: { + text: "richText", + }, + prepare({ text }) { + //TODO: add preview + }, + }, +}); + +export default richTextBlock; From fda9b17ee6bb359d558e3d048dfe49ab89cdd3bc Mon Sep 17 00:00:00 2001 From: Ane Date: Wed, 16 Oct 2024 15:41:54 +0200 Subject: [PATCH 2/5] prepare for richtext --- studioShared/schemas/objects/richTextBlock.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/studioShared/schemas/objects/richTextBlock.ts b/studioShared/schemas/objects/richTextBlock.ts index 851a3ee1a..94fb61e84 100644 --- a/studioShared/schemas/objects/richTextBlock.ts +++ b/studioShared/schemas/objects/richTextBlock.ts @@ -16,7 +16,9 @@ const richTextBlock = defineField({ text: "richText", }, prepare({ text }) { - //TODO: add preview + return { + title: text, //Does not work + }; }, }, }); From 037698171ccabb63bfe077f8249f57a448bcc30c Mon Sep 17 00:00:00 2001 From: Mathias Oterhals Myklebust Date: Wed, 16 Oct 2024 16:08:32 +0200 Subject: [PATCH 3/5] feat(richTextBlock): initial preview --- studio/lib/interfaces/global.ts | 29 +++++++++++-------- studio/utils/i18n.ts | 12 ++++---- studio/utils/preview.ts | 27 +++++++++++++++++ studioShared/schemas/objects/richTextBlock.ts | 17 +++++++++-- 4 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 studio/utils/preview.ts diff --git a/studio/lib/interfaces/global.ts b/studio/lib/interfaces/global.ts index eb11d8418..4550feba3 100644 --- a/studio/lib/interfaces/global.ts +++ b/studio/lib/interfaces/global.ts @@ -3,14 +3,9 @@ export interface Slug { current: string; } -export interface DocumentWithSlug { - slug: Slug; - _updatedAt: string; -} - -export function isInternationalizedString( +export function isInternationalizedValue( value: unknown, -): value is InternationalizedString { +): value is InternationalizedValue { return ( Array.isArray(value) && value.every( @@ -19,15 +14,25 @@ export function isInternationalizedString( item !== null && "_key" in item && typeof item._key === "string" && - "value" in item && - typeof item.value === "string", + "value" in item, ) ); } -export type InternationalizedString = InternationalizedStringRecord[]; +export function isInternationalizedString( + value: unknown, +): value is InternationalizedString { + return ( + isInternationalizedValue(value) && + value.every((item) => typeof item.value === "string") + ); +} + +export type InternationalizedValue = InternationalizedValueRecord[]; -export interface InternationalizedStringRecord { +export interface InternationalizedValueRecord { _key: string; - value: string; + value: T; } + +export type InternationalizedString = InternationalizedValueRecord[]; diff --git a/studio/utils/i18n.ts b/studio/utils/i18n.ts index 7b63d5bbf..a67ec211b 100644 --- a/studio/utils/i18n.ts +++ b/studio/utils/i18n.ts @@ -1,10 +1,10 @@ -import { InternationalizedString } from "studio/lib/interfaces/global"; +import { InternationalizedValue } from "studio/lib/interfaces/global"; -export function firstTranslation( - translatedString: InternationalizedString, -): string | null { - if (translatedString.length === 0) { +export function firstTranslation( + internationalizedValue: InternationalizedValue, +): T | null { + if (internationalizedValue.length === 0) { return null; } - return translatedString[0].value; + return internationalizedValue[0].value; } diff --git a/studio/utils/preview.ts b/studio/utils/preview.ts new file mode 100644 index 000000000..423aa9f6f --- /dev/null +++ b/studio/utils/preview.ts @@ -0,0 +1,27 @@ +import { PortableTextBlock } from "sanity"; + +// Convert rich text content to plaintext preview string +// (see https://www.sanity.io/docs/previewing-block-content) +export function richTextPreview( + richText: PortableTextBlock[], +): string | undefined { + console.log(richText); + const block = richText.find((block) => block._type === "block"); + if ( + block === undefined || + !("children" in block) || + !Array.isArray(block.children) + ) { + return undefined; + } + return block.children + .filter( + (child: unknown) => + typeof child === "object" && + child !== null && + "_type" in child && + child._type === "span", + ) + .map((span) => span.text) + .join(""); +} diff --git a/studioShared/schemas/objects/richTextBlock.ts b/studioShared/schemas/objects/richTextBlock.ts index 94fb61e84..f1e2c1986 100644 --- a/studioShared/schemas/objects/richTextBlock.ts +++ b/studioShared/schemas/objects/richTextBlock.ts @@ -1,5 +1,9 @@ import { defineField } from "sanity"; +import { isInternationalizedValue } from "studio/lib/interfaces/global"; +import { firstTranslation } from "studio/utils/i18n"; +import { richTextPreview } from "studio/utils/preview"; + const richTextBlock = defineField({ name: "richTextBlock", title: "Rich Text Block", @@ -13,11 +17,18 @@ const richTextBlock = defineField({ ], preview: { select: { - text: "richText", + richText: "richText", }, - prepare({ text }) { + prepare({ richText }) { + // TODO: better type guard for rich text + if (!isInternationalizedValue(richText)) { + throw new TypeError( + `Expected 'richText' to be InternationalizedValue, was ${typeof richText}`, + ); + } + const translatedRichText = firstTranslation(richText); return { - title: text, //Does not work + title: richTextPreview(translatedRichText), }; }, }, From 79bbe3b10a3806b1c1d0ede43ebb94c789ac3ada Mon Sep 17 00:00:00 2001 From: Mathias Oterhals Myklebust Date: Thu, 17 Oct 2024 09:35:59 +0200 Subject: [PATCH 4/5] feat(richTextBlock): improve type check for rich text preview --- studio/lib/interfaces/global.ts | 13 +++++++ studio/lib/interfaces/richText.ts | 37 +++++++++++++++++++ studio/utils/preview.ts | 23 ++++-------- studioShared/schemas/objects/richTextBlock.ts | 12 +++--- 4 files changed, 65 insertions(+), 20 deletions(-) create mode 100644 studio/lib/interfaces/richText.ts diff --git a/studio/lib/interfaces/global.ts b/studio/lib/interfaces/global.ts index 4550feba3..dbd856aaa 100644 --- a/studio/lib/interfaces/global.ts +++ b/studio/lib/interfaces/global.ts @@ -1,3 +1,7 @@ +import { PortableTextBlock } from "sanity"; + +import { isRichText } from "./richText"; + export interface Slug { _type: string; current: string; @@ -28,6 +32,15 @@ export function isInternationalizedString( ); } +export function isInternationalizedRichText( + value: unknown, +): value is InternationalizedValue { + return ( + isInternationalizedValue(value) && + value.every((record) => isRichText(record.value)) + ); +} + export type InternationalizedValue = InternationalizedValueRecord[]; export interface InternationalizedValueRecord { diff --git a/studio/lib/interfaces/richText.ts b/studio/lib/interfaces/richText.ts new file mode 100644 index 000000000..29ed1ad8f --- /dev/null +++ b/studio/lib/interfaces/richText.ts @@ -0,0 +1,37 @@ +import { + PortableTextBlock, + PortableTextObject, + isPortableTextTextBlock, +} from "sanity"; + +export function isRichText(value: unknown): value is PortableTextBlock[] { + return ( + Array.isArray(value) && value.every((item) => isPortableTextBlock(item)) + ); +} + +export function isPortableTextBlock( + value: unknown, +): value is PortableTextBlock { + return isPortableTextTextBlock(value) || isPortableTextObject(value); +} + +export function isPortableTextObject( + value: unknown, +): value is PortableTextObject { + return isSanityKeyTypeObject(value); +} + +function isSanityKeyTypeObject(value: unknown): value is { + _key: string; + _type: string; +} { + return ( + typeof value === "object" && + value !== null && + "_key" in value && + typeof value._key === "string" && + "_type" in value && + typeof value._type === "string" + ); +} diff --git a/studio/utils/preview.ts b/studio/utils/preview.ts index 423aa9f6f..ae701d939 100644 --- a/studio/utils/preview.ts +++ b/studio/utils/preview.ts @@ -1,27 +1,20 @@ -import { PortableTextBlock } from "sanity"; +import { + PortableTextBlock, + isPortableTextSpan, + isPortableTextTextBlock, +} from "sanity"; // Convert rich text content to plaintext preview string -// (see https://www.sanity.io/docs/previewing-block-content) +// (inspired by https://www.sanity.io/docs/previewing-block-content) export function richTextPreview( richText: PortableTextBlock[], ): string | undefined { - console.log(richText); const block = richText.find((block) => block._type === "block"); - if ( - block === undefined || - !("children" in block) || - !Array.isArray(block.children) - ) { + if (!isPortableTextTextBlock(block)) { return undefined; } return block.children - .filter( - (child: unknown) => - typeof child === "object" && - child !== null && - "_type" in child && - child._type === "span", - ) + .filter((child) => isPortableTextSpan(child)) .map((span) => span.text) .join(""); } diff --git a/studioShared/schemas/objects/richTextBlock.ts b/studioShared/schemas/objects/richTextBlock.ts index f1e2c1986..74ce0164a 100644 --- a/studioShared/schemas/objects/richTextBlock.ts +++ b/studioShared/schemas/objects/richTextBlock.ts @@ -1,6 +1,6 @@ import { defineField } from "sanity"; -import { isInternationalizedValue } from "studio/lib/interfaces/global"; +import { isInternationalizedRichText } from "studio/lib/interfaces/global"; import { firstTranslation } from "studio/utils/i18n"; import { richTextPreview } from "studio/utils/preview"; @@ -20,15 +20,17 @@ const richTextBlock = defineField({ richText: "richText", }, prepare({ richText }) { - // TODO: better type guard for rich text - if (!isInternationalizedValue(richText)) { + if (!isInternationalizedRichText(richText)) { throw new TypeError( - `Expected 'richText' to be InternationalizedValue, was ${typeof richText}`, + `Expected 'richText' to be InternationalizedRichText, was ${typeof richText}`, ); } const translatedRichText = firstTranslation(richText); return { - title: richTextPreview(translatedRichText), + title: + translatedRichText !== null + ? richTextPreview(translatedRichText) + : undefined, }; }, }, From 8a4a1a380f7456db4003951b6c244a0559ac4238 Mon Sep 17 00:00:00 2001 From: Mathias Oterhals Myklebust Date: Thu, 17 Oct 2024 11:00:25 +0200 Subject: [PATCH 5/5] feat(customerCase): include block sections in customer case query --- studioShared/lib/queries/customerCases.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/studioShared/lib/queries/customerCases.ts b/studioShared/lib/queries/customerCases.ts index e50e0058f..2ead1314f 100644 --- a/studioShared/lib/queries/customerCases.ts +++ b/studioShared/lib/queries/customerCases.ts @@ -28,6 +28,13 @@ export const CUSTOMER_CASE_QUERY = groq` "sector": ${translatedFieldFragment("sector")}, "delivery": ${translatedFieldFragment("delivery")}, consultants + }, + "sections": sections[] { + _type, + _type == "richTextBlock" => { + ..., + "richText": ${translatedFieldFragment("richText")}, + } } } `;