diff --git a/dotcom-rendering/src/layouts/DecideLayout.tsx b/dotcom-rendering/src/layouts/DecideLayout.tsx index 57edc35d105..b52abadf201 100644 --- a/dotcom-rendering/src/layouts/DecideLayout.tsx +++ b/dotcom-rendering/src/layouts/DecideLayout.tsx @@ -9,6 +9,7 @@ import { FullPageInteractiveLayout } from './FullPageInteractiveLayout'; import { GalleryLayout } from './GalleryLayout'; import { HostedArticleLayout } from './HostedArticleLayout'; import { HostedGalleryLayout } from './HostedGalleryLayout'; +import { HostedVideoLayout } from './HostedVideoLayout'; import { ImmersiveLayout } from './ImmersiveLayout'; import { InteractiveLayout } from './InteractiveLayout'; import { LiveLayout } from './LiveLayout'; @@ -363,7 +364,6 @@ const DecideLayoutWeb = ({ article, NAV, renderingTarget }: WebProps) => { /> ); case ArticleDesign.HostedArticle: - case ArticleDesign.HostedVideo: return ( { renderingTarget={renderingTarget} /> ); + case ArticleDesign.HostedVideo: + return ( + + ); case ArticleDesign.HostedGallery: return ( ; + +export default meta; + +type Story = StoryObj; + +const format = { + theme: ArticleSpecial.Labs, + design: ArticleDesign.HostedVideo, + display: ArticleDisplay.Standard, +}; + +export const Apps = { + args: { + content: enhanceArticleType(hostedVideo, 'Apps'), + format, + renderingTarget: 'Apps', + }, + parameters: { + config: { + renderingTarget: 'Apps', + darkModeAvailable: true, + }, + chromatic: { + modes: { + 'light mobileMedium': allModes['light mobileMedium'], + }, + }, + }, +} satisfies Story; + +export const Web = { + args: { + content: enhanceArticleType(hostedVideo, 'Web'), + format, + renderingTarget: 'Web', + }, + parameters: { + config: { + renderingTarget: 'Web', + }, + }, +} satisfies Story; diff --git a/dotcom-rendering/src/layouts/HostedVideoLayout.tsx b/dotcom-rendering/src/layouts/HostedVideoLayout.tsx new file mode 100644 index 00000000000..247a793be07 --- /dev/null +++ b/dotcom-rendering/src/layouts/HostedVideoLayout.tsx @@ -0,0 +1,341 @@ +import { css } from '@emotion/react'; +import { + breakpoints, + from, + palette as sourcePalette, + space, +} from '@guardian/source/foundations'; +import { ArticleBody } from '../components/ArticleBody'; +import { ArticleContainer } from '../components/ArticleContainer'; +import { ArticleHeadline } from '../components/ArticleHeadline'; +import { CallToActionAtom } from '../components/CallToActionAtom'; +import { Caption } from '../components/Caption'; +import { HostedContentDisclaimer } from '../components/HostedContentDisclaimer'; +import { HostedContentHeader } from '../components/HostedContentHeader'; +import { Island } from '../components/Island'; +import { MainMedia } from '../components/MainMedia'; +import { Section } from '../components/Section'; +import { ShareButton } from '../components/ShareButton.importable'; +import { Standfirst } from '../components/Standfirst'; +import { grid } from '../grid'; +import type { ArticleFormat } from '../lib/articleFormat'; +import { getContributionsServiceUrl } from '../lib/contributions'; +import { decideMainMediaCaption } from '../lib/decide-caption'; +import { palette } from '../palette'; +import type { Article } from '../types/article'; +import type { RenderingTarget } from '../types/renderingTarget'; +import { Stuck } from './lib/stickiness'; + +interface Props { + content: Article; + format: ArticleFormat; + renderingTarget: RenderingTarget; +} + +interface WebProps extends Props { + renderingTarget: 'Web'; +} + +interface AppProps extends Props { + renderingTarget: 'Apps'; +} + +const headerStyles = css` + ${grid.container} + ${grid.column.all} + grid-row: 1; +`; + +const contentStyles = css` + ${grid.container} + ${grid.column.all} + grid-row: 2; +`; + +const mainMediaStyles = css` + ${grid.column.all} + grid-row: 1; + overflow: hidden; + max-height: 400px; + + ${from.wide} { + width: ${breakpoints.wide}px; + margin: auto; + } +`; + +const captionStyles = css` + ${grid.column.centre} + grid-row: 2; + + ${from.desktop} { + ${grid.span(12, 2)} + } + ${from.leftCol} { + ${grid.column.right} + } +`; + +const headlineStyles = css` + margin-top: ${space[4]}px; + ${grid.column.centre} + ${from.desktop} { + ${grid.span(4, 8)} + grid-row: 2; + } + ${from.leftCol} { + ${grid.column.centre} + } +`; +const metaStyles = css` + margin-top: ${space[4]}px; + padding: ${space[1]}px; + ${grid.column.centre} + grid-row: 3; + ${from.desktop} { + grid-row: 2; + } + ${from.leftCol} { + ${grid.column.left} + } +`; + +const standfirstStyles = css` + ${grid.column.centre} + grid-row: 1; + ${from.desktop} { + ${grid.between(4, 'right-column-end')} + } + ${from.leftCol} { + ${grid.column.centre} + } +`; + +const articleBodyStyles = css` + ${grid.column.centre} + grid-row:auto; + ${from.desktop} { + ${grid.between(4, 'right-column-end')} + grid-row: 2; + } + ${from.leftCol} { + ${grid.column.centre} + grid-row: 2; + } + padding-bottom: 24px; +`; + +const onwardContentStyles = css` + height: 20px; + background-color: lightgrey; + + ${grid.column.centre} + grid-row:auto; + + ${from.desktop} { + ${grid.span(4, 8)} + grid-row: 3; + } + ${from.leftCol} { + ${grid.column.right} + grid-row: 1 + } + margin-bottom: 24px; +`; + +const ctaStyles = css` + ${grid.column.all} + grid-row:auto; + overflow: hidden; + max-height: 400px; + ${from.wide} { + width: ${breakpoints.wide}px; + margin: auto; + } +`; + +const sideBorders = css` + ${from.desktop} { + position: relative; + ::before { + position: absolute; + top: 0; + bottom: 0; + content: ''; + border-left: 1px solid ${palette('--article-border')}; + border-right: 1px solid ${palette('--article-border')}; + left: -${grid.mobileColumnGap}; + right: -${grid.mobileColumnGap}; + ${from.mobileLandscape} { + left: -${grid.columnGap}; + right: -${grid.columnGap}; + } + ${grid.between('centre-column-start', 'right-column-end')} + ${from.leftCol} { + ${grid.between('left-column-start', 'right-column-end')} + } + } + } +`; + +export const HostedVideoLayout = (props: WebProps | AppProps) => { + const { + content: { frontendData }, + format, + } = props; + + const contributionsServiceUrl = getContributionsServiceUrl(frontendData); + + const mainMedia = frontendData.mainMediaElements[0]; + const mainMediaCaptionText = decideMainMediaCaption(mainMedia); + + const { branding } = + frontendData.commercialProperties[frontendData.editionId]; + + return ( + <> + {branding ? ( + +
+ +
+
+ ) : null} + +
+
+
+
+ +
+ +
+ +
+ + {props.renderingTarget === 'Web' && ( +
+ + + +
+ )} + +
+ +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ {'Placeholder - onward content'} +
+ +
+ +
+
+
+
+ + ); +};