Skip to content

Commit

Permalink
✨ Add big text teaser component #1890
Browse files Browse the repository at this point in the history
  • Loading branch information
fernandolucchesi committed Oct 2, 2023
1 parent d24867e commit 2b2a9a0
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 33 deletions.
8 changes: 7 additions & 1 deletion sanityv3/schemas/editors/blockContentType.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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' },
Expand Down
80 changes: 73 additions & 7 deletions sanityv3/schemas/objects/teaser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -25,7 +25,7 @@ const imageAlignmentOptions = [
{ value: 'right', icon: RightAlignedImage },
]

const blockContentType = configureBlockContent({
const blockConfig = {
h1: false,
h2: false,
h3: false,
Expand All @@ -34,20 +34,38 @@ 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 }) => <span style={{ fontSize: '42px' }}>{children}</span>,
},
})

export type Teaser = {
_type: 'teaser'
overline?: string
title?: PortableTextBlock[]
text?: PortableTextBlock[]
bigTextTeaser?: boolean
bigText?: PortableTextBlock[]
action?: (LinkSelector | DownloadableFile | DownloadableImage)[]
image: ImageWithAlt
imagePosition?: string
imageSize?: string
background?: ColorSelectorValue
}

type TeaserDocument = {
parent: Teaser
}

export default {
name: 'teaser',
title: 'Teaser',
Expand All @@ -62,6 +80,7 @@ export default {
collapsible: true,
collapsed: true,
},
hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser,
},
{
name: 'link',
Expand All @@ -74,6 +93,11 @@ export default {
},
],
fields: [
{
title: 'Big text teaser',
name: 'bigTextTeaser',
type: 'boolean',
},
{
name: 'overline',
title: 'Eyebrow',
Expand All @@ -87,14 +111,35 @@ export default {
input: CompactBlockEditor,
},
of: [titleContentType],
hidden: ({ parent }: TeaserDocument) => parent.bigTextTeaser,
},
{
name: 'text',
title: 'Text content',
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',
Expand Down Expand Up @@ -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,
}
},
Expand Down
5 changes: 3 additions & 2 deletions web/components/src/Text/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const StyledText = styled(Typography)<StyledTextProps>`
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);
& + & {
Expand Down Expand Up @@ -41,7 +41,7 @@ const StyledText = styled(Typography)<StyledTextProps>`
`

export type TextProps = {
size?: 'regular' | 'md' | 'small'
size?: 'regular' | 'md' | 'small' | 'big'
bold?: boolean
italic?: boolean
centered?: boolean
Expand All @@ -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<HTMLDivElement, TextProps>(function Text(
Expand Down
14 changes: 8 additions & 6 deletions web/lib/queries/common/pageContentFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
Expand Down
28 changes: 22 additions & 6 deletions web/pageComponents/shared/Teaser.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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

Expand Down Expand Up @@ -55,9 +56,9 @@ const TeaserAction = ({ action }: { action: LinkData }) => {
if (action.type === 'internalUrl') {
const locale = getLocaleFromName(action.link?.lang)
return (
<Link href={url} locale={locale} variant="readMore" aria-label={action.ariaLabel}>
{action.label}
</Link>
<Link href={url} locale={locale} variant="readMore" aria-label={action.ariaLabel}>
{action.label}
</Link>
)
}

Expand All @@ -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)) {
Expand All @@ -92,7 +93,22 @@ const Teaser = ({ data, anchor }: TeaserProps) => {

{title && <TitleText value={title} />}

{text && <IngressText value={text} />}
{text && (
<IngressText
value={text}
components={
bigTextTeaser
? {
block: {
normal: ({ children }: { children: React.ReactNode }) => {
return <Text size="big">{children}</Text>
},
} as BlockType,
}
: {}
}
/>
)}
{action && <TeaserAction action={action} />}
</Content>
</StyledEnvisTeaser>
Expand Down
21 changes: 10 additions & 11 deletions web/pageComponents/shared/portableText/IngressText.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -57,14 +56,14 @@ type IngressTextProps = {
centered?: boolean
} & PortableTextProps

const IngressText = ({ value, centered = false, components = {}, ...props }: IngressTextProps) => (
<PortableText
value={value}
// eslint-disable-next-line
// @ts-ignore: Look into the correct way of doing this
components={{ ...defaultComponents(centered), ...components }}
{...props}
/>
)
const IngressText = ({ value, centered = false, components = {}, ...props }: IngressTextProps) => {
return (
<PortableText
value={value}
components={{ ...defaultComponents(centered), ...components } as PortableTextReactComponents}
{...props}
/>
)
}

export default IngressText
1 change: 1 addition & 0 deletions web/styles/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions web/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ export type TeaserData = {
title: PortableTextBlock[]
text: PortableTextBlock[]
overline?: string
bigTextTeaser?: boolean
image: ImageWithAlt
action?: LinkData
designOptions: DesignOptions
Expand Down

0 comments on commit 2b2a9a0

Please sign in to comment.