diff --git a/sanityv3/icons/customIcons.tsx b/sanityv3/icons/customIcons.tsx index 861586e9b..2c0068989 100644 --- a/sanityv3/icons/customIcons.tsx +++ b/sanityv3/icons/customIcons.tsx @@ -152,6 +152,34 @@ export const ContentRightImage = (): JSX.Element => ( /> ) +export const ContentBottomCenterImage = (): JSX.Element => ( + + + +) +export const ContentBottomLeftImage = (): JSX.Element => ( + + + +) export const RightAlignedImage = (): JSX.Element => ( { const { options } = schemaType const colors = (options?.colors as ThemeSelectorValue[]) || themeColors + const theSelectorUniqueId = useId() const handleSelect = useCallback( (selected: ThemeSelectorValue) => { @@ -83,10 +84,10 @@ export const ThemeSelector = ({ value, onChange, schemaType }: ThemeSelectorProp {colors.map((colorItem: ThemeSelectorValue) => { - const { background } = getColorForTheme(colorItem.value) + const { background, highlight } = getColorForTheme(colorItem.value) return ( { switch (pattern) { case 1: return { + //moss green light background: { value: defaultColors[1].value, key: defaultColors[1].key, }, + //energy red highlight: { value: defaultColors[8].value, key: defaultColors[8].key, @@ -36,8 +60,8 @@ export const getColorForTheme = (pattern: number) => { key: defaultColors[2].key, }, highlight: { - value: defaultColors[8].value, - key: defaultColors[8].key, + value: defaultColors[9].value, + key: defaultColors[9].key, }, } case 3: @@ -47,8 +71,8 @@ export const getColorForTheme = (pattern: number) => { key: defaultColors[3].key, }, highlight: { - value: defaultColors[8].value, - key: defaultColors[8].key, + value: defaultColors[9].value, + key: defaultColors[9].key, }, } case 4: @@ -58,8 +82,8 @@ export const getColorForTheme = (pattern: number) => { key: defaultColors[4].key, }, highlight: { - value: defaultColors[8].value, - key: defaultColors[8].key, + value: defaultColors[9].value, + key: defaultColors[9].key, }, } case 5: @@ -68,7 +92,10 @@ export const getColorForTheme = (pattern: number) => { value: defaultColors[5].value, key: defaultColors[5].key, }, - highlight: {}, + highlight: { + value: defaultColors[9].value, + key: defaultColors[9].key, + }, } case 6: return { @@ -122,6 +149,41 @@ export const getColorForTheme = (pattern: number) => { key: defaultColors[6].key, }, } + case 11: + return { + background: { + value: defaultColors[0].value, + key: defaultColors[0].key, + }, + highlight: { + value: defaultColors[9].value, + key: defaultColors[9].key, + }, + } + case 12: + return { + background: { + value: defaultColors[9].value, + key: defaultColors[9].key, + }, + highlight: { + value: defaultColors[0].value, + key: defaultColors[0].key, + }, + } + case 13: { + //black on moss green light + return { + background: { + value: defaultColors[1].value, + key: defaultColors[1].key, + }, + highlight: { + value: defaultColors[9].value, + key: defaultColors[9].key, + }, + } + } case 0: default: diff --git a/sanityv3/schemas/defaultColors.js b/sanityv3/schemas/defaultColors.js index ca25f7f27..eeefbfb7b 100644 --- a/sanityv3/schemas/defaultColors.js +++ b/sanityv3/schemas/defaultColors.js @@ -25,4 +25,5 @@ export const defaultColors = [ { title: 'Mid Blue', value: colors.blue[50], key: 'blue-50', dark: true }, { title: 'Mid Green', value: colors.green[50], key: 'green-50', dark: false }, { title: 'Energy Red', value: colors['energy-red'][100], key: 'energy-red-50', dark: false, onlyTextColor: true }, + { title: 'Black', value: 'rgba(61, 61, 61, 1)', key: 'slate-80', dark: false, onlyTextColor: true }, ] diff --git a/sanityv3/schemas/editors/index.ts b/sanityv3/schemas/editors/index.ts index 5f066b0c8..3fe12c55d 100644 --- a/sanityv3/schemas/editors/index.ts +++ b/sanityv3/schemas/editors/index.ts @@ -1,2 +1,3 @@ export * from './blockContentType' export * from './titleEditorContentType' +export * from './themedTitleEditorContentType' diff --git a/sanityv3/schemas/editors/themedTitleEditorContentType.tsx b/sanityv3/schemas/editors/themedTitleEditorContentType.tsx new file mode 100644 index 000000000..5d6844eb0 --- /dev/null +++ b/sanityv3/schemas/editors/themedTitleEditorContentType.tsx @@ -0,0 +1,95 @@ +import { SuperScriptRenderer, SubScriptRenderer, StrikeThroughRenderer } from '../components' +import { IconSuperScript, IconSubScript } from '../../icons' +import { StrikethroughIcon } from '@sanity/icons' +import { BlockDefinition } from 'sanity' +import { em, ExtraLargeTextRender, LargeTextRender } from './blockContentType' + +export type ThemedTitleContentProps = { + normalText?: boolean + largeText?: boolean + extraLargeText?: boolean + twoXLText?: boolean +} + +const TwoXLTextRender = (props: any) => { + const { children } = props + return {children} +} + +// TODO: Add relevant styles for titles (i.e. highlighted text) +export const configureThemedTitleBlockContent = (options: ThemedTitleContentProps = {}): BlockDefinition => { + const { largeText = true, extraLargeText = false, twoXLText = false, normalText = true } = options + + const config: BlockDefinition = { + type: 'block', + name: 'block', + styles: [], + lists: [], + marks: { + decorators: [ + { title: 'Strong', value: 'strong' }, + { title: 'Emphasis', value: 'em' }, + { + title: 'Strikethrough', + value: 's', + icon: StrikethroughIcon, + component: StrikeThroughRenderer, + }, + { + title: 'Sub', + value: 'sub', + icon: IconSubScript, + component: SubScriptRenderer, + }, + { + title: 'Super', + value: 'sup', + icon: IconSuperScript, + component: SuperScriptRenderer, + }, + ], + annotations: [], + }, + } + + const normalTextConfig = { title: 'Normal', value: 'normal' } + // Since one cant disable value normal, when title should only have large and not normal, make normal like Large + // Make sure that the block serializer picks up this 'as large' for normal text + const normalAsLargeTextConfig = { title: 'Large', value: 'normal', blockEditor: { render: LargeTextRender } } + + const largeTextConfig = { + title: 'Large text', + value: 'largeText', + component: LargeTextRender, + } + const extraLargeTextConfig = { + title: 'Extra large text', + value: 'extraLargeText', + component: ExtraLargeTextRender, + } + const twoXLTextConfig = { + title: '2XL text', + value: 'twoXLText', + component: TwoXLTextRender, + } + + if (normalText) { + config?.styles?.push(normalTextConfig) + } + if (!normalText && largeText) { + config?.styles?.push(normalAsLargeTextConfig) + } + if (normalText && largeText) { + config?.styles?.push(largeTextConfig) + } + if (extraLargeText) { + config?.styles?.push(extraLargeTextConfig) + } + if (twoXLText) { + config?.styles?.push(twoXLTextConfig) + } + + return config +} + +export default configureThemedTitleBlockContent() diff --git a/sanityv3/schemas/objects/background/imageBackground.tsx b/sanityv3/schemas/objects/background/imageBackground.tsx index 31f57cb23..dc55b60cd 100644 --- a/sanityv3/schemas/objects/background/imageBackground.tsx +++ b/sanityv3/schemas/objects/background/imageBackground.tsx @@ -33,6 +33,10 @@ export default defineType({ name: 'useAnimation', type: 'boolean', description: 'Animates content over the background image.', + hidden: ({ parent }: any) => { + console.log('parent in image background', parent) + return false + }, }), defineField({ title: 'Apply light gradient', @@ -43,7 +47,7 @@ export default defineType({ defineField({ name: 'contentAlignment', title: 'Content Alignment', - description: 'Select the content alignment on larger screens.', + description: 'Select the content alignment on larger screens. Bottom alignments can be kept on mobile', type: 'string', initialValue: 'left', components: { diff --git a/sanityv3/schemas/objects/grid/cellTypes/gridTeaser.tsx b/sanityv3/schemas/objects/grid/cellTypes/gridTeaser.tsx index 772dbb45f..5b778a20c 100644 --- a/sanityv3/schemas/objects/grid/cellTypes/gridTeaser.tsx +++ b/sanityv3/schemas/objects/grid/cellTypes/gridTeaser.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/display-name */ import blocksToText from '../../../../helpers/blocksToText' -import { configureBlockContent } from '../../../editors' +import { configureBlockContent, configureThemedTitleBlockContent } from '../../../editors' import { validateCharCounterEditor } from '../../../validations/validateCharCounterEditor' import type { PortableTextBlock, Reference, Rule, ValidationContext } from 'sanity' @@ -11,12 +11,14 @@ import type { LinkSelector } from '../../linkSelector' import type { ColorSelectorValue } from '../../../components/ColorSelector' import { LeftAlignedImage, RightAlignedImage } from '../../../../icons' import { RadioIconSelector } from '../../../components' +import { fromLargerTextThemeColors, fromNormalTextThemeColors } from '../../../components/ThemeSelector' const blockContentType = configureBlockContent({ smallText: true, largeText: true, extraLargeText: true, }) +const themedTitleContentType = configureThemedTitleBlockContent({ normalText: false, extraLargeText: true }) const imageAlignmentOptions = [ { value: 'left', icon: LeftAlignedImage }, @@ -26,6 +28,8 @@ const imageAlignmentOptions = [ export type GridTeaser = { _type: 'gridTeaser' content?: PortableTextBlock[] + themedContent?: PortableTextBlock[] + useExtendedThemes?: boolean quote: string author: string authorTitle?: string @@ -34,6 +38,9 @@ export type GridTeaser = { imagePosition?: string background?: ColorSelectorValue } +type GridTeaserDocument = { + parent: GridTeaser +} export default { name: 'gridTeaser', @@ -61,11 +68,29 @@ export default { }, ], fields: [ + { + title: 'Use extended themes', + name: 'useExtendedThemes', + description: 'Enabling this removes normal text style and quote, but gives more theme options', + type: 'boolean', + }, { name: 'content', title: 'Content', type: 'array', of: [blockContentType], + hidden: ({ parent }: GridTeaserDocument) => parent.useExtendedThemes, + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { + return validateCharCounterEditor(value, 600) + }).warning(), + }, + { + name: 'themedContent', + title: 'Themed Content', + type: 'array', + of: [themedTitleContentType], + hidden: ({ parent }: GridTeaserDocument) => !parent.useExtendedThemes, validation: (Rule: Rule) => Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { return validateCharCounterEditor(value, 600) @@ -75,19 +100,22 @@ export default { name: 'quote', type: 'text', title: 'Quote', - description: 'Highlighted quote from the article.', + description: 'Highlighted quote from the article, gets theme from below', rows: 5, + hidden: ({ parent }: GridTeaserDocument) => parent.useExtendedThemes, }, { name: 'author', type: 'string', title: 'Name', + hidden: ({ parent }: GridTeaserDocument) => parent.useExtendedThemes, }, { name: 'authorTitle', type: 'string', title: 'Title', description: 'Optional title for the author.', + hidden: ({ parent }: GridTeaserDocument) => parent.useExtendedThemes, }, { name: 'action', @@ -105,7 +133,7 @@ export default { name: 'image', title: 'Image', type: 'imageWithAlt', - validation: (Rule: Rule) => Rule.required(), + validation: (Rule: Rule) => Rule.custom((value: ImageWithAlt) => (!value.asset ? 'Image is required' : true)), }, { name: 'imagePosition', @@ -130,8 +158,20 @@ export default { { name: 'theme', title: 'Theme', - description: 'If no theme set, normal text color is set', type: 'themeList', + options: { + colors: fromNormalTextThemeColors, + }, + hidden: ({ parent }: GridTeaserDocument) => parent.useExtendedThemes, + }, + { + name: 'themeFromLarger', + title: 'Theme', + type: 'themeList', + options: { + colors: fromLargerTextThemeColors, + }, + hidden: ({ parent }: GridTeaserDocument) => !parent.useExtendedThemes, }, ], preview: { diff --git a/sanityv3/schemas/objects/grid/cellTypes/gridTextBlock.tsx b/sanityv3/schemas/objects/grid/cellTypes/gridTextBlock.tsx index 91edbab3e..ee9b469d2 100644 --- a/sanityv3/schemas/objects/grid/cellTypes/gridTextBlock.tsx +++ b/sanityv3/schemas/objects/grid/cellTypes/gridTextBlock.tsx @@ -2,46 +2,115 @@ import { text_field } from '@equinor/eds-icons' import type { PortableTextBlock, Reference, Rule } from 'sanity' import type { ColorSelectorValue } from '../../../components/ColorSelector' +import CompactBlockEditor from '../../../components/CompactBlockEditor' import blocksToText from '../../../../helpers/blocksToText' import { EdsIcon } from '../../../../icons' import { configureBlockContent } from '../../../editors' +import { configureThemedTitleBlockContent } from '../../../editors/themedTitleEditorContentType' +import { fromLargerTextThemeColors, fromNormalTextThemeColors } from '../../../components/ThemeSelector' +import { capitalizeFirstLetter } from '../../../../helpers/formatters' +import { + ContentRightImage, + ContentLeftImage, + ContentCenterImage, + ContentBottomLeftImage, + ContentBottomCenterImage, +} from '../../../../icons' +import { RadioIconSelector } from '../../../components' const blockContentType = configureBlockContent({ smallText: true, largeText: true, extraLargeText: true, }) +const themedTitleContentType = configureThemedTitleBlockContent({ normalText: false }) +const titleContentType = configureThemedTitleBlockContent() + +const contentAlignmentOptions = [ + { value: 'left', icon: ContentLeftImage }, + { value: 'center', icon: ContentCenterImage }, + { value: 'right', icon: ContentRightImage }, + { value: 'bottom-left', icon: ContentBottomLeftImage }, + { value: 'bottom-center', icon: ContentBottomCenterImage }, +] type GridTextBlock = { + overline?: string + useThemedTitle?: boolean + title?: string content?: string action?: Reference[] background?: ColorSelectorValue } +type GridTextBlockDocument = { + parent: GridTextBlock +} + export default { name: 'gridTextBlock', title: 'Grid Text block', type: 'object', + fieldsets: [ + { + name: 'title', + title: 'Title options', + }, + ], fields: [ { - name: 'content', - title: 'Content', + name: 'overline', + title: 'Eyebrow', + type: 'string', + fieldset: 'title', + }, + { + title: 'Use themed title', + name: 'useThemedTitle', + description: 'Enabling this removes normal text style, but gives more theme options for the title', + type: 'boolean', + fieldset: 'title', + }, + { + name: 'title', type: 'array', - of: [blockContentType], + components: { + input: CompactBlockEditor, + }, + fieldset: 'title', + of: [titleContentType], + hidden: ({ parent }: GridTextBlockDocument) => parent.useThemedTitle, + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[]) => (!value ? 'A title is recommended' : true)).warning(), }, { - title: 'Text Alignment', - name: 'textAlignment', - description: 'Overrides background image alignment', - type: 'string', + name: 'themedTitle', + type: 'array', + components: { + input: CompactBlockEditor, + }, + fieldset: 'title', + of: [themedTitleContentType], + hidden: ({ parent }: GridTextBlockDocument) => !parent.useThemedTitle, + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[]) => (!value ? 'A title is recommended' : true)).warning(), + }, + { + name: 'titleThemeFromLarger', + title: 'Title theme', + type: 'themeList', options: { - list: [ - { title: 'Left', value: 'left' }, - { title: 'Right', value: 'right' }, - { title: 'Center', value: 'center' }, - ], + colors: fromLargerTextThemeColors, }, - initialValue: 'left', + fieldset: 'title', + hidden: ({ parent }: GridTextBlockDocument) => !parent.useThemedTitle, + description: 'Use white text or black text when background image', + }, + { + name: 'content', + title: 'Content', + type: 'array', + of: [blockContentType], }, { name: 'action', @@ -55,20 +124,88 @@ export default { ], validation: (Rule: Rule) => Rule.max(1).error('Only one action is permitted'), }, + { + name: 'contentTheme', + title: 'Content theme', + type: 'themeList', + options: { + colors: fromNormalTextThemeColors, + }, + hidden: ({ parent }: GridTextBlockDocument) => !parent.useThemedTitle, + description: + 'Title theme background will be used if different.Text will then be white/black. Use white or black text when background image', + }, { name: 'theme', + title: 'Theme', type: 'themeList', + options: { + colors: fromNormalTextThemeColors, + }, + hidden: ({ parent }: GridTextBlockDocument) => parent.useThemedTitle, + description: 'Use white or black text when background image', + }, + { + name: 'contentAlignment', + title: 'Content Alignment', + description: 'Select the content alignment on larger screens. Bottom alignments can be kept on mobile', + type: 'string', + initialValue: 'left', + components: { + input: function ({ onChange, value }: { onChange: any; value: string }) { + return ( + + ) + }, + }, }, { - name: 'backgroundImage', - type: 'imageBackground', - title: 'Background Image', - description: 'Content alignment is ignored on this', + name: 'imageBackground', + title: 'Image background', + type: 'object', + fields: [ + { + title: 'Image', + name: 'image', + type: 'image', + options: { + hotspot: true, + collapsed: false, + }, + }, + { + title: 'Apply light gradient', + name: 'useLight', + type: 'boolean', + description: 'Applies a white gradient over semi transparent background image.', + }, + ], + + preview: { + select: { + image: 'image', + useAnimation: 'useAnimation', + contentAlignment: 'contentAlignment', + }, + prepare({ image, contentAlignment }: any) { + return { + title: `Image background`, + subtitle: `${capitalizeFirstLetter(contentAlignment) + ' aligned '} content`, + media: image.asset, + } + }, + }, }, ].filter((e) => e), preview: { select: { - title: 'content', + title: 'title', }, prepare({ title }: { title: PortableTextBlock[] }) { const plainTitle = blocksToText(title) diff --git a/sanityv3/schemas/objects/imageWithAlt.tsx b/sanityv3/schemas/objects/imageWithAlt.tsx index b14d5679e..e26802853 100644 --- a/sanityv3/schemas/objects/imageWithAlt.tsx +++ b/sanityv3/schemas/objects/imageWithAlt.tsx @@ -22,7 +22,6 @@ export default { title: 'Image is decorative', description: 'If this image is purely decorative you can disable the alt tag input here. Please note that this makes the image invisible for screen reader users.', - initialValue: false, }, { name: 'alt', diff --git a/web/components/src/Backgrounds/BackgroundContainer.tsx b/web/components/src/Backgrounds/BackgroundContainer.tsx index bbbc47f48..0e5b07efb 100644 --- a/web/components/src/Backgrounds/BackgroundContainer.tsx +++ b/web/components/src/Backgrounds/BackgroundContainer.tsx @@ -25,10 +25,25 @@ export type BackgroundContainerProps = { renderFragmentWhenPossible?: boolean /** Extended tailwind styling */ twClassName?: string + /** Extended styling when background image */ + scrimClassName?: string + /* On mobile dont split background image and content */ + dontSplit?: boolean } & HTMLAttributes export const BackgroundContainer = forwardRef(function BackgroundContainer( - { background, style, children, className, twClassName = '', id, renderFragmentWhenPossible = false, ...rest }, + { + background, + style, + children, + className = '', + scrimClassName = '', + twClassName = '', + id, + renderFragmentWhenPossible = false, + dontSplit = false, + ...rest + }, ref, ) { const { backgroundImage, type, ...restBackground } = background || {} @@ -37,11 +52,14 @@ export const BackgroundContainer = forwardRef {type === 'backgroundImage' && backgroundImage && ( {children} diff --git a/web/components/src/Backgrounds/ImageBackgroundContainer.tsx b/web/components/src/Backgrounds/ImageBackgroundContainer.tsx index fb5944bce..c1b6d977e 100644 --- a/web/components/src/Backgrounds/ImageBackgroundContainer.tsx +++ b/web/components/src/Backgrounds/ImageBackgroundContainer.tsx @@ -4,12 +4,26 @@ import { ImageBackground } from '../../../types/types' import { twMerge } from 'tailwind-merge' import { useMediaQuery } from '../../../lib/hooks/useMediaQuery' -type ImageBackgroundContainerProps = ImageBackground & HTMLAttributes +type ImageBackgroundContainerProps = { + scrimClassName?: string + /* On mobile dont split background image and content */ + dontSplit?: boolean +} & ImageBackground & + HTMLAttributes const DEFAULT_MAX_WIDTH = 1920 export const ImageBackgroundContainer = forwardRef( function ImageBackgroundContainer( - { image, useAnimation = false, useLight = false, contentAlignment = 'center', children, className }, + { + image, + useAnimation = false, + useLight = false, + contentAlignment = 'center', + children, + className = '', + scrimClassName = '', + dontSplit = false, + }, ref, ) { const props = useSanityLoader(image, DEFAULT_MAX_WIDTH, undefined) @@ -36,20 +50,27 @@ export const ImageBackgroundContainer = forwardRef {/** Scrim */}
{children}
- - ) : isMobile ? ( -
+ + ) : isMobile && !dontSplit ? ( +
{children} -
+ ) : ( -
{/** Scrim */}
{children}
-
+ ) }, ) diff --git a/web/core/Typography/Heading.tsx b/web/core/Typography/Heading.tsx index 8deab12ee..317fb0c35 100644 --- a/web/core/Typography/Heading.tsx +++ b/web/core/Typography/Heading.tsx @@ -9,11 +9,28 @@ import { twMerge } from 'tailwind-merge' export type HeadingProps = { value?: PortableTextBlock[] + noProse?: boolean + serializerClassnames?: { + largeText?: string + normal?: string + extraLargeText?: string + twoXLText?: string + } } & PortableTextProps & TypographyProps & BlockProps -const defaultComponents = ({ variant, as: providedAs, className }: TypographyProps) => { +type DefaultComponentsProps = { + serializerClassnames?: { + largeText?: string + normal?: string + extraLargeText?: string + twoXLText?: string + } + className?: string +} & TypographyProps + +const defaultComponents = ({ variant, as: providedAs, serializerClassnames, className }: DefaultComponentsProps) => { return { block: { h1: ({ children }: PortableTextBlock) => { @@ -38,22 +55,25 @@ const defaultComponents = ({ variant, as: providedAs, className }: TypographyPro ) }, largeText: ({ children }: PortableTextBlock) => { + const classNames = serializerClassnames ? serializerClassnames['largeText'] : className return ( - + <>{children} ) }, extraLargeText: ({ children }: PortableTextBlock) => { + const classNames = serializerClassnames ? serializerClassnames['extraLargeText'] : className return ( - + <>{children} ) }, twoXLText: ({ children }: PortableTextBlock) => { + const classNames = serializerClassnames ? serializerClassnames['twoXLText'] : className return ( - + <>{children} ) @@ -67,9 +87,10 @@ const defaultComponents = ({ variant, as: providedAs, className }: TypographyPro ) }, normal: ({ children }: PortableTextBlock) => { + const classNames = serializerClassnames ? serializerClassnames['normal'] : className if (isEmpty(children)) return null return ( - + <>{children} ) @@ -89,15 +110,18 @@ const defaultComponents = ({ variant, as: providedAs, className }: TypographyPro */ export const Heading = ({ value, - components = {}, + blocksComponents = {}, variant, group, as, className, + noProse = false, proseClassName = '', + serializerClassnames, ...props }: HeadingProps) => { let div: PortableTextBlock[] = [] + return ( <> {value?.length > 1 ? ( @@ -117,17 +141,27 @@ export const Heading = ({ return ( ) @@ -136,9 +170,19 @@ export const Heading = ({ ) : ( )} diff --git a/web/core/Typography/Typography.tsx b/web/core/Typography/Typography.tsx index 79df1f3be..b3b793496 100644 --- a/web/core/Typography/Typography.tsx +++ b/web/core/Typography/Typography.tsx @@ -2,7 +2,7 @@ import { forwardRef, ElementType, HTMLAttributes, AnchorHTMLAttributes } from 'react' import { TypographyGroups, TypographyVariants, quickVariants, variants } from './variants' import { OverridableComponent } from '@equinor/eds-utils' -import { twMerge } from 'tailwind-merge' +import envisTwMerge from '../../twMerge' const getElementType = (variant: string, link: boolean): ElementType => { if (link) { @@ -18,6 +18,7 @@ const getElementType = (variant: string, link: boolean): ElementType => { return variant case 'caption': case 'ingress': + case 'overline': case 'body': default: return 'p' @@ -77,12 +78,10 @@ export const Typography: OverridableComponent = fo if (typeof typography === 'undefined') { throw new Error(`Typography variant not found for variant "${variant}" ("${variant}") & group "${group || ''}"`) } - const classNames = twMerge(typography, className) - const TypographyTag = as ?? (`p` as React.ElementType) return ( - + {children} ) diff --git a/web/core/Typography/variants.ts b/web/core/Typography/variants.ts index 4d6f08031..2b289da39 100644 --- a/web/core/Typography/variants.ts +++ b/web/core/Typography/variants.ts @@ -8,7 +8,8 @@ const variants = { h6: 'text-slate-80 dark:text-white-100 text-base leading-inherit font-normal pb-0', h7: 'text-slate-80 dark:text-white-100 text-xs leading-earthy font-normal pb-0', xs: 'text-slate-80 dark:text-white-100 text-xs leading-earthy font-normal', - sm: 'text-slate-80 dark:text-white-100 text-base leading-inherit font-normal', + sm: 'text-slate-80 dark:text-white-100 text-sm leading-inherit font-normal', + base: 'text-slate-80 dark:text-white-100 text-base leading-inherit font-normal', md: 'text-slate-80 dark:text-white-100 text-md leading-inherit font-normal', lg: 'text-slate-80 dark:text-white-100 text-lg leading-inherit font-normal', xl: 'text-slate-80 dark:text-white-100 text-xl leading-inherit font-normal', @@ -22,7 +23,8 @@ const variants = { paragraph: { ingress: '', caption: '', - body: 'text-base font-normal', + overline: 'text-md text-slate-80 dark:text-white-100', + body: 'text-base font-normal text-slate-80 dark:text-white-100', }, } export type TypographyTokens = { diff --git a/web/lib/queries/common/pageContentFields.ts b/web/lib/queries/common/pageContentFields.ts index cd462425c..c61b110da 100644 --- a/web/lib/queries/common/pageContentFields.ts +++ b/web/lib/queries/common/pageContentFields.ts @@ -74,7 +74,7 @@ _type == "keyNumbers" =>{ bigTitle[]{..., ${markDefs}}, title[]{..., ${markDefs}} ), - useBrandTheme, + 'useBrandTheme': coalesce(useBrandTheme, false), ingress[]{..., ${markDefs}}, text[]{..., ${markDefs}}, "callToActions": action[]{ diff --git a/web/lib/queries/gridContentFields.ts b/web/lib/queries/gridContentFields.ts index 3e0841675..7c9c9f465 100644 --- a/web/lib/queries/gridContentFields.ts +++ b/web/lib/queries/gridContentFields.ts @@ -36,15 +36,22 @@ height, _type == "gridTextBlock"=>{ "type": _type, "id": _key, -"theme": coalesce(theme.value, null), textAlignment, +overline, +useThemedTitle, +title[]{..., ${markDefs}}, +themedTitle[]{..., ${markDefs}}, +"titleThemeFromLarger":coalesce(titleThemeFromLarger.value, null), content[]{..., ${markDefs}}, +"contentTheme":coalesce(contentTheme.value, null), +"theme":coalesce(theme.value, null), "action": action[0]{ ${linkSelectorFields}, ${downloadableFileFields}, ${downloadableImageFields}, }, -backgroundImage +contentAlignment, +imageBackground }, _type == "figure"=>{ "type": _type, @@ -62,16 +69,16 @@ ${background}, _type == "gridTeaser" => { "type": _type, "id": _key, + useExtendedThemes, content[]{..., ${markDefs}}, + themedContent[]{..., ${markDefs}}, + "themeFromLarger": coalesce(themeFromLarger.value, null), + "theme":coalesce(theme.value, null), author, authorTitle, quote, "imagePosition": coalesce(imagePosition, 'left'), - "theme": coalesce(theme.value, null), - "image": image { - ..., - "extension": asset-> extension - }, + image, "action": action[0]{ ${linkSelectorFields}, ${downloadableFileFields}, diff --git a/web/pageComponents/shared/portableText/Blocks.tsx b/web/pageComponents/shared/portableText/Blocks.tsx index 3747c2a61..9053b8623 100644 --- a/web/pageComponents/shared/portableText/Blocks.tsx +++ b/web/pageComponents/shared/portableText/Blocks.tsx @@ -95,7 +95,7 @@ export type BlockProps = { /** * Override default block serializers */ - blocks?: BlockType + blocksComponents?: Partial /** * Override default marks serializers */ @@ -131,7 +131,7 @@ const inlineBlockTypes = ['block', 'positionedInlineImage', 'pullQuote', 'basicI //@ts-ignore export default function Blocks({ value, - blocks: blocksComponents, + blocksComponents, marks: marksComponents, components, proseClassName = '', diff --git a/web/pageComponents/shared/textTeaser/theme.ts b/web/pageComponents/shared/textTeaser/theme.ts index 65f5f9817..9ea6bcc57 100644 --- a/web/pageComponents/shared/textTeaser/theme.ts +++ b/web/pageComponents/shared/textTeaser/theme.ts @@ -1,102 +1,20 @@ -import { ColorKeyTokens } from '../../../styles/colorKeyToUtilityMap' import { BackgroundColours } from '../../../types' export type ThemeColors = { - background: BackgroundColours + background?: BackgroundColours highlight?: string backgroundUtility?: string textUtility?: string dark?: boolean } //Keep in sync with sanityv3/schemas/components/ThemeSelector/themeColors -/*export const getColorForTheme = (pattern: number): ThemeColors => { - switch (pattern) { - case 1: - return { - background: 'Moss Green Light', - utility: { - background: 'bg-moss-green-50', - highlight: 'text-energy-red-100', - }, - } - case 2: - return { - background: 'Spruce Wood', - utility: { - background: 'bg-spruce-wood-90', - highlight: 'text-energy-red-100', - }, - } - case 3: - return { - background: 'Mist Blue', - utility: { - background: 'bg-mist-blue-100', - highlight: 'text-energy-red-100', - }, - } - case 4: - return { - background: 'Mid Yellow', - utility: { - background: 'bg-yellow-50', - highlight: 'text-energy-red-100', - }, - } - case 5: - return { - background: 'Mid Orange', - utility: { - background: 'bg-orange-50', - highlight: 'text-energy-red-100', - }, - } - case 6: - return { - background: 'Mid Blue', - highlight: 'var(--bg-mid-orange)', - dark: true, - utility: { - background: 'bg-blue-50', - highlight: 'text-orange-50', - }, - } - case 7: - return { - background: 'Mid Blue', - highlight: 'var(--bg-mid-yellow)', - dark: true, - utility: { - background: 'bg-blue-50', - highlight: 'text-yellow-50', - }, - } - case 8: - return { - background: 'Mid Green', - utility: { - background: 'bg-green-50', - highlight: 'text-energy-red-100', - }, - } - - case 0: - default: - return { - background: 'bg-white-100', - highlight: 'text-energy-red-100 ', - } - } -} - */ - -export const getColorForTheme = (pattern: number): ThemeColors => { +export const getColorForTheme = (pattern?: number): ThemeColors => { switch (pattern) { case 1: return { background: 'Moss Green Light', backgroundUtility: 'bg-moss-green-50', - textUtility: 'text-slate-80', + textUtility: 'text-energy-red-100', } case 2: return { @@ -129,6 +47,7 @@ export const getColorForTheme = (pattern: number): ThemeColors => { highlight: 'var(--bg-mid-orange)', backgroundUtility: 'bg-blue-50', textUtility: 'text-orange-50', + dark: true, } case 7: return { @@ -136,6 +55,7 @@ export const getColorForTheme = (pattern: number): ThemeColors => { backgroundUtility: 'bg-blue-50', highlight: 'var(--bg-mid-yellow)', textUtility: 'text-yellow-50', + dark: true, } case 8: return { @@ -143,6 +63,7 @@ export const getColorForTheme = (pattern: number): ThemeColors => { backgroundUtility: 'bg-blue-50', highlight: 'var(--bg-white)', textUtility: 'text-white-100', + dark: true, } case 9: return { @@ -157,13 +78,28 @@ export const getColorForTheme = (pattern: number): ThemeColors => { backgroundUtility: 'bg-mist-blue-100', textUtility: 'text-blue-50', } - + case 11: + return { + textUtility: 'text-slate-80', + } + case 12: + return { + textUtility: 'text-white-100', + dark: true, + } + case 13: + return { + background: 'Moss Green Light', + backgroundUtility: 'bg-moss-green-50', + textUtility: 'text-slate-80', + } case 0: - default: return { background: 'White', backgroundUtility: 'bg-white-100', textUtility: 'text-energy-red-100', } + default: + return {} } } diff --git a/web/pageComponents/topicPages/TextBlock.tsx b/web/pageComponents/topicPages/TextBlock.tsx index 4d8842ff1..ded0eb6ff 100644 --- a/web/pageComponents/topicPages/TextBlock.tsx +++ b/web/pageComponents/topicPages/TextBlock.tsx @@ -46,6 +46,8 @@ const TextBlock = ({ data, anchor, className = '' }: TextBlockProps) => { right: 'items-start text-start px-layout-lg xl:items-end xl:text-end xl:max-w-[45dvw] xl:ml-auto xl:pr-layout-sm xl:pl-0 ', left: 'items-start text-start px-layout-lg xl:items-start xl:max-w-[45dvw] xl:mr-auto xl:pl-layout-sm xl:pr-0', + 'bottom-left': 'items-start text-start px-layout-lg xl:mr-auto xl:pl-layout-sm xl:pr-0', + 'bottom-center': 'items-start text-start px-layout-lg xl:pl-layout-sm xl:pr-0', } let backgroundImageContentClassNames = ` justify-center @@ -70,6 +72,14 @@ const TextBlock = ({ data, anchor, className = '' }: TextBlockProps) => { } } + const common = `${useBrandTheme ? 'text-energy-red-100' : ''} text-balance` + const serializerClassnames = { + largeText: common, + normal: common, + twoXLText: common, + extraLargeText: common, + } + return (
{ {overline ? (
{overline} - {title && } + {title && }
) : ( <> @@ -97,7 +107,8 @@ const TextBlock = ({ data, anchor, className = '' }: TextBlockProps) => { value={title} as="h2" variant="xl" - className={`mb-2 ${useBrandTheme ? 'text-energy-red-100' : ''}`} + serializerClassnames={serializerClassnames} + className={`mb-2`} /> )} diff --git a/web/sections/CampaignBanner/CampaignBanner.tsx b/web/sections/CampaignBanner/CampaignBanner.tsx index 08c7c2e78..0884fda1a 100644 --- a/web/sections/CampaignBanner/CampaignBanner.tsx +++ b/web/sections/CampaignBanner/CampaignBanner.tsx @@ -84,7 +84,7 @@ const CampaignBanner = forwardRef(function Cam diff --git a/web/sections/Grid/GridLinkArrow.tsx b/web/sections/Grid/GridLinkArrow.tsx index 148435d46..81c7a763a 100644 --- a/web/sections/Grid/GridLinkArrow.tsx +++ b/web/sections/Grid/GridLinkArrow.tsx @@ -5,38 +5,43 @@ import { BaseLink } from '@core/Link' import { getLocaleFromName } from '../../lib/localization' import { ArrowRight } from '../../icons' import { LinkData } from '../../types/types' -import { getColorForTheme } from '../../pageComponents/shared/textTeaser/theme' type GridLinkArrowProps = { - theme?: number action?: LinkData className?: string + bgColor?: string } -const GridLinkArrow = ({ theme, action, className }: GridLinkArrowProps) => { +const GridLinkArrow = ({ action, className = '', bgColor }: GridLinkArrowProps) => { const url = action && getUrlFromAction(action) - const { textUtility } = getColorForTheme(theme ?? 0) - const variantClassName = () => { - switch (theme) { - case 0: - return 'text-energy-red-100 hover:bg-energy-red-100 hover:text-white-100 focus-visible:bg-energy-red-100 focus-visible:text-white-100' - case 8: - return `text-white-100 hover:bg-white-100 hover:text-blue-50 focus-visible:bg-white-100 focus-visible:text-blue-50` - case 10: + switch (bgColor) { + case 'bg-yellow-50': + case 'bg-green-50': + case 'bg-orange-50': + case 'bg-mist-blue-100': + case 'bg-moss-green-50': + case 'bg-spruce-wood-90': + return `text-slate-80 hover:bg-slate-80 hover:text-white-100 focus-visible:bg-slate-80 focus-visible:text-white-100` + case 'bg-white-100': + return `text-slate-80 hover:bg-grey-50 hover:text-white-100 focus-visible:bg-grey-50 focus-visible:text-white-100` + case 'bg-blue-50': + case 'bg-slate-80': default: - return `${theme !== null ? textUtility : ''} hover:bg-white-100 hover:${ - theme !== null ? textUtility : '' - } focus-visible:bg-white-100 focus-visible:${theme !== null ? textUtility : ''}` - //return 'text-white-100 hover:bg-white-100 hover:text-slate-80 focus-visible:bg-white-100 focus-visible:text-slate-80' + return `text-white-100 hover:bg-white-100 hover:text-slate-80 focus-visible:bg-white-100 focus-visible:text-slate-80` } } return ( <> {action && url && ( -
+
export const GridTeaser = forwardRef(function GridTeaser({ data, rowType }, ref) { - const { image, action, content, quote, author, authorTitle, theme } = data + const { + image, + action, + content, + themedContent, + quote, + author, + authorTitle, + useExtendedThemes, + themeFromLarger, + theme, + } = data + const imageSrc = urlFor(image).size(1200, 800).auto('format').toString() const altTag = image?.isDecorative ? '' : image?.alt || '' - const { backgroundUtility, textUtility } = getColorForTheme(theme ?? 0) + let contentTextColor = 'text-slate-80' + let bgColor = 'bg-white-100' + if (useExtendedThemes && themeFromLarger) { + const { backgroundUtility: extendedBg, textUtility: extendedTxt } = getColorForTheme(themeFromLarger) + if (extendedTxt) { + contentTextColor = extendedTxt + } + if (extendedBg) { + bgColor = extendedBg + } + } + if (!useExtendedThemes && theme) { + const { backgroundUtility: themeBg, textUtility: themeTxt } = getColorForTheme(theme) + if (themeTxt) { + contentTextColor = themeTxt + } + if (themeBg) { + bgColor = themeBg + } + } return (
(function G grid-rows-2 lg:grid-rows-[250px_1fr] ${String(rowType) === 'span3' ? 'lg:grid-cols-[40%_60%] lg:grid-rows-1' : ''} - ${theme !== null ? backgroundUtility : ''} + ${bgColor} `)} > {image && ( @@ -41,22 +75,35 @@ export const GridTeaser = forwardRef(function G alt={altTag} style={{ objectFit: 'cover' }} fill + sizes="(max-width: 800px) 100vw, 800px" role={image?.isDecorative ? 'presentation' : undefined} />
)} -
-
- {content && ( +
+
+ {(content || (useExtendedThemes && themedContent)) && ( { + if (isEmpty(children)) return null + return ( +

+ <>{children} +

+ ) + }, + } as Partial, + })} /> )} {quote && ( @@ -84,7 +131,7 @@ export const GridTeaser = forwardRef(function G )}
- {action && } + {action && }
) diff --git a/web/sections/Grid/GridTextBlock.tsx b/web/sections/Grid/GridTextBlock.tsx index f237fee4a..99f389465 100644 --- a/web/sections/Grid/GridTextBlock.tsx +++ b/web/sections/Grid/GridTextBlock.tsx @@ -2,43 +2,240 @@ import { twMerge } from 'tailwind-merge' import { getUrlFromAction } from '../../common/helpers' import GridLinkArrow from './GridLinkArrow' import { getColorForTheme } from '../../pageComponents/shared/textTeaser/theme' -import { GridTextBlockData } from '../../types/types' +import { BackgroundTypes, GridTextBlockData } from '../../types/types' import Blocks from '../../pageComponents/shared/portableText/Blocks' +import { BackgroundContainer } from '@components/Backgrounds' +import { Heading, Typography } from '@core/Typography' +import { RowType } from './mapGridContent' +import envisTwMerge from '../../twMerge' type GridTextBlockProps = { data: GridTextBlockData + rowType?: RowType className?: string } -const GridTextBlock = ({ data, className }: GridTextBlockProps) => { - const { action, content, textAlignment = 'left', theme } = data +const GridTextBlock = ({ data, className, rowType }: GridTextBlockProps) => { + const { + action, + overline, + title, + content, + useThemedTitle, + themedTitle, + titleThemeFromLarger, + contentTheme, + theme, + contentAlignment, + imageBackground, + } = data const url = action && getUrlFromAction(action) - const contentAlignment = { - center: 'justify-center text-center', - right: 'justify-center text-start xl:items-end xl:text-end xl:ml-auto', - left: 'justify-center text-start xl:items-start xl:mr-auto', + const contentAlignmentUtilities = { + center: 'justify-center items-center', + right: 'justify-end items-center', + left: 'justify-start items-center', + 'bottom-left': 'justify-start items-end', + 'bottom-center': 'justify-center items-end', + } + const textContentAlignmentUtilities = { + center: 'text-center', + right: 'text-end', + left: 'text-start', + 'bottom-left': 'text-start', + 'bottom-center': 'text-center', + } + + const textClassNames = twMerge(`${(title || themedTitle) && content ? 'text-sm' : 'text-md'}`, className) + + let titleTextColor = 'text-slate-80' + let contentTextColor = 'text-slate-80' + let bgColor = 'bg-white-100' + + if (useThemedTitle) { + const { + backgroundUtility: titleBgUtility, + textUtility: titleTextUtility, + dark, + } = getColorForTheme(titleThemeFromLarger) + if (titleTextUtility) { + titleTextColor = titleTextUtility + } + const { textUtility: contentTextUtility, backgroundUtility: contentBgUtility } = getColorForTheme(contentTheme) + if (contentBgUtility === titleBgUtility && contentTextUtility) { + contentTextColor = contentTextUtility + } + if (contentBgUtility !== titleBgUtility) { + contentTextColor = dark ? 'text-white-100' : 'text-slate-80' + } + bgColor = titleBgUtility ?? contentBgUtility ?? 'bg-white-100' + } + if (!useThemedTitle && theme) { + const { backgroundUtility: commonBgUtility, textUtility: commonTextUtility } = getColorForTheme(theme) + if (commonTextUtility) { + titleTextColor = commonTextUtility + contentTextColor = commonTextUtility + } + if (commonBgUtility) { + bgColor = commonBgUtility + } } - const contentClassNames = twMerge(`${contentAlignment[textAlignment]}`, className) - const { backgroundUtility, textUtility } = getColorForTheme(theme ?? 0) + const imageBgOptions = { + background: { + type: 'backgroundImage' as BackgroundTypes, + backgroundImage: imageBackground, + dark: + (((useThemedTitle && titleThemeFromLarger) || contentTheme) ?? theme) === 12 && !imageBackground?.useLight + ? true + : false, + }, + } + + if (imageBackground?.image) { + titleTextColor = 'text-white-100' + if (imageBackground?.useLight) { + titleTextColor = 'text-slate-80' + } + } + + if (imageBackground?.image) { + bgColor = 'bg-slate-80' + contentTextColor = 'text-white-100' + if (imageBackground?.useLight) { + contentTextColor = 'text-slate-80' + bgColor = 'bg-white-100' + } + } - return ( + const lightGradientForContentAlignment = { + center: '', + right: '', + left: '', + 'bottom-left': + rowType === 'span3' ? 'white-to-top-tall-gradient lg:white-to-top-gradient' : 'white-to-top-tall-gradient', + 'bottom-center': + rowType === 'span3' ? 'white-to-top-tall-gradient lg:white-to-top-gradient' : 'white-to-top-tall-gradient', + } + const darkGradientForContentAlignment = { + center: '', + right: '', + left: '', + 'bottom-left': + rowType === 'span3' ? 'black-to-top-tall-gradient lg:black-to-top-gradient' : 'black-to-top-tall-gradient', + 'bottom-center': + rowType === 'span3' ? 'black-to-top-tall-gradient lg:black-to-top-gradient' : 'black-to-top-tall-gradient', + } + + const getLayout = () => { + switch (rowType) { + case 'span3': + return 'lg:grid lg:grid-cols-[35%_60%] gap-10' + case 'span2and1': + return '4xl:grid 4xl:grid-cols-[35%_60%] gap-10' + case 'threeColumns': + default: + return '' + } + } + + const serializerClassnames = { + largeText: `leading-tight text-balance ${titleTextColor}`, + normal: `text-lg leading-snug text-balance ${titleTextColor}`, + } + + const mainContent = ( + <> +
+ {overline ? ( +
+ + {overline} + + {(title || (useThemedTitle && themedTitle)) && ( + + )} +
+ ) : ( + <> + {(title || (useThemedTitle && themedTitle)) && ( + + )} + + )} + {content && ( +
+ +
+ )} +
+ {action && url && } + + ) + + return imageBackground?.image ? ( + + {mainContent} + + ) : (
- {content && ( -
- -
- )} - {action && url && } + {mainContent}
) } diff --git a/web/sections/Grid/mapGridContent.tsx b/web/sections/Grid/mapGridContent.tsx index 9c994cde9..a5523473c 100644 --- a/web/sections/Grid/mapGridContent.tsx +++ b/web/sections/Grid/mapGridContent.tsx @@ -11,7 +11,7 @@ export type RowType = 'span3' | 'span2and1' | 'threeColumns' | undefined export const mapGridContent = (data: ComponentProps, rowType?: RowType, isMobile?: boolean): React.ReactNode => { switch (data.type) { case 'gridTextBlock': - return + return case 'gridTeaser': return case 'figure': diff --git a/web/styles/tailwind.css b/web/styles/tailwind.css index c2c362229..bca17a1b3 100644 --- a/web/styles/tailwind.css +++ b/web/styles/tailwind.css @@ -98,6 +98,28 @@ rgba(255, 255, 255, 0.4) 100% ); } + .white-to-top-gradient { + background-image: linear-gradient( + to top, + rgba(255, 255, 255, 0.7), + rgba(255, 255, 255, 0.3) 30%, + rgba(255, 255, 255, 0) 100% + ); + } + /* rgba(255, 255, 255, 0.7), + rgba(255, 255, 255, 0.6) 30%, + rgba(255, 255, 255, 0.4) 50%, + rgba(255, 255, 255, 0.3) 60%, + rgba(255, 255, 255, 0) 100% */ + .white-to-top-tall-gradient { + background-image: linear-gradient( + to top, + rgba(255, 255, 255, 0.6), + rgba(255, 255, 255, 0.5) 30%, + rgba(255, 255, 255, 0.35) 60%, + rgba(255, 255, 255, 0) 100% + ); + } .white-center-gradient { background-image: linear-gradient(rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.4)); } @@ -111,6 +133,26 @@ .black-center-gradient { background-image: linear-gradient(rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.4)); } + .black-to-top-gradient { + background-image: linear-gradient( + to top, + rgba(0, 0, 0, 0.7), + rgba(0, 0, 0, 0.6) 20%, + rgba(0, 0, 0, 0.45) 32%, + rgba(0, 0, 0, 0.1) 60%, + rgba(0, 0, 0, 0) 100% + ); + } + /* rgba(0, 0, 0, 0.7), + rgba(0, 0, 0, 0.6) 30%, + rgba(0, 0, 0, 0.4) 50%, + rgba(0, 0, 0, 0.3) 60%, + rgba(0, 0, 0, 0) 100% */ + .black-to-top-tall-gradient { + background-image: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0) 100%), + linear-gradient(26deg, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.45) 35%, rgba(0, 0, 0, 0) 100%); + } + .box-shadow-crisp { box-shadow: 0.3px 0.5px 0.7px hsl(var(--tw-shadow-color) / 0.34), 0.4px 0.8px 1px -1.2px hsl(var(--tw-shadow-color) / 0.34), 1px 2px 2.5px -2.5px hsl(var(--tw-shadow-color) / 0.34); diff --git a/web/tailwind.config.cjs b/web/tailwind.config.cjs index 194353cd5..835bb2187 100644 --- a/web/tailwind.config.cjs +++ b/web/tailwind.config.cjs @@ -33,6 +33,7 @@ module.exports = { extend: { screens: { '3xl': '1600px', + '4xl': '1920px', }, colors: ({ theme }) => ({ current: 'currentColor', @@ -260,6 +261,8 @@ module.exports = { }, maxWidth: { viewport: '1920px', + //When large font, prose(65ch) might not be the best + text: '760px', }, minWidth: { viewport: '375', @@ -419,7 +422,7 @@ module.exports = { css: { color: theme('colors.current'), p: { - fontSize: theme('fontSize.md'), + textWrap: 'balance', marginTop: '0', marginBottom: '0', }, diff --git a/web/twMerge/index.ts b/web/twMerge/index.ts index 2aa801292..fed643fc1 100644 --- a/web/twMerge/index.ts +++ b/web/twMerge/index.ts @@ -11,6 +11,7 @@ const envisTwMerge = extendTailwindMerge({ maxWidth: ['viewport'], minWidth: ['viewport'], size: ['arrow-right'], + lineHeight: ['text', 'earthy', 'misty', 'cloudy', 'planetary', 'inherit'], }, }, }) diff --git a/web/types/types.ts b/web/types/types.ts index 56751dff8..4dd7a8540 100644 --- a/web/types/types.ts +++ b/web/types/types.ts @@ -865,14 +865,22 @@ export type ThreeColumns = { id: string columns?: GridContentType[] } +type GridTextBlockContentAlignment = 'left' | 'right' | 'center' | 'bottom-left' | 'bottom-center' export type GridTextBlockData = { id: string type: 'gridTextBlock' action?: LinkData + overline?: string + useThemedTitle?: boolean + title?: PortableTextBlock[] + themedTitle?: PortableTextBlock[] content?: PortableTextBlock[] - textAlignment?: ContentAlignmentTypes - theme?: number + contentAlignment?: GridTextBlockContentAlignment + contentTheme?: any + titleThemeFromLarger?: any + theme?: any + imageBackground?: ImageBackground } export type CampaignBannerData = { @@ -886,7 +894,10 @@ export type GridTeaserData = { id: string image: ImageWithAlt rowType?: RowType - content?: PortableTextBlock + useExtendedThemes?: boolean + content?: PortableTextBlock[] + themedContent?: PortableTextBlock[] + themeFromLarger?: any quote?: string author?: string authorTitle?: string