diff --git a/dotcom-rendering/index.d.ts b/dotcom-rendering/index.d.ts index 017d6bd5ed5..205b2ed24c4 100644 --- a/dotcom-rendering/index.d.ts +++ b/dotcom-rendering/index.d.ts @@ -94,6 +94,7 @@ declare namespace JSX { 'data-spacefinder-role'?: | 'nested' | 'immersive' + | 'fullWidth' | 'inline' | 'richLink' | 'thumbnail'; diff --git a/dotcom-rendering/src/components/Figure.tsx b/dotcom-rendering/src/components/Figure.tsx index d169c06b022..8ce7dbc7679 100644 --- a/dotcom-rendering/src/components/Figure.tsx +++ b/dotcom-rendering/src/components/Figure.tsx @@ -7,7 +7,7 @@ type Props = { children: React.ReactNode; format: ArticleFormat; isMainMedia: boolean; - role?: RoleType | 'richLink'; + role?: RoleType | 'richLink' | 'fullWidth'; id?: string; className?: string; type?: FEElement['_type']; @@ -70,6 +70,59 @@ const roleCss = { } `, + fullWidth: css` + margin-top: ${space[3]}px; + margin-bottom: ${space[3]}px; + + @property --scrollbar-width { + syntax: ''; + inherits: true; + initial-value: 15px; + } + + --scrollbar-width: 15px; + + ${until.mobileLandscape} { + margin-left: -10px; + margin-right: -10px; + } + ${until.tablet} { + margin-left: -20px; + margin-right: -20px; + } + ${from.tablet} { + width: calc(100vw - var(--scrollbar-width, 15px)); + max-width: calc(100vw - var(--scrollbar-width, 15px)); + + --grid-container-max-width: 740px; + --grid-container-left-margin: calc( + ((-100vw + (var(--grid-container-max-width) - 42px)) / 2) + + (var(--scrollbar-width, 15px) / 2) + ); + --grid-body-column-left: calc( + (var(--grid-container-left-margin, 0px) * -1) + + var(--grid-left-col-width, 0px) + ); + + margin-left: calc(var(--grid-container-left-margin)); + } + ${from.desktop} { + --grid-container-max-width: 980px; + } + ${from.leftCol} { + --grid-container-max-width: 1140px; + --grid-left-col-width: 140px; + --grid-body-column-left: calc( + (var(--grid-container-left-margin, 0px) * -1) + + var(--grid-left-col-width, 0px) + 21px + ); + } + ${from.wide} { + --grid-container-max-width: 1300px; + --grid-left-col-width: 219px; + } + `, + showcase: css` margin-top: ${space[3]}px; margin-bottom: ${space[3]}px; @@ -150,7 +203,7 @@ const roleCss = { // Used for vast majority of layouts. export const defaultRoleStyles = ( - role: RoleType | 'richLink', + role: RoleType | 'richLink' | 'fullWidth', format: ArticleFormat, isTimeline = false, ) => { @@ -161,6 +214,8 @@ export const defaultRoleStyles = ( return roleCss.supporting; case 'immersive': return roleCss.immersive; + case 'fullWidth': + return roleCss.fullWidth; case 'showcase': if (isTimeline) { return css` diff --git a/dotcom-rendering/src/frontend/schemas/feArticle.json b/dotcom-rendering/src/frontend/schemas/feArticle.json index 76e940db3c7..2423bc93ee0 100644 --- a/dotcom-rendering/src/frontend/schemas/feArticle.json +++ b/dotcom-rendering/src/frontend/schemas/feArticle.json @@ -2378,7 +2378,16 @@ "type": "string" }, "role": { - "$ref": "#/definitions/RoleType" + "enum": [ + "fullWidth", + "halfWidth", + "immersive", + "inline", + "showcase", + "supporting", + "thumbnail" + ], + "type": "string" } }, "required": [ diff --git a/dotcom-rendering/src/layouts/lib/interactiveLegacyStyling.ts b/dotcom-rendering/src/layouts/lib/interactiveLegacyStyling.ts index 660edff22c2..698e7a109a9 100644 --- a/dotcom-rendering/src/layouts/lib/interactiveLegacyStyling.ts +++ b/dotcom-rendering/src/layouts/lib/interactiveLegacyStyling.ts @@ -9,7 +9,7 @@ export const isInteractive = (design: ArticleDesign): boolean => export const interactiveLegacyFigureClasses = ( elementType: string, - role?: RoleType, + role?: RoleType | 'fullWidth', ): string => { const elementClasses: { [key: string]: string } = { 'model.dotcomrendering.pageElements.InteractiveAtomBlockElement': diff --git a/dotcom-rendering/src/lib/renderElement.tsx b/dotcom-rendering/src/lib/renderElement.tsx index 55d8c605e95..c38822e8a33 100644 --- a/dotcom-rendering/src/lib/renderElement.tsx +++ b/dotcom-rendering/src/lib/renderElement.tsx @@ -1060,7 +1060,17 @@ export const RenderArticleElement = ({ }); const needsFigure = !bareElements.has(element._type); - const role = 'role' in element ? (element.role as RoleType) : undefined; + + const isInteractiveFormat = + format.design === ArticleDesign.Interactive || + format.design === ArticleDesign.FullPageInteractive; + + const role: RoleType | 'fullWidth' | undefined = + 'role' in element + ? element.role === 'fullWidth' && !isInteractiveFormat + ? 'immersive' + : (element.role as RoleType | undefined) + : undefined; return needsFigure ? (