From c6984acb23c6a52210ec07444c313cf02608975e Mon Sep 17 00:00:00 2001 From: Fernando Lucchesi Date: Wed, 4 Oct 2023 16:54:03 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20big=20title=20for=20rich=20te?= =?UTF-8?q?xt=20and=20improve=20code=20#1890?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sanityv3/schemas/objects/teaser.tsx | 36 ++++----- sanityv3/schemas/objects/textBlock.tsx | 88 +++++++++++++++------ web/lib/queries/common/pageContentFields.ts | 14 ++-- web/pageComponents/shared/Teaser.tsx | 8 +- web/pageComponents/topicPages/TextBlock.tsx | 33 ++++++-- web/types/types.ts | 4 +- 6 files changed, 120 insertions(+), 63 deletions(-) diff --git a/sanityv3/schemas/objects/teaser.tsx b/sanityv3/schemas/objects/teaser.tsx index c9688902f..fac1f71d5 100644 --- a/sanityv3/schemas/objects/teaser.tsx +++ b/sanityv3/schemas/objects/teaser.tsx @@ -53,7 +53,7 @@ export type Teaser = { overline?: string title?: PortableTextBlock[] text?: PortableTextBlock[] - bigTextTeaser?: boolean + isBigText?: boolean bigText?: PortableTextBlock[] action?: (LinkSelector | DownloadableFile | DownloadableImage)[] image: ImageWithAlt @@ -80,7 +80,7 @@ export default { collapsible: true, collapsed: true, }, - hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser, + hidden: ({ parent }: TeaserDocument) => parent.isBigText, }, { name: 'link', @@ -94,8 +94,8 @@ export default { ], fields: [ { - title: 'Big text teaser', - name: 'bigTextTeaser', + title: 'Big text', + name: 'isBigText', type: 'boolean', }, { @@ -111,7 +111,7 @@ export default { input: CompactBlockEditor, }, of: [titleContentType], - hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser, + hidden: ({ parent }: TeaserDocument) => parent.isBigText, }, { name: 'text', @@ -120,12 +120,12 @@ export default { of: [blockContentType], validation: (Rule: Rule) => Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { - if (!(ctx.parent as Teaser)?.bigTextTeaser) { + if (!(ctx.parent as Teaser)?.isBigText) { return validateCharCounterEditor(value, 600) } return true }).warning(), - hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser, + hidden: ({ parent }: TeaserDocument) => parent.isBigText, }, { name: 'bigText', @@ -134,12 +134,12 @@ export default { of: [blockContentTypeForBigText], validation: (Rule: Rule) => Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { - if ((ctx.parent as Teaser)?.bigTextTeaser) { + if ((ctx.parent as Teaser)?.isBigText) { return validateCharCounterEditor(value, 600) } return true }), - hidden: ({ parent }: TeaserDocument) => !parent.bigTextTeaser, + hidden: ({ parent }: TeaserDocument) => !parent.isBigText, }, { name: 'action', @@ -211,34 +211,28 @@ export default { select: { title: 'title', text: 'text', - bigTextTeaser: 'bigTextTeaser', + isBigText: 'isBigText', bigText: 'bigText', image: 'image.asset', }, prepare({ title, text, - bigTextTeaser, + isBigText, bigText, image, }: { title: PortableTextBlock[] text: PortableTextBlock[] - bigTextTeaser: boolean + isBigText: boolean bigText: PortableTextBlock[] image: Reference }) { - let plainTitle = undefined - - if (bigTextTeaser) { - plainTitle = bigText ? blocksToText(bigText) : undefined - } else { - plainTitle = title || text ? blocksToText(title || text) : undefined - } + const plainTitle = isBigText ? blocksToText(bigText) : blocksToText(title || text) return { - title: plainTitle || 'Missing title/text', - subtitle: bigTextTeaser ? 'Big text teaser component' : 'Teaser component', + title: plainTitle || 'Missing title/content', + subtitle: isBigText ? 'Teaser component (BIG TEXT)' : 'Teaser component', media: image, } }, diff --git a/sanityv3/schemas/objects/textBlock.tsx b/sanityv3/schemas/objects/textBlock.tsx index 14b3a8340..533fb7df5 100644 --- a/sanityv3/schemas/objects/textBlock.tsx +++ b/sanityv3/schemas/objects/textBlock.tsx @@ -1,10 +1,9 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { text_field } from '@equinor/eds-icons' -import type { Reference, Rule } from 'sanity' +import type { PortableTextBlock, Reference, Rule, SanityDocument, ValidationContext } from 'sanity' import type { ColorSelectorValue } from '../components/ColorSelector' import blocksToText from '../../helpers/blocksToText' import { EdsIcon } from '../../icons' -import { SchemaType } from '../../types' import CompactBlockEditor from '../components/CompactBlockEditor' import { configureBlockContent, configureTitleBlockContent } from '../editors' import { validateComponentAnchor } from '../validations/validateAnchorReference' @@ -16,6 +15,7 @@ const blockContentType = configureBlockContent({ h4: false, attachment: false, }) + const ingressContentType = configureBlockContent({ h1: false, h2: false, @@ -23,6 +23,21 @@ const ingressContentType = configureBlockContent({ h4: false, attachment: false, }) + +const ingressContentTypeForBigText = configureBlockContent({ + h1: false, + h2: false, + h3: false, + h4: false, + attachment: false, + smallText: false, + normalTextOverride: { + title: 'Normal', + value: 'normal', + component: ({ children }: { children: React.ReactNode }) => {children}, + }, +}) + const titleContentType = configureTitleBlockContent() type TextBlock = { @@ -31,12 +46,18 @@ type TextBlock = { anchor?: string ingress?: string text?: string + isBigText?: boolean + bigText?: PortableTextBlock[] action?: Reference[] splitList?: boolean overrideButtonStyle?: boolean background?: ColorSelectorValue } +type TextBlockDocument = { + parent: TextBlock +} + export default { name: 'textBlock', title: 'Text block', @@ -50,6 +71,7 @@ export default { collapsible: true, collapsed: true, }, + hidden: ({ parent }: TextBlockDocument) => parent.isBigText, }, { title: 'Eyebrow headline', @@ -59,6 +81,7 @@ export default { collapsible: true, collapsed: true, }, + hidden: ({ parent }: TextBlockDocument) => parent.isBigText, }, { title: 'Call to action(s)', @@ -84,6 +107,11 @@ export default { }, ], fields: [ + { + title: 'Big text', + name: 'isBigText', + type: 'boolean', + }, { name: 'image', type: 'imageWithAlt', @@ -105,7 +133,11 @@ export default { input: CompactBlockEditor, }, of: [titleContentType], - validation: (Rule: SchemaType.ValidationRule) => Rule.required().warning('A title is recommended'), + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => + !value && !(ctx.parent as TextBlock)?.isBigText ? 'A title is recommended' : true, + ).warning(), + hidden: ({ parent }: TextBlockDocument) => parent.isBigText, }, { name: 'anchor', @@ -124,6 +156,18 @@ export default { title: 'Ingress', type: 'array', of: [ingressContentType], + hidden: ({ parent }: TextBlockDocument) => parent.isBigText, + }, + { + name: 'bigIngress', + title: 'Ingress', + type: 'array', + of: [ingressContentTypeForBigText], + hidden: ({ parent }: TextBlockDocument) => !parent.isBigText, + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => + !value && (ctx.parent as TextBlock)?.isBigText ? 'Ingress is required' : true, + ), }, { name: 'text', @@ -176,27 +220,27 @@ export default { title: 'title', ingress: 'ingress', text: 'text', - }, - prepare({ title = [], ingress, text }: { title: any[]; ingress: any; text: any }) { - const textBlock = (text || []).find((introBlock: any) => introBlock._type === 'block') - const ingressBlock = (ingress || []).find((introBlock: any) => introBlock._type === 'block') - const plainTitle = title ? blocksToText(title) : undefined + isBigText: 'isBigText', + bigIngress: 'bigIngress', + }, + prepare({ + title, + isBigText, + bigIngress, + ingress, + text, + }: { + title: PortableTextBlock[] + ingress: PortableTextBlock[] + isBigText: boolean + bigIngress: PortableTextBlock[] + text: PortableTextBlock[] + }) { + const plainTitle = isBigText ? blocksToText(bigIngress) : blocksToText(title || ingress || text) return { - title: - plainTitle || - (textBlock && - textBlock.children - .filter((child: any) => child._type === 'span') - .map((span: any) => span.text) - .join('')) || - (ingressBlock && - ingressBlock.children - .filter((child: any) => child._type === 'span') - .map((span: any) => span.text) - .join('')) || - 'Missing content!', - subtitle: `Text block component.`, + title: plainTitle || 'Missing title/content', + subtitle: isBigText ? 'Text block component (BIG TEXT)' : 'Text block component', media: EdsIcon(text_field), } }, diff --git a/web/lib/queries/common/pageContentFields.ts b/web/lib/queries/common/pageContentFields.ts index 5f797f200..d39d5143b 100644 --- a/web/lib/queries/common/pageContentFields.ts +++ b/web/lib/queries/common/pageContentFields.ts @@ -17,9 +17,9 @@ const pageContentFields = /* groq */ ` "id": _key, overline, title, - bigTextTeaser, + isBigText, "text": select( - bigTextTeaser => + isBigText => bigText[]{..., ${markDefs}}, text[]{..., ${markDefs}} ), @@ -44,10 +44,12 @@ const pageContentFields = /* groq */ ` image, overline, title, - ingress[]{ - ..., - ${markDefs}, - }, + isBigText, + "ingress": select( + isBigText => + bigIngress[]{..., ${markDefs}}, + ingress[]{..., ${markDefs}} + ), text[]{ ..., ${markDefs}, diff --git a/web/pageComponents/shared/Teaser.tsx b/web/pageComponents/shared/Teaser.tsx index 89ea76fe0..d272c4ace 100644 --- a/web/pageComponents/shared/Teaser.tsx +++ b/web/pageComponents/shared/Teaser.tsx @@ -70,7 +70,7 @@ const TeaserAction = ({ action }: { action: LinkData }) => { } const Teaser = ({ data, anchor }: TeaserProps) => { - const { title, overline, text, image, action, designOptions, bigTextTeaser } = data + const { title, overline, text, image, action, designOptions, isBigText } = data const { background, imageSize, imagePosition } = designOptions if ([title, overline, text, image?.asset, action].every((i) => !i)) { @@ -89,15 +89,13 @@ const Teaser = ({ data, anchor }: TeaserProps) => { {image?.asset && } - {bigTextTeaser ? ( + {isBigText ? ( text && ( { - return {children} - }, + normal: ({ children }: { children: React.ReactNode }) => {children}, } as BlockType, }} /> diff --git a/web/pageComponents/topicPages/TextBlock.tsx b/web/pageComponents/topicPages/TextBlock.tsx index a772f7c29..2cf30714c 100644 --- a/web/pageComponents/topicPages/TextBlock.tsx +++ b/web/pageComponents/topicPages/TextBlock.tsx @@ -1,4 +1,4 @@ -import { Eyebrow, BackgroundContainer } from '@components' +import { Eyebrow, BackgroundContainer, Text } from '@components' import IngressText from '../shared/portableText/IngressText' import RichText from '../shared/portableText/RichText' import TitleText from '../shared/portableText/TitleText' @@ -6,6 +6,7 @@ import Image, { Ratios } from '../shared/SanityImage' import styled from 'styled-components' import type { TextBlockData } from '../../types/types' import CallToActions from './CallToActions' +import { BlockType } from '../shared/portableText/helpers/defaultSerializers' export const StyledTextBlockWrapper = styled(BackgroundContainer)<{ id: string | undefined }>` ${({ id }) => @@ -62,6 +63,7 @@ const TextBlock = ({ data, anchor }: TextBlockProps) => { callToActions, splitList, overrideButtonStyle = false, + isBigText, } = data /* Don't render the component if it only has an eyebrow */ if (!title && !ingress && !text && (!callToActions || callToActions.length === 0)) return null @@ -70,14 +72,29 @@ const TextBlock = ({ data, anchor }: TextBlockProps) => { return ( - {image?.asset && ( - - - + {isBigText ? ( + ingress && ( + {children}, + } as BlockType, + }} + /> + ) + ) : ( + <> + {image?.asset && ( + + + + )} + {overline && {overline}} + {title && } + {ingress && } + )} - {overline && {overline}} - {title && } - {ingress && } {text && ( diff --git a/web/types/types.ts b/web/types/types.ts index f6498a72e..1ad4bc52b 100644 --- a/web/types/types.ts +++ b/web/types/types.ts @@ -261,6 +261,7 @@ export type DesignOptions = { imagePosition?: TeaserImagePosition imageSize?: TeaserImageSize } + export type TextBlockData = { type: string id: string @@ -268,6 +269,7 @@ export type TextBlockData = { image?: ImageWithAlt overline?: string text: PortableTextBlock[] + isBigText?: boolean ingress: PortableTextBlock[] callToActions?: LinkData[] splitList?: boolean @@ -289,7 +291,7 @@ export type TeaserData = { title: PortableTextBlock[] text: PortableTextBlock[] overline?: string - bigTextTeaser?: boolean + isBigText?: boolean image: ImageWithAlt action?: LinkData designOptions: DesignOptions