From 2f3adb09da81eeff8ca649488cde535c8bae121f Mon Sep 17 00:00:00 2001 From: Fernando Lucchesi Date: Mon, 2 Oct 2023 13:29:36 -0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20big=20text=20teaser=20compone?= =?UTF-8?q?nt=20#1890?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sanityv3/schemas/editors/blockContentType.tsx | 8 +- sanityv3/schemas/objects/teaser.tsx | 80 +++++++++++++++++-- web/components/src/Text/Text.tsx | 5 +- web/lib/queries/common/pageContentFields.ts | 14 ++-- web/pageComponents/shared/Teaser.tsx | 28 +++++-- .../shared/portableText/IngressText.tsx | 21 +++-- web/styles/settings.ts | 1 + web/types/types.ts | 1 + 8 files changed, 125 insertions(+), 33 deletions(-) diff --git a/sanityv3/schemas/editors/blockContentType.tsx b/sanityv3/schemas/editors/blockContentType.tsx index fc433614a..377a7e20a 100644 --- a/sanityv3/schemas/editors/blockContentType.tsx +++ b/sanityv3/schemas/editors/blockContentType.tsx @@ -17,6 +17,11 @@ export type BlockContentProps = { attachment?: boolean lists?: boolean smallText?: boolean + normalTextOverride?: { + title: string + value: 'normal' + component?: ({ children }: { children: React.ReactNode }) => JSX.Element + } } const SmallTextRender = (props: any) => { const { children } = props @@ -34,11 +39,12 @@ export const configureBlockContent = (options: BlockContentProps = {}): BlockFie attachment = false, lists = true, smallText = true, + normalTextOverride = { title: 'Normal', value: 'normal' }, } = options const config: BlockFieldType = { type: 'block', - styles: [{ title: 'Normal', value: 'normal' }], + styles: [normalTextOverride], lists: lists ? [ { title: 'Numbered', value: 'number' }, diff --git a/sanityv3/schemas/objects/teaser.tsx b/sanityv3/schemas/objects/teaser.tsx index fbf94ff99..c9688902f 100644 --- a/sanityv3/schemas/objects/teaser.tsx +++ b/sanityv3/schemas/objects/teaser.tsx @@ -6,7 +6,7 @@ import CompactBlockEditor from '../components/CompactBlockEditor' import { configureBlockContent, configureTitleBlockContent } from '../editors' import { validateCharCounterEditor } from '../validations/validateCharCounterEditor' -import type { PortableTextBlock, Reference, Rule } from 'sanity' +import type { PortableTextBlock, Reference, Rule, ValidationContext } from 'sanity' import type { DownloadableImage } from './downloadableImage' import type { DownloadableFile } from './files' import type { ImageWithAlt } from './imageWithAlt' @@ -25,7 +25,7 @@ const imageAlignmentOptions = [ { value: 'right', icon: RightAlignedImage }, ] -const blockContentType = configureBlockContent({ +const blockConfig = { h1: false, h2: false, h3: false, @@ -34,6 +34,18 @@ const blockContentType = configureBlockContent({ externalLink: false, attachment: false, lists: false, +} + +const blockContentType = configureBlockContent({ ...blockConfig }) + +const blockContentTypeForBigText = configureBlockContent({ + ...blockConfig, + smallText: false, + normalTextOverride: { + title: 'Normal', + value: 'normal', + component: ({ children }: { children: React.ReactNode }) => {children}, + }, }) export type Teaser = { @@ -41,6 +53,8 @@ export type Teaser = { overline?: string title?: PortableTextBlock[] text?: PortableTextBlock[] + bigTextTeaser?: boolean + bigText?: PortableTextBlock[] action?: (LinkSelector | DownloadableFile | DownloadableImage)[] image: ImageWithAlt imagePosition?: string @@ -48,6 +62,10 @@ export type Teaser = { background?: ColorSelectorValue } +type TeaserDocument = { + parent: Teaser +} + export default { name: 'teaser', title: 'Teaser', @@ -62,6 +80,7 @@ export default { collapsible: true, collapsed: true, }, + hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser, }, { name: 'link', @@ -74,6 +93,11 @@ export default { }, ], fields: [ + { + title: 'Big text teaser', + name: 'bigTextTeaser', + type: 'boolean', + }, { name: 'overline', title: 'Eyebrow', @@ -87,6 +111,7 @@ export default { input: CompactBlockEditor, }, of: [titleContentType], + hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser, }, { name: 'text', @@ -94,7 +119,27 @@ export default { type: 'array', of: [blockContentType], validation: (Rule: Rule) => - Rule.custom((value: PortableTextBlock[]) => validateCharCounterEditor(value, 600)).warning(), + Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { + if (!(ctx.parent as Teaser)?.bigTextTeaser) { + return validateCharCounterEditor(value, 600) + } + return true + }).warning(), + hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser, + }, + { + name: 'bigText', + title: 'Text content', + type: 'array', + of: [blockContentTypeForBigText], + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { + if ((ctx.parent as Teaser)?.bigTextTeaser) { + return validateCharCounterEditor(value, 600) + } + return true + }), + hidden: ({ parent }: TeaserDocument) => !parent.bigTextTeaser, }, { name: 'action', @@ -165,14 +210,35 @@ export default { preview: { select: { title: 'title', + text: 'text', + bigTextTeaser: 'bigTextTeaser', + bigText: 'bigText', image: 'image.asset', }, - prepare({ title, image }: { title: PortableTextBlock[]; image: Reference }) { - const plainTitle = title ? blocksToText(title) : undefined + prepare({ + title, + text, + bigTextTeaser, + bigText, + image, + }: { + title: PortableTextBlock[] + text: PortableTextBlock[] + bigTextTeaser: boolean + bigText: PortableTextBlock[] + image: Reference + }) { + let plainTitle = undefined + + if (bigTextTeaser) { + plainTitle = bigText ? blocksToText(bigText) : undefined + } else { + plainTitle = title || text ? blocksToText(title || text) : undefined + } return { - title: plainTitle || 'Missing title!', - subtitle: 'Teaser component', + title: plainTitle || 'Missing title/text', + subtitle: bigTextTeaser ? 'Big text teaser component' : 'Teaser component', media: image, } }, diff --git a/web/components/src/Text/Text.tsx b/web/components/src/Text/Text.tsx index 4eb429fdc..e68246de3 100644 --- a/web/components/src/Text/Text.tsx +++ b/web/components/src/Text/Text.tsx @@ -12,7 +12,7 @@ const StyledText = styled(Typography)` font-size: var(--size); line-height: var(--lineHeight-3); /* @TODO: Let's consider to move all the margin woo to the article layout - We should. Not move, but scope. For both news and topic pages. But this will + We should. Not move, but scope. For both news and topic pages. But this will require a lot of retest, since in some of the uses cases we will need to reintroduce the margin */ margin-bottom: var(--space-medium); & + & { @@ -41,7 +41,7 @@ const StyledText = styled(Typography)` ` export type TextProps = { - size?: 'regular' | 'md' | 'small' + size?: 'regular' | 'md' | 'small' | 'big' bold?: boolean italic?: boolean centered?: boolean @@ -54,6 +54,7 @@ const sizes = { regular: 'var(--typeScale-1)', md: 'var(--typeScale-2)', small: 'var(--typeScale-0)', + big: 'var(--typeScale-4_5)', } export const Text = forwardRef(function Text( diff --git a/web/lib/queries/common/pageContentFields.ts b/web/lib/queries/common/pageContentFields.ts index 3893d7fe2..5f797f200 100644 --- a/web/lib/queries/common/pageContentFields.ts +++ b/web/lib/queries/common/pageContentFields.ts @@ -12,21 +12,23 @@ import promoteMagazine from './promotions/promoteMagazine' import { publishDateTimeQuery } from './publishDateTime' const pageContentFields = /* groq */ ` - _type == "teaser" =>{ + _type == "teaser" => { "type": _type, "id": _key, overline, title, - text[]{ - ..., - ${markDefs}, - }, + bigTextTeaser, + "text": select( + bigTextTeaser => + bigText[]{..., ${markDefs}}, + text[]{..., ${markDefs}} + ), "designOptions": { "background": coalesce(background.title, 'White'), "imagePosition": coalesce(imagePosition, 'left'), imageSize, }, - "image": image{ + "image": image { ..., "extension": asset-> extension }, diff --git a/web/pageComponents/shared/Teaser.tsx b/web/pageComponents/shared/Teaser.tsx index 6b59b094e..c6bbd2102 100644 --- a/web/pageComponents/shared/Teaser.tsx +++ b/web/pageComponents/shared/Teaser.tsx @@ -1,4 +1,4 @@ -import { Teaser as EnvisTeaser, Link, Eyebrow, BackgroundContainer } from '@components' +import { Teaser as EnvisTeaser, Link, Eyebrow, BackgroundContainer, Text } from '@components' import styled from 'styled-components' import IngressText from './portableText/IngressText' import TitleText from './portableText/TitleText' @@ -9,6 +9,7 @@ import { getUrlFromAction } from '../../common/helpers/getUrlFromAction' import type { TeaserData, ImageWithAlt, LinkData } from '../../types/types' import { getLocaleFromName } from '../../lib/localization' +import { BlockType } from './portableText/helpers/defaultSerializers' const { Content, Media } = EnvisTeaser @@ -55,9 +56,9 @@ const TeaserAction = ({ action }: { action: LinkData }) => { if (action.type === 'internalUrl') { const locale = getLocaleFromName(action.link?.lang) return ( - - {action.label} - + + {action.label} + ) } @@ -69,7 +70,7 @@ const TeaserAction = ({ action }: { action: LinkData }) => { } const Teaser = ({ data, anchor }: TeaserProps) => { - const { title, overline, text, image, action, designOptions } = data + const { title, overline, text, image, action, designOptions, bigTextTeaser } = data const { background, imageSize, imagePosition } = designOptions if ([title, overline, text, image?.asset, action].every((i) => !i)) { @@ -92,7 +93,22 @@ const Teaser = ({ data, anchor }: TeaserProps) => { {title && } - {text && } + {text && ( + { + return {children} + }, + } as BlockType, + } + : {} + } + /> + )} {action && } diff --git a/web/pageComponents/shared/portableText/IngressText.tsx b/web/pageComponents/shared/portableText/IngressText.tsx index c2a97b098..0db2ba4db 100644 --- a/web/pageComponents/shared/portableText/IngressText.tsx +++ b/web/pageComponents/shared/portableText/IngressText.tsx @@ -1,5 +1,4 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { PortableText, PortableTextProps } from '@portabletext/react' +import { PortableText, PortableTextProps, PortableTextReactComponents } from '@portabletext/react' import styled from 'styled-components' import { h3Heading, h2Heading, Sub, Sup, ExternalLink, InternalLink } from './components' import isEmpty from './helpers/isEmpty' @@ -57,14 +56,14 @@ type IngressTextProps = { centered?: boolean } & PortableTextProps -const IngressText = ({ value, centered = false, components = {}, ...props }: IngressTextProps) => ( - -) +const IngressText = ({ value, centered = false, components = {}, ...props }: IngressTextProps) => { + return ( + + ) +} export default IngressText diff --git a/web/styles/settings.ts b/web/styles/settings.ts index d053bab7b..af9f08e68 100644 --- a/web/styles/settings.ts +++ b/web/styles/settings.ts @@ -98,6 +98,7 @@ export const typography = css` --typeScale-2: clamp(calc(19.20 / 16 * 1rem), 0.54vw + 1.07rem, calc(27.50 / 16 * 1rem)); --typeScale-3: clamp(calc(23.04 / 16 * 1rem), 0.73vw + 1.27rem, calc(34.38 / 16 * 1rem)); --typeScale-4: clamp(calc(27.65 / 16 * 1rem), 0.99vw + 1.5rem, calc(42.97 / 16 * 1rem)); + --typeScale-4_5: clamp(calc(33.73 / 16 * 1rem), 1.38vw + 1.785rem, calc(55.055 / 16 * 1rem)); --typeScale-5: clamp(calc(39.81 / 16 * 1rem), 1.77vw + 2.07rem, calc(67.14 / 16 * 1rem)); // search and replace, then remove diff --git a/web/types/types.ts b/web/types/types.ts index 663174645..f6498a72e 100644 --- a/web/types/types.ts +++ b/web/types/types.ts @@ -289,6 +289,7 @@ export type TeaserData = { title: PortableTextBlock[] text: PortableTextBlock[] overline?: string + bigTextTeaser?: boolean image: ImageWithAlt action?: LinkData designOptions: DesignOptions