From f4cf0657969f6820b3c8fdb85dedb21bf2e18b61 Mon Sep 17 00:00:00 2001 From: Alex Sanders Date: Thu, 12 Dec 2024 13:39:41 +0000 Subject: [PATCH] Revert "removing crossowrd formatting" This reverts commit f3b9feb8b5bedab83d63cf17c06f7f76451e7007. --- .../src/components/ArticleContainer.tsx | 3 + .../src/components/BylineLink.tsx | 5 + .../src/components/CrosswordInstructions.tsx | 26 + .../src/components/CrosswordLinks.tsx | 33 + .../src/layouts/CrosswordLayout.tsx | 788 ++++++++++++++++++ dotcom-rendering/src/layouts/DecideLayout.tsx | 10 + dotcom-rendering/src/lib/articleFormat.ts | 5 + dotcom-rendering/src/types/frontend.ts | 3 +- 8 files changed, 872 insertions(+), 1 deletion(-) create mode 100644 dotcom-rendering/src/components/CrosswordInstructions.tsx create mode 100644 dotcom-rendering/src/components/CrosswordLinks.tsx create mode 100644 dotcom-rendering/src/layouts/CrosswordLayout.tsx diff --git a/dotcom-rendering/src/components/ArticleContainer.tsx b/dotcom-rendering/src/components/ArticleContainer.tsx index 94e02c55792..5a1e46222e4 100644 --- a/dotcom-rendering/src/components/ArticleContainer.tsx +++ b/dotcom-rendering/src/components/ArticleContainer.tsx @@ -24,6 +24,9 @@ const articleWidth = (format: ArticleFormat) => { } `; } + case ArticleDesign.Crossword: + /* The crossword player manages its own width; */ + return null; case ArticleDesign.Video: case ArticleDesign.Audio: return css` diff --git a/dotcom-rendering/src/components/BylineLink.tsx b/dotcom-rendering/src/components/BylineLink.tsx index 3c9c4beca07..e7c1eb745d0 100644 --- a/dotcom-rendering/src/components/BylineLink.tsx +++ b/dotcom-rendering/src/components/BylineLink.tsx @@ -1,6 +1,7 @@ import { isString } from '@guardian/libs'; import { Hide } from '@guardian/source/react-components'; import { DottedLines } from '@guardian/source-development-kitchen/react-components'; +import { Fragment } from 'react'; import { ArticleDesign, type ArticleFormat } from '../lib/articleFormat'; import { getBylineComponentsFromTokens, @@ -160,6 +161,10 @@ const getRenderedTokens = ( ); } + if (design === ArticleDesign.Crossword && renderedTokens.length > 0) { + return [Set by: , ...renderedTokens]; + } + return renderedTokens; }; diff --git a/dotcom-rendering/src/components/CrosswordInstructions.tsx b/dotcom-rendering/src/components/CrosswordInstructions.tsx new file mode 100644 index 00000000000..93d17ffdb0c --- /dev/null +++ b/dotcom-rendering/src/components/CrosswordInstructions.tsx @@ -0,0 +1,26 @@ +import { css } from '@emotion/react'; +import { + textEgyptian17, + textEgyptianBold17, +} from '@guardian/source/foundations'; + +const instructionsStyles = css` + ${textEgyptian17}; + white-space: pre-line; +`; + +const headerStyles = css` + ${textEgyptianBold17}; + white-space: pre-line; +`; + +export const CrosswordInstructions = ({ + instructions, +}: { + instructions: string; +}) => ( +
+ Special instructions: + {instructions} +
+); diff --git a/dotcom-rendering/src/components/CrosswordLinks.tsx b/dotcom-rendering/src/components/CrosswordLinks.tsx new file mode 100644 index 00000000000..9f4ee8844a6 --- /dev/null +++ b/dotcom-rendering/src/components/CrosswordLinks.tsx @@ -0,0 +1,33 @@ +import { css } from '@emotion/react'; +import { isUndefined } from '@guardian/libs'; +import { type CrosswordProps } from '@guardian/react-crossword-next'; +import { textSans15 } from '@guardian/source/foundations'; +import { palette } from '../palette'; + +const crosswordLinkStyles = css` + ${textSans15}; + + a { + color: ${palette('--standfirst-link-text')}; + text-decoration: none; + :hover { + border-bottom: 1px solid ${palette('--standfirst-link-border')}; + } + } +`; + +export const CrosswordLinks = ({ + crossword, +}: { + crossword: CrosswordProps['data']; +}) => { + return ( + isUndefined(crossword.pdf) || ( + + + PDF version + + + ) + ); +}; diff --git a/dotcom-rendering/src/layouts/CrosswordLayout.tsx b/dotcom-rendering/src/layouts/CrosswordLayout.tsx new file mode 100644 index 00000000000..ecd5f915c07 --- /dev/null +++ b/dotcom-rendering/src/layouts/CrosswordLayout.tsx @@ -0,0 +1,788 @@ +import { css } from '@emotion/react'; +import { + from, + palette as sourcePalette, + until, +} from '@guardian/source/foundations'; +import { Hide } from '@guardian/source/react-components'; +import { StraightLines } from '@guardian/source-development-kitchen/react-components'; +import React from 'react'; +import { AdPortals } from '../components/AdPortals.importable'; +import { AdSlot, MobileStickyContainer } from '../components/AdSlot.web'; +import { AppsFooter } from '../components/AppsFooter.importable'; +import { ArticleBody } from '../components/ArticleBody'; +import { ArticleContainer } from '../components/ArticleContainer'; +import { ArticleHeadline } from '../components/ArticleHeadline'; +import { ArticleMetaApps } from '../components/ArticleMeta.apps'; +import { ArticleMeta } from '../components/ArticleMeta.web'; +import { ArticleTitle } from '../components/ArticleTitle'; +import { Carousel } from '../components/Carousel.importable'; +import { CrosswordInstructions } from '../components/CrosswordInstructions'; +import { CrosswordLinks } from '../components/CrosswordLinks'; +import { DecideLines } from '../components/DecideLines'; +import { DiscussionLayout } from '../components/DiscussionLayout'; +import { Footer } from '../components/Footer'; +import { GridItem } from '../components/GridItem'; +import { HeaderAdSlot } from '../components/HeaderAdSlot'; +import { Island } from '../components/Island'; +import { Masthead } from '../components/Masthead/Masthead'; +import { MostViewedFooterData } from '../components/MostViewedFooterData.importable'; +import { MostViewedFooterLayout } from '../components/MostViewedFooterLayout'; +import { OnwardsUpper } from '../components/OnwardsUpper.importable'; +import { RightColumn } from '../components/RightColumn'; +import { Section } from '../components/Section'; +import { SlotBodyEnd } from '../components/SlotBodyEnd.importable'; +import { Standfirst } from '../components/Standfirst'; +import { StickyBottomBanner } from '../components/StickyBottomBanner.importable'; +import { SubMeta } from '../components/SubMeta'; +import { SubNav } from '../components/SubNav.importable'; +import { type ArticleFormat, ArticleSpecial } from '../lib/articleFormat'; +import { canRenderAds } from '../lib/canRenderAds'; +import { getContributionsServiceUrl } from '../lib/contributions'; +import { decideTrail } from '../lib/decideTrail'; +import type { NavType } from '../model/extract-nav'; +import { palette as themePalette } from '../palette'; +import type { ArticleDeprecated } from '../types/article'; +import type { RenderingTarget } from '../types/renderingTarget'; +import { BannerWrapper, Stuck } from './lib/stickiness'; + +const CrosswordGrid = ({ children }: { children: React.ReactNode }) => ( +
+ {children} +
+); + +const maxWidth = css` + ${from.desktop} { + max-width: 620px; + } +`; + +const stretchLines = css` + ${until.phablet} { + margin-left: -20px; + margin-right: -20px; + } + ${until.mobileLandscape} { + margin-left: -10px; + margin-right: -10px; + } +`; + +interface CommonProps { + article: ArticleDeprecated; + format: ArticleFormat; + renderingTarget: RenderingTarget; +} + +interface WebProps extends CommonProps { + NAV: NavType; + renderingTarget: 'Web'; +} + +interface AppsProps extends CommonProps { + renderingTarget: 'Apps'; +} + +export const CrosswordLayout = (props: WebProps | AppsProps) => { + const { article, format, renderingTarget } = props; + const { + config: { isPaidContent, host, hasSurveyAd }, + } = article; + + const isApps = renderingTarget === 'Apps'; + const isWeb = renderingTarget === 'Web'; + + const showComments = article.isCommentable && !isPaidContent; + + const { branding } = article.commercialProperties[article.editionId]; + + const contributionsServiceUrl = getContributionsServiceUrl(article); + + const { absoluteServerTimes = false } = article.config.switches; + + /** + * This property currently only applies to the header and merchandising slots + */ + const renderAds = isWeb && canRenderAds(article); + return ( + <> + {isWeb && ( + <> +
+ {renderAds && ( + +
+
+ +
+
+
+ )} + + +
+ + {renderAds && hasSurveyAd && ( + + )} + + )} +
+ {isApps && ( + <> + + + + + )} +
+
+ + +
+ +
+
+ +
+ +
+
+ {article.crossword && ( + + + + )} + + + + + +
+
+ +
+
+
+ +
+ {isApps ? ( + <> + + + + + + + + ) : ( + + )} +
+
+ {!!article.crossword?.instructions && ( + + + + )} + + + + + + + + {renderAds ? ( + + ) : null} + + +
+
+
+ +
+
+ + + +
+
+ +
+ +
+ +
+ +
+ {renderAds && ( +
+ +
+ )} + + {article.storyPackage && ( +
+ + + +
+ )} + + + + + + {showComments && ( +
+ +
+ )} + + {!isPaidContent && ( +
+ + + + + +
+ )} + + {renderAds && ( +
+ +
+ )} +
+ + {isWeb && props.NAV.subNavSections && ( +
+ + + +
+ )} + + {isWeb && ( + <> +
+
+
+ + + + + + + + + )} + {isApps && ( +
+ + + +
+ )} + + ); +}; diff --git a/dotcom-rendering/src/layouts/DecideLayout.tsx b/dotcom-rendering/src/layouts/DecideLayout.tsx index b55f4973791..9920cb9d19c 100644 --- a/dotcom-rendering/src/layouts/DecideLayout.tsx +++ b/dotcom-rendering/src/layouts/DecideLayout.tsx @@ -8,6 +8,7 @@ import type { ArticleDeprecated } from '../types/article'; import type { RenderingTarget } from '../types/renderingTarget'; import { AudioLayout } from './AudioLayout'; import { CommentLayout } from './CommentLayout'; +import { CrosswordLayout } from './CrosswordLayout'; import { FullPageInteractiveLayout } from './FullPageInteractiveLayout'; import { ImmersiveLayout } from './ImmersiveLayout'; import { InteractiveLayout } from './InteractiveLayout'; @@ -273,6 +274,15 @@ const DecideLayoutWeb = ({ NAV={NAV} /> ); + case ArticleDesign.Crossword: + return ( + + ); default: return ( ): ArticleDesign => { return ArticleDesign.Timeline; case 'ProfileDesign': return ArticleDesign.Profile; + case 'CrosswordDesign': + return ArticleDesign.Crossword; default: return ArticleDesign.Standard; } @@ -270,6 +273,8 @@ const designToFEDesign = (design: ArticleDesign): FEDesign => { return 'TimelineDesign'; case ArticleDesign.Profile: return 'ProfileDesign'; + case ArticleDesign.Crossword: + return 'CrosswordDesign'; } }; diff --git a/dotcom-rendering/src/types/frontend.ts b/dotcom-rendering/src/types/frontend.ts index 1c3bee83cd1..f0f8ee43c77 100644 --- a/dotcom-rendering/src/types/frontend.ts +++ b/dotcom-rendering/src/types/frontend.ts @@ -210,7 +210,8 @@ export type FEDesign = | 'FullPageInteractiveDesign' | 'NewsletterSignupDesign' | 'TimelineDesign' - | 'ProfileDesign'; + | 'ProfileDesign' + | 'CrosswordDesign'; /** FEDisplay is the display information passed through from frontend (originating in the capi scala client) and dictates the display style of the content e.g. Immersive https://github.com/guardian/content-api-scala-client/blob/master/client/src/main/scala/com.gu.contentapi.client/utils/format/Display.scala */