diff --git a/FeatureFlags.js b/FeatureFlags.js index 97bd8a7fd..af178b6f3 100644 --- a/FeatureFlags.js +++ b/FeatureFlags.js @@ -47,6 +47,7 @@ const MAGAZINE = [...GLOBAL_PROD, ...GLOBAL_DEV] /* Allows same slug for different languages */ const SAME_SLUG = [...GLOBAL_DEV, 'japan', 'southkorea'] const LINE_BREAK_TYPO = ['southkorea'] +const CAMPAIGN = [...GLOBAL_PROD, ...GLOBAL_DEV] /** * @param {string} dataset @@ -72,4 +73,5 @@ export default (dataset) => ({ IS_GLOBAL_PROD: GLOBAL_PROD.includes(dataset), IS_DEV: GLOBAL_DEV.includes(dataset), IS_SATELLITE: SATELLITES.includes(dataset), + HAS_CAMPAIGN_BLOCKS: CAMPAIGN.includes(dataset), }) diff --git a/sanityv3/schemas/components/ThemeSelector/themeColors.ts b/sanityv3/schemas/components/ThemeSelector/themeColors.ts index b87d0923b..fcff2c7b1 100644 --- a/sanityv3/schemas/components/ThemeSelector/themeColors.ts +++ b/sanityv3/schemas/components/ThemeSelector/themeColors.ts @@ -10,7 +10,9 @@ export const themeColors = [ { title: 'Mid Orange', value: 5 }, { title: 'Mid Blue 1', value: 6 }, { title: 'Mid Blue 2', value: 7 }, - { title: 'Mid Green', value: 8 }, + { title: 'Mid Blue 3', value: 8 }, + { title: 'Mid Green', value: 9 }, + { title: 'Mist Blue 2', value: 10 }, ] //Keep in sync with web/pageComponents/shared/textTeaser/theme @@ -91,6 +93,17 @@ export const getColorForTheme = (pattern: number) => { }, } case 8: + return { + background: { + value: defaultColors[6].value, + key: defaultColors[6].key, + }, + highlight: { + value: defaultColors[0].value, + key: defaultColors[0].key, + }, + } + case 9: return { background: { value: defaultColors[7].value, @@ -98,6 +111,17 @@ export const getColorForTheme = (pattern: number) => { }, highlight: {}, } + case 10: + return { + background: { + value: defaultColors[3].value, + key: defaultColors[3].key, + }, + highlight: { + value: defaultColors[6].value, + key: defaultColors[6].key, + }, + } case 0: default: diff --git a/sanityv3/schemas/documents/header/sharedHeaderFields.ts b/sanityv3/schemas/documents/header/sharedHeaderFields.ts index 64792a3e1..2e7847e99 100644 --- a/sanityv3/schemas/documents/header/sharedHeaderFields.ts +++ b/sanityv3/schemas/documents/header/sharedHeaderFields.ts @@ -42,7 +42,7 @@ const heroBigTitleDefault = { of: [ configureTitleBlockContent({ highlight: true, - styles: defaultBannerBigTitletStyle, + extendedStyles: defaultBannerBigTitletStyle, }), ], hidden: ({ parent }: DocumentType) => !parent.isBigTitle || parent.heroType !== HeroTypes.DEFAULT, @@ -64,7 +64,7 @@ const heroBigTitleFiftyFifty = { title: 'Hero Title', type: 'array', fieldset: 'header', - of: [configureTitleBlockContent({ styles: fiftyFiftyBigTitleStyle })], + of: [configureTitleBlockContent({ extendedStyles: fiftyFiftyBigTitleStyle })], hidden: ({ parent }: DocumentType) => !parent.isBigTitle || parent.heroType !== HeroTypes.FIFTY_FIFTY, validation: (Rule: Rule) => Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => diff --git a/sanityv3/schemas/documents/page.ts b/sanityv3/schemas/documents/page.ts index b869fe417..9e59fcf48 100644 --- a/sanityv3/schemas/documents/page.ts +++ b/sanityv3/schemas/documents/page.ts @@ -43,6 +43,12 @@ export default { fieldset: 'metadata', }, ...sharedHeroFields, + { + title: 'Is Campain', + name: 'isCampaign', + description: 'Set this to true if the page should be treated as campaign. the header title h1 will be hidden.', + type: 'boolean', + }, { name: 'content', type: 'array', @@ -68,6 +74,8 @@ export default { { type: 'videoPlayer' }, { type: 'videoPlayerCarousel' }, { type: 'table' }, + Flags.HAS_CAMPAIGN_BLOCKS && { type: 'grid' }, + Flags.HAS_CAMPAIGN_BLOCKS && { type: 'campaignBanner' }, Flags.HAS_FORMS && { type: 'form' }, Flags.HAS_NEWS && { type: 'newsList' }, { type: 'stockValuesApi' }, diff --git a/sanityv3/schemas/editors/blockContentType.tsx b/sanityv3/schemas/editors/blockContentType.tsx index e1dc5159b..2646aded1 100644 --- a/sanityv3/schemas/editors/blockContentType.tsx +++ b/sanityv3/schemas/editors/blockContentType.tsx @@ -19,6 +19,8 @@ export type BlockContentProps = { attachment?: boolean lists?: boolean smallText?: boolean + largeText?: boolean + extraLargeText?: boolean highlight?: boolean normalTextOverride?: { title: string @@ -42,20 +44,28 @@ const round = (num: number) => .toFixed(7) .replace(/(\.[0-9]+?)0+$/, '$1') .replace(/\.0$/, '') -const em = (px: number, base: number) => `${round(px / base)}em` +export const em = (px: number, base: number) => `${round(px / base)}em` const SmallTextRender = (props: any) => { const { children } = props return {children} } +export const LargeTextRender = (props: any) => { + const { children } = props + return {children} +} +export const ExtraLargeTextRender = (props: any) => { + const { children } = props + return {children} +} const Level2BaseStyle = (props: any) => { const { children } = props - return

{children}

+ return

{children}

} const Level3BaseStyle = (props: any) => { const { children } = props - return

{children}

+ return

{children}

} // H1 not allowed in block content since it should be a document title. @@ -70,6 +80,8 @@ export const configureBlockContent = (options: BlockContentProps = {}): BlockDef externalLink = true, attachment = false, lists = true, + largeText = false, + extraLargeText = false, smallText = true, highlight = false, extendedStyles = [], @@ -119,6 +131,16 @@ export const configureBlockContent = (options: BlockContentProps = {}): BlockDef value: 'smallText', component: SmallTextRender, } + const largeTextConfig = { + title: 'Large text', + value: 'largeText', + component: LargeTextRender, + } + const extraLargeTextConfig = { + title: 'Extra large text', + value: 'extraLargeText', + component: ExtraLargeTextRender, + } const externalLinkConfig = { name: 'link', type: 'object', @@ -267,6 +289,12 @@ export const configureBlockContent = (options: BlockContentProps = {}): BlockDef if (smallText) { config?.styles?.push(smallTextConfig) } + if (largeText) { + config?.styles?.push(largeTextConfig) + } + if (extraLargeText) { + config?.styles?.push(extraLargeTextConfig) + } if (externalLink) { config?.marks?.annotations?.push(externalLinkConfig) diff --git a/sanityv3/schemas/editors/titleEditorContentType.tsx b/sanityv3/schemas/editors/titleEditorContentType.tsx index bd904c3a2..d4ae51bb2 100644 --- a/sanityv3/schemas/editors/titleEditorContentType.tsx +++ b/sanityv3/schemas/editors/titleEditorContentType.tsx @@ -4,30 +4,37 @@ import { StrikethroughIcon } from '@sanity/icons' import { BlockDefinition, BlockStyleDefinition } from 'sanity' import { format_color_text } from '@equinor/eds-icons' import { defaultColors } from '../defaultColors' +import { em, ExtraLargeTextRender, LargeTextRender } from './blockContentType' export type TitleContentProps = { - styles?: BlockStyleDefinition[] + extendedStyles?: BlockStyleDefinition[] highlight?: boolean highlightTitle?: string + 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 configureTitleBlockContent = ( - options: TitleContentProps = { - styles: [ - { - title: 'Normal', - value: 'normal', - }, - ], - }, -): BlockDefinition => { - const { highlight = false, styles, highlightTitle = 'Highlight' } = options +export const configureTitleBlockContent = (options: TitleContentProps = {}): BlockDefinition => { + const { + highlight = false, + highlightTitle = 'Highlight', + largeText = false, + extraLargeText = false, + twoXLText = false, + extendedStyles = [], + } = options const config: BlockDefinition = { type: 'block', name: 'block', - styles: styles, + styles: [{ title: 'Normal', value: 'normal' }, ...extendedStyles], lists: [], marks: { decorators: [ @@ -56,6 +63,22 @@ export const configureTitleBlockContent = ( }, } + 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, + } + const textColorConfig = { title: highlightTitle, value: 'highlight', @@ -68,6 +91,15 @@ export const configureTitleBlockContent = ( if (highlight) { config.marks?.decorators?.push(textColorConfig) } + if (largeText) { + config?.styles?.push(largeTextConfig) + } + if (extraLargeText) { + config?.styles?.push(extraLargeTextConfig) + } + if (twoXLText) { + config?.styles?.push(twoXLTextConfig) + } return config } diff --git a/sanityv3/schemas/index.js b/sanityv3/schemas/index.js index 253bf2314..1b4a7283c 100644 --- a/sanityv3/schemas/index.js +++ b/sanityv3/schemas/index.js @@ -94,6 +94,14 @@ import card from './objects/card' import cardsList from './objects/cardsList' import backgroundOptions from './objects/background/backgroundOptions' import imageBackground from './objects/background/imageBackground' +import grid from './objects/grid/index' +import span3 from './objects/grid/rowTypes/span3' +import span2and1 from './objects/grid/rowTypes/span2and1' +import gridTextBlock from './objects/grid/cellTypes/gridTextBlock' +import campaignBanner from './objects/campaignBanner' +import gridTeaser from './objects/grid/cellTypes/gridTeaser' +import threeColumns from './objects/grid/rowTypes/3columns' +import gridColorTheme from './objects/grid/theme' const routeSchemas = languages.map(({ name, title }) => { return route(name, title) @@ -182,6 +190,14 @@ const RemainingSchemas = [ cardsList, backgroundOptions, imageBackground, + grid, + span3, + span2and1, + gridTextBlock, + campaignBanner, + gridTeaser, + threeColumns, + gridColorTheme, ] // Then we give our schema to the builder and provide the result to Sanity diff --git a/sanityv3/schemas/objects/campaignBanner/index.tsx b/sanityv3/schemas/objects/campaignBanner/index.tsx new file mode 100644 index 000000000..69f960962 --- /dev/null +++ b/sanityv3/schemas/objects/campaignBanner/index.tsx @@ -0,0 +1,107 @@ +/* eslint-disable react/display-name */ +import blocksToText from '../../../helpers/blocksToText' +import { configureBlockContent } from '../../editors' +import { validateCharCounterEditor } from '../../validations/validateCharCounterEditor' + +import type { Image, PortableTextBlock, Reference, Rule, ValidationContext } from 'sanity' +import type { ColorSelectorValue } from '../../components/ColorSelector' + +const blockConfigTitle = { + h2: false, + h3: false, + h4: false, + internalLink: false, + externalLink: false, + attachment: false, + lists: false, + smallText: true, + largeText: true, + extraLargeText: true, +} +const blockConfigContent = { + h2: false, + h3: false, + h4: false, + internalLink: false, + externalLink: false, + attachment: false, + lists: false, + smallText: true, +} + +const blockTitleType = configureBlockContent({ ...blockConfigTitle }) +const blockContentType = configureBlockContent({ ...blockConfigContent }) + +export type CampaignBanner = { + _type: 'campaignBanner' + overline?: string + title?: PortableTextBlock[] + text?: PortableTextBlock[] + image: Image + imagePosition?: string + imageSize?: string + background?: ColorSelectorValue +} + +export default { + name: 'campaignBanner', + title: 'Campaign Banner', + type: 'object', + localize: true, + fieldsets: [ + { + title: 'Background image', + name: 'backgroundImage', + description: 'Settings for the background image', + options: { + collapsible: true, + collapsed: true, + }, + }, + ], + fields: [ + { + name: 'title', + title: 'Title content', + type: 'array', + of: [blockTitleType], + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { + return validateCharCounterEditor(value, 600) + }).warning(), + }, + { + title: 'Image', + name: 'backgroundImage', + type: 'image', + options: { + hotspot: true, + collapsed: false, + }, + fieldset: 'backgroundImage', + }, + { + title: 'Background Color', + description: 'Fallback if no background image. Default is white.', + name: 'backgroundColor', + type: 'colorlist', + fieldset: 'backgroundImage', + }, + ], + preview: { + select: { + title: 'title', + text: 'text', + image: 'backgroundImage.asset', + }, + prepare({ title, text, image }: { title: PortableTextBlock[]; text: PortableTextBlock[]; image: Reference }) { + const plainTitle = blocksToText(title || text) + + return { + title: plainTitle || 'Missing title/content', + subtitle: 'Campaign banner component', + media: image, + } + }, + }, +} diff --git a/sanityv3/schemas/objects/grid/cellTypes/gridTeaser.tsx b/sanityv3/schemas/objects/grid/cellTypes/gridTeaser.tsx new file mode 100644 index 000000000..772dbb45f --- /dev/null +++ b/sanityv3/schemas/objects/grid/cellTypes/gridTeaser.tsx @@ -0,0 +1,163 @@ +/* eslint-disable react/display-name */ +import blocksToText from '../../../../helpers/blocksToText' +import { configureBlockContent } from '../../../editors' +import { validateCharCounterEditor } from '../../../validations/validateCharCounterEditor' + +import type { PortableTextBlock, Reference, Rule, ValidationContext } from 'sanity' +import type { DownloadableImage } from './../../downloadableImage' +import type { DownloadableFile } from '../../files' +import type { ImageWithAlt } from '../../imageWithAlt' +import type { LinkSelector } from '../../linkSelector' +import type { ColorSelectorValue } from '../../../components/ColorSelector' +import { LeftAlignedImage, RightAlignedImage } from '../../../../icons' +import { RadioIconSelector } from '../../../components' + +const blockContentType = configureBlockContent({ + smallText: true, + largeText: true, + extraLargeText: true, +}) + +const imageAlignmentOptions = [ + { value: 'left', icon: LeftAlignedImage }, + { value: 'right', icon: RightAlignedImage }, +] + +export type GridTeaser = { + _type: 'gridTeaser' + content?: PortableTextBlock[] + quote: string + author: string + authorTitle?: string + action?: (LinkSelector | DownloadableFile | DownloadableImage)[] + image: ImageWithAlt + imagePosition?: string + background?: ColorSelectorValue +} + +export default { + name: 'gridTeaser', + title: 'Grid Teaser', + type: 'object', + localize: true, + fieldsets: [ + { + title: 'Quote', + name: 'quote', + description: '', + options: { + collapsible: true, + collapsed: true, + }, + }, + { + name: 'link', + title: 'Link', + description: 'Select either an internal link or external URL.', + }, + { + name: 'design', + title: 'Design options', + }, + ], + fields: [ + { + name: 'content', + title: 'Content', + type: 'array', + of: [blockContentType], + validation: (Rule: Rule) => + Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => { + return validateCharCounterEditor(value, 600) + }).warning(), + }, + { + name: 'quote', + type: 'text', + title: 'Quote', + description: 'Highlighted quote from the article.', + rows: 5, + }, + { + name: 'author', + type: 'string', + title: 'Name', + }, + { + name: 'authorTitle', + type: 'string', + title: 'Title', + description: 'Optional title for the author.', + }, + { + name: 'action', + title: 'Link/action', + description: 'Select the link or downloadable file for the teaser', + type: 'array', + of: [ + { type: 'linkSelector', title: 'Link' }, + { type: 'downloadableImage', title: 'Downloadable image' }, + { type: 'downloadableFile', title: 'Downloadable file' }, + ], + validation: (Rule: Rule) => Rule.max(1).error('Only one action is permitted'), + }, + { + name: 'image', + title: 'Image', + type: 'imageWithAlt', + validation: (Rule: Rule) => Rule.required(), + }, + { + name: 'imagePosition', + title: 'Image position', + description: + 'On span 3 one can select which side the image will be on for larger screens. On mobile and single column the image will be above', + type: 'string', + components: { + input: function ({ onChange, value }: { onChange: any; value: string }) { + return ( + + ) + }, + }, + }, + { + name: 'theme', + title: 'Theme', + description: 'If no theme set, normal text color is set', + type: 'themeList', + }, + ], + preview: { + select: { + title: 'content', + text: 'quote', + image: 'image.asset', + }, + prepare({ + title, + text, + image, + }: { + title: PortableTextBlock[] + text: PortableTextBlock[] + isBigText: boolean + bigText: PortableTextBlock[] + image: Reference + }) { + const plainTitle = blocksToText(title || text) + + return { + title: plainTitle || 'Missing content/quote', + subtitle: 'Grid Teaser component', + media: image, + } + }, + }, +} diff --git a/sanityv3/schemas/objects/grid/cellTypes/gridTextBlock.tsx b/sanityv3/schemas/objects/grid/cellTypes/gridTextBlock.tsx new file mode 100644 index 000000000..91edbab3e --- /dev/null +++ b/sanityv3/schemas/objects/grid/cellTypes/gridTextBlock.tsx @@ -0,0 +1,83 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { text_field } from '@equinor/eds-icons' +import type { PortableTextBlock, Reference, Rule } from 'sanity' +import type { ColorSelectorValue } from '../../../components/ColorSelector' +import blocksToText from '../../../../helpers/blocksToText' +import { EdsIcon } from '../../../../icons' +import { configureBlockContent } from '../../../editors' + +const blockContentType = configureBlockContent({ + smallText: true, + largeText: true, + extraLargeText: true, +}) + +type GridTextBlock = { + content?: string + action?: Reference[] + background?: ColorSelectorValue +} + +export default { + name: 'gridTextBlock', + title: 'Grid Text block', + type: 'object', + fields: [ + { + name: 'content', + title: 'Content', + type: 'array', + of: [blockContentType], + }, + { + title: 'Text Alignment', + name: 'textAlignment', + description: 'Overrides background image alignment', + type: 'string', + options: { + list: [ + { title: 'Left', value: 'left' }, + { title: 'Right', value: 'right' }, + { title: 'Center', value: 'center' }, + ], + }, + initialValue: 'left', + }, + { + name: 'action', + title: 'Link/action', + description: 'Select the link or downloadable file', + type: 'array', + of: [ + { type: 'linkSelector', title: 'Link' }, + { type: 'downloadableImage', title: 'Downloadable image' }, + { type: 'downloadableFile', title: 'Downloadable file' }, + ], + validation: (Rule: Rule) => Rule.max(1).error('Only one action is permitted'), + }, + { + name: 'theme', + type: 'themeList', + }, + { + name: 'backgroundImage', + type: 'imageBackground', + title: 'Background Image', + description: 'Content alignment is ignored on this', + }, + ].filter((e) => e), + preview: { + select: { + title: 'content', + }, + prepare({ title }: { title: PortableTextBlock[] }) { + const plainTitle = blocksToText(title) + + return { + title: plainTitle || 'Missing title/content', + subtitle: 'Grid text block component', + media: EdsIcon(text_field), + } + }, + }, +} diff --git a/sanityv3/schemas/objects/grid/index.tsx b/sanityv3/schemas/objects/grid/index.tsx new file mode 100644 index 000000000..9fe2bc528 --- /dev/null +++ b/sanityv3/schemas/objects/grid/index.tsx @@ -0,0 +1,64 @@ +import { configureBlockContent } from '../../editors' +import { PortableTextBlock } from 'sanity' +import { EdsIcon } from '../../../icons' +import { table_chart } from '@equinor/eds-icons' + +export type Grid = { + _type: 'grid' +} + +export default { + title: 'Grid', + name: 'grid', + type: 'object', + fieldsets: [ + { + title: 'Design options', + name: 'design', + description: 'Some options for design', + options: { + collapsible: true, + collapsed: false, + }, + }, + ], + fields: [ + { + name: 'gridRows', + title: 'Grid rows', + description: 'Add different types of rows', + type: 'array', + of: [ + { + type: 'span3', + title: 'Span 3 columns', + name: 'span3', + }, + { + type: 'span2and1', + title: 'Span 2 columns and one single column', + name: 'span2and1', + }, + { + type: 'threeColumns', + title: '3 columns', + name: 'threeColumns', + }, + ], + }, + ], + preview: { + select: { + title: 'title', + }, + prepare({ title = [] }: { title: PortableTextBlock[] }) { + const plainTitle = 'Grid' + + return { + title: plainTitle, + subtitle: 'Grid component', + media: () => EdsIcon(table_chart), + } + }, + }, +} diff --git a/sanityv3/schemas/objects/grid/rowTypes/3columns.tsx b/sanityv3/schemas/objects/grid/rowTypes/3columns.tsx new file mode 100644 index 000000000..c6a9cefac --- /dev/null +++ b/sanityv3/schemas/objects/grid/rowTypes/3columns.tsx @@ -0,0 +1,41 @@ +import blocksToText from '../../../../helpers/blocksToText' +import { PortableTextBlock, Rule } from 'sanity' +import { EdsIcon } from '../../../../icons' +import { table_chart } from '@equinor/eds-icons' + +export type Span2And1 = { + _type: 'threeColumns' +} + +export default { + title: '3 columns', + name: 'threeColumns', + type: 'object', + fields: [ + { + name: 'columns', + title: 'List of 3 columns', + type: 'array', + of: [ + { name: 'gridTextBlock', type: 'gridTextBlock', title: 'Text block' }, + { type: 'figure' }, + { type: 'gridTeaser' }, + ], + validation: (Rule: Rule) => Rule.max(3).error('Only three is permitted'), + }, + ], + preview: { + select: { + title: 'title', + }, + prepare({ title = [] }: { title: PortableTextBlock[] }) { + const plainTitle = title.length > 0 ? blocksToText(title) : '3 columns type' + + return { + title: plainTitle, + subtitle: '3 columns component', + media: () => EdsIcon(table_chart), + } + }, + }, +} diff --git a/sanityv3/schemas/objects/grid/rowTypes/span2and1.tsx b/sanityv3/schemas/objects/grid/rowTypes/span2and1.tsx new file mode 100644 index 000000000..791e9357c --- /dev/null +++ b/sanityv3/schemas/objects/grid/rowTypes/span2and1.tsx @@ -0,0 +1,61 @@ +import blocksToText from '../../../../helpers/blocksToText' +import { configureBlockContent } from '../../../editors' + +import { PortableTextBlock, Rule } from 'sanity' +import { EdsIcon } from '../../../../icons' +import { table_chart } from '@equinor/eds-icons' + +export type Span2And1 = { + _type: 'span2and1' +} + +export default { + title: 'Span 2 and 1 column', + name: 'span2and1', + type: 'object', + fields: [ + { + name: 'span2', + title: 'The span 2 content', + type: 'array', + of: [ + { name: 'gridTextBlock', type: 'gridTextBlock', title: 'Text block' }, + { type: 'videoPlayer' }, + { type: 'iframe' }, + { type: 'figure' }, + ], + validation: (Rule: Rule) => Rule.max(1).error('Only one is permitted'), + }, + { + title: 'Align Span 2 on the right', + name: 'alignSpan2Right', + description: 'Will align the span 2 on the right side. If not selected on the left', + type: 'boolean', + }, + { + name: 'singleColumn', + title: 'The single column content', + type: 'array', + of: [ + { name: 'gridTextBlock', type: 'gridTextBlock', title: 'Text block' }, + { type: 'figure' }, + { type: 'gridTeaser' }, + ], + validation: (Rule: Rule) => Rule.max(1).error('Only one is permitted'), + }, + ], + preview: { + select: { + title: 'title', + }, + prepare({ title = [] }: { title: PortableTextBlock[] }) { + const plainTitle = title.length > 0 ? blocksToText(title) : 'Span 2 and 1 type' + + return { + title: plainTitle, + subtitle: 'Span 2 and 1 component', + media: () => EdsIcon(table_chart), + } + }, + }, +} diff --git a/sanityv3/schemas/objects/grid/rowTypes/span3.tsx b/sanityv3/schemas/objects/grid/rowTypes/span3.tsx new file mode 100644 index 000000000..82bd7afa4 --- /dev/null +++ b/sanityv3/schemas/objects/grid/rowTypes/span3.tsx @@ -0,0 +1,44 @@ +import blocksToText from '../../../../helpers/blocksToText' +import { PortableTextBlock, Rule } from 'sanity' +import { EdsIcon } from '../../../../icons' +import { table_chart } from '@equinor/eds-icons' + +export type Span3 = { + _type: 'span3' +} + +export default { + title: 'Span 3', + name: 'span3', + type: 'object', + fields: [ + { + name: 'content', + title: 'Span 3 type', + description: 'Select one type of content for span 3 type', + type: 'array', + of: [ + { name: 'gridTextBlock', type: 'gridTextBlock', title: 'Text block' }, + { type: 'videoPlayer' }, + { type: 'iframe' }, + { type: 'figure' }, + { type: 'gridTeaser' }, + ], + validation: (Rule: Rule) => Rule.max(1).error('Only one is permitted'), + }, + ], + preview: { + select: { + title: 'title', + }, + prepare({ title = [] }: { title: PortableTextBlock[] }) { + const plainTitle = title.length > 0 ? blocksToText(title) : 'Span 3 type' + + return { + title: plainTitle, + subtitle: 'Span 3 component', + media: () => EdsIcon(table_chart), + } + }, + }, +} diff --git a/sanityv3/schemas/objects/grid/theme.tsx b/sanityv3/schemas/objects/grid/theme.tsx new file mode 100644 index 000000000..6d00e2da7 --- /dev/null +++ b/sanityv3/schemas/objects/grid/theme.tsx @@ -0,0 +1,15 @@ +export default { + name: 'gridColorTheme', + title: 'Grid Color theme', + description: 'Text color on background color. Call to actions will be black or white text', + type: 'string', + options: { + list: [ + { title: 'normal', value: 'normal' }, + { title: 'red on white', value: 'redOnWhite' }, + { title: 'white on dark blue', value: 'whiteOnDarkBlue' }, + { title: 'dark blue on light blue', value: 'darkBlueOnLightBlue' }, + ], + }, + initialValue: 'normal', +} diff --git a/sanityv3/schemas/objects/teaser.tsx b/sanityv3/schemas/objects/teaser.tsx index e738943ec..bcdaef655 100644 --- a/sanityv3/schemas/objects/teaser.tsx +++ b/sanityv3/schemas/objects/teaser.tsx @@ -142,15 +142,21 @@ export default { }, { name: 'action', - title: 'Link/action', - description: 'Select the link or downloadable file for the teaser', + title: 'Links/actions', + description: 'Select links or downloadable files for the teaser', type: 'array', of: [ { type: 'linkSelector', title: 'Link' }, { type: 'downloadableImage', title: 'Downloadable image' }, { type: 'downloadableFile', title: 'Downloadable file' }, ], - validation: (Rule: Rule) => Rule.max(1).error('Only one action is permitted'), + validation: (Rule: Rule) => Rule.max(2).error('Only two action is permitted'), + }, + { + title: 'Use resource link style', + description: 'Default is read more link style', + name: 'useResourceLinks', + type: 'boolean', }, { name: 'image', diff --git a/sanityv3/schemas/objects/textBlock.tsx b/sanityv3/schemas/objects/textBlock.tsx index b844c8367..9e7915f2e 100644 --- a/sanityv3/schemas/objects/textBlock.tsx +++ b/sanityv3/schemas/objects/textBlock.tsx @@ -6,7 +6,6 @@ import blocksToText from '../../helpers/blocksToText' import { EdsIcon } from '../../icons' import CompactBlockEditor from '../components/CompactBlockEditor' import { configureBlockContent, configureTitleBlockContent } from '../editors' -import { validateComponentAnchor } from '../validations/validateAnchorReference' const blockContentType = configureBlockContent({ h2: false, @@ -28,22 +27,27 @@ const blockContentTypeForBigText = configureBlockContent({ h4: false, attachment: false, smallText: false, + largeText: true, + extraLargeText: true, normalTextOverride: { title: 'Normal', value: 'normal', component: ({ children }: { children: React.ReactNode }) => {children}, }, }) - -const titleContentType = configureTitleBlockContent() +const titleContentType = configureTitleBlockContent({ + largeText: true, + extraLargeText: true, + twoXLText: true, +}) type TextBlock = { overline?: string title?: string - anchor?: string ingress?: string text?: string isBigText?: boolean + useBrandTheme?: boolean bigText?: PortableTextBlock[] action?: Reference[] splitList?: boolean @@ -86,26 +90,20 @@ export default { name: 'actions', options: { collapsible: true, - collapsed: false, + collapsed: true, }, }, { - name: 'anchor', - title: 'Additional anchor point reference (Deprecated)', - description: - 'If the anchor reference to this component is set using anchor link component, the value here will be overridden', + name: 'titleOptions', + title: 'Title', + description: '', options: { collapsible: true, - collapsed: true, + collapsed: false, }, }, ], fields: [ - { - title: 'Big text', - name: 'isBigText', - type: 'boolean', - }, { name: 'image', type: 'imageWithAlt', @@ -123,45 +121,53 @@ export default { { name: 'title', type: 'array', + fieldset: 'titleOptions', components: { input: CompactBlockEditor, }, of: [titleContentType], validation: (Rule: Rule) => Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => - !value && !(ctx.parent as TextBlock)?.isBigText ? 'A title is recommended' : true, + !value ? 'A title is recommended' : true, ).warning(), - hidden: ({ parent }: TextBlockDocument) => parent.isBigText, }, { - name: 'anchor', - type: 'anchorReferenceField', - title: 'Anchor reference', - validation: (Rule: Rule) => [ - Rule.max(0).warning('Clear this field and use anchor link component instead.'), - // @ts-ignore - Rule.custom((value: string, context: any) => validateComponentAnchor(value, context)), - ], - fieldset: 'anchor', - readOnly: ({ value }: { value?: string }) => !value, + title: 'Use brand theme for title', + description: 'Sets background to white and text color to brand red. Will disable other background options', + name: 'useBrandTheme', + type: 'boolean', + fieldset: 'titleOptions', }, { - name: 'ingress', - title: 'Ingress', - type: 'array', - of: [ingressContentType], - hidden: ({ parent }: TextBlockDocument) => parent.isBigText, + title: 'Big text (Deprecated)', + description: 'Set big text to false. Will be removed after a transition period', + name: 'isBigText', + type: 'boolean', + fieldset: 'titleOptions', + readOnly: ({ value }: { value?: string }) => !value, }, { name: 'bigTitle', - title: 'Title', + title: 'Title (Deprecated)', + description: 'Use regular title and set big text to false. Will be removed after a transition period', + fieldset: 'titleOptions', type: 'array', of: [blockContentTypeForBigText], hidden: ({ parent }: TextBlockDocument) => !parent.isBigText, validation: (Rule: Rule) => Rule.custom((value: PortableTextBlock[], ctx: ValidationContext) => - !value && (ctx.parent as TextBlock)?.isBigText ? 'Title is required' : true, - ), + value && (ctx.parent as TextBlock)?.isBigText + ? 'Clear this field and use regular title without big text boolean' + : true, + ).warning(), + readOnly: ({ value }: { value?: string }) => !value, + }, + { + name: 'ingress', + title: 'Ingress', + type: 'array', + of: [ingressContentType], + hidden: ({ parent }: TextBlockDocument) => parent.isBigText, }, { name: 'text', @@ -204,6 +210,7 @@ export default { { name: 'designOptions', type: 'backgroundOptions', + readOnly: ({ parent }: { parent: TextBlock }) => parent.useBrandTheme, }, { title: 'Background (Deprecated)', diff --git a/sanityv3/schemas/objects/textTeaser.tsx b/sanityv3/schemas/objects/textTeaser.tsx index b69fae311..65310e636 100644 --- a/sanityv3/schemas/objects/textTeaser.tsx +++ b/sanityv3/schemas/objects/textTeaser.tsx @@ -15,7 +15,7 @@ import { ThemeSelectorValue } from '../components/ThemeSelector' const titleContentType = configureTitleBlockContent({ highlight: true, highlightTitle: 'Highlight text selected from theme below', - styles: [ + extendedStyles: [ { title: 'Normal', value: 'normal', diff --git a/sanityv3/schemas/objects/videoPlayer.tsx b/sanityv3/schemas/objects/videoPlayer.tsx index 5f02cf524..a3ab6f0dc 100644 --- a/sanityv3/schemas/objects/videoPlayer.tsx +++ b/sanityv3/schemas/objects/videoPlayer.tsx @@ -20,6 +20,17 @@ export default { name: 'videoPlayer', title: 'Video Player', type: 'object', + fieldsets: [ + { + name: 'designOptions', + title: 'Design options', + description: '', + options: { + collapsible: true, + collapsed: false, + }, + }, + ], fields: [ { name: 'title', @@ -72,20 +83,43 @@ export default { layout: 'dropdown', }, initialValue: '16:9', + fieldset: 'designOptions', validation: (Rule: Rule) => Rule.required(), }, + { + name: 'width', + type: 'string', + title: 'Width', + options: { + list: [ + { title: 'Normal', value: 'normal' }, + { title: 'Extra wide', value: 'extraWide' }, + ], + layout: 'dropdown', + }, + fieldset: 'designOptions', + initialValue: 'normal', + }, { name: 'height', type: 'number', title: 'Height', + fieldset: 'designOptions', description: 'Set a fixed height in pixels for the video. Note: this will override the aspect ratio setting.', validation: (Rule: Rule) => Rule.positive().greaterThan(0).precision(0), }, - + { + title: 'Use brand theme for video', + description: 'Make play button bigger and brand red.', + name: 'useBrandTheme', + type: 'boolean', + fieldset: 'designOptions', + }, { title: 'Background', description: 'Pick a colour for the background. Default is white.', name: 'background', + fieldset: 'designOptions', type: 'colorlist', }, ], diff --git a/search/pnpm-lock.yaml b/search/pnpm-lock.yaml index 7b344feca..150a93630 100644 --- a/search/pnpm-lock.yaml +++ b/search/pnpm-lock.yaml @@ -1,9 +1,5 @@ lockfileVersion: '6.0' -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - dependencies: '@azure/storage-blob': specifier: ^12.15.0 @@ -3752,3 +3748,7 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false diff --git a/web/components/src/Backgrounds/ColouredContainer.tsx b/web/components/src/Backgrounds/ColouredContainer.tsx index cdb596b41..f169ef540 100644 --- a/web/components/src/Backgrounds/ColouredContainer.tsx +++ b/web/components/src/Backgrounds/ColouredContainer.tsx @@ -25,7 +25,7 @@ const ColourContainer = styled.div` ` export const ColouredContainer = forwardRef(function BackgroundContainer( - { backgroundColor = 'White', backgroundUtility, dark, style, children, className, ...rest }, + { backgroundColor = 'White', backgroundUtility, dark, style, children, className = '', ...rest }, ref, ) { const styleVariant = getContainerColor(backgroundColor) @@ -38,7 +38,7 @@ export const ColouredContainer = forwardRef, 'src'> & { src: string playButton?: boolean videoDescription?: string + /* setting this will sett fluid mode to video player */ aspectRatio?: string + /** Ignores aspect ratio to enable fill mode */ + useFillMode?: boolean loadingSpinner?: boolean + useBrandTheme?: boolean onReady?: (player: Player) => void } export const VideoJS: React.FC = ({ @@ -27,6 +31,8 @@ export const VideoJS: React.FC = ({ aspectRatio, onReady, loadingSpinner, + useBrandTheme = false, + useFillMode = false, poster, allowFullScreen, ...rest @@ -71,7 +77,7 @@ export const VideoJS: React.FC = ({ autoplay: autoPlay, preload: autoPlay ? 'auto' : 'none', controls: showControls, - aspectRatio, + ...(!useFillMode && { aspectRatio: aspectRatio }), bigPlayButton: !controls, controlbar: true, loadingSpinner: !autoPlay, @@ -109,17 +115,19 @@ export const VideoJS: React.FC = ({ return ( <> {/* eslint-disable-next-line */} - + {showPlayButton && (