diff --git a/src/components/editions/article.tsx b/src/components/editions/article.tsx index 3d43e9613..7893574bc 100644 --- a/src/components/editions/article.tsx +++ b/src/components/editions/article.tsx @@ -127,7 +127,7 @@ const Article: FC = ({ item }) => {
-
+
= ({ item }) => { - const [contributor] = item.contributors; - const format = getFormat(item); +const Avatar: FC = () => { + const { + contributors: [contributor], + format, + } = useItemExtras(); return pipe2( contributor.image, diff --git a/src/components/editions/byline.tsx b/src/components/editions/byline.tsx index b88bc265e..6e0acd413 100644 --- a/src/components/editions/byline.tsx +++ b/src/components/editions/byline.tsx @@ -12,11 +12,9 @@ import type { } from '@guardian/src-foundations/typography/types'; import type { Format } from '@guardian/types'; import { Design, Display } from '@guardian/types'; -import type { Item } from 'item'; -import { getFormat } from 'item'; +import { useItemExtras } from 'itemExtrasContext'; import { maybeRender } from 'lib'; import type { FC, ReactNode } from 'react'; -import { getThemeStyles } from 'themeStyles'; import EditionsAvatar from './avatar'; import { ShareIcon } from './shareIcon'; import { @@ -192,7 +190,6 @@ const getStyles = (format: Format, kickerColor: string): SerializedStyles => { // ----- Component ----- // interface Props { - item: Item; shareIcon?: boolean; large?: boolean; avatar?: boolean; @@ -221,16 +218,19 @@ const renderText = ( } }); -const Byline: FC = ({ item, shareIcon, large, avatar }) => { - const format = getFormat(item); - const { kicker: kickerColor } = getThemeStyles(format.theme); +const Byline: FC = ({ shareIcon, large, avatar }) => { + const { + bylineHtml, + format, + themeStyles: { kicker: kickerColor }, + } = useItemExtras(); const ignoreKickerColour = (format: Format): boolean => format.design === Design.Media || format.display === Display.Immersive; const bylineColor = ignoreKickerColour(format) ? neutral[100] : kickerColor; - return maybeRender(item.bylineHtml, (byline) => ( + return maybeRender(bylineHtml, (byline) => (
{renderText(byline, bylineColor, large)}
{shareIcon && ( @@ -240,7 +240,7 @@ const Byline: FC = ({ item, shareIcon, large, avatar }) => { )} {avatar && (
- +
)}
diff --git a/src/components/editions/galleryImage.tsx b/src/components/editions/galleryImage.tsx index c0940c742..04f532510 100644 --- a/src/components/editions/galleryImage.tsx +++ b/src/components/editions/galleryImage.tsx @@ -5,24 +5,22 @@ import { Img } from '@guardian/image-rendering'; import { neutral, remSpace } from '@guardian/src-foundations'; import { from } from '@guardian/src-foundations/mq'; import { textSans } from '@guardian/src-foundations/typography'; -import type { Format, Option } from '@guardian/types'; +import type { Option } from '@guardian/types'; import { map, none, some, withDefault } from '@guardian/types'; import type { Image } from 'bodyElement'; +import { useItemExtras } from 'itemExtrasContext'; import { maybeRender, pipe2 } from 'lib'; import type { FC } from 'react'; import React from 'react'; -import { getThemeStyles } from 'themeStyles'; const width = '100%'; type Props = { image: Image; - format: Format; }; type CaptionProps = { details: CaptionDetails; - format: Format; }; type CaptionDetails = { @@ -126,8 +124,10 @@ const CaptionDescription: FC<{ description: string }> = ({ description }) => { return

{description}

; }; -const GalleryImageCaption: FC = ({ details, format }) => { - const { kicker } = getThemeStyles(format.theme); +const GalleryImageCaption: FC = ({ details }) => { + const { + themeStyles: { kicker }, + } = useItemExtras(); const tabletWidth = '170px'; const styles = css` ${from.tablet} { @@ -149,7 +149,8 @@ const GalleryImageCaption: FC = ({ details, format }) => { ); }; -const GalleryImage: FC = ({ image, format }) => { +const GalleryImage: FC = ({ image }) => { + const { format } = useItemExtras(); return (
= ({ image, format }) => { credit: none, })} /> - +
); }; diff --git a/src/components/editions/header.tsx b/src/components/editions/header.tsx index 2a579d2a1..8c6117a96 100644 --- a/src/components/editions/header.tsx +++ b/src/components/editions/header.tsx @@ -13,7 +13,8 @@ import Series from 'components/editions/series'; import Standfirst from 'components/editions/standfirst'; import type { Item } from 'item'; import { isPicture } from 'item'; -import type { FC, ReactElement } from 'react'; +import { useItemExtras } from 'itemExtrasContext'; +import type { FC } from 'react'; import { articleMarginStyles, headerBackgroundColour, @@ -32,10 +33,6 @@ const tablet = tabletContentWidth + 12; // ----- Component ----- // -interface HeaderProps { - item: Item; -} - const headerStyles = css` ${sidePadding} `; @@ -142,129 +139,128 @@ const linesBorderStyles = css` border-right: 1px solid ${border.secondary}; `; -const StandardHeader: FC = ({ item }) => ( +const StandardHeader: FC = () => (
- - - - + + + + - +
); -const ShowcaseHeader: FC = ({ item }) => ( +const ShowcaseHeader: FC = () => (
- - - - + + + + - +
); -const AnalysisHeader: FC = ({ item }) => ( +const AnalysisHeader: FC = () => (
- - - + + + - +
); -const CommentHeader: FC = ({ item }) => ( +const CommentHeader: FC = () => (
- - - + + + - +
); -const InterviewHeader: FC = ({ item }) => ( -
- -
- - -
- - -
-); +const InterviewHeader: FC = () => { + const itemExtras = useItemExtras(); + return ( +
+ +
+ + +
+ + +
+ ); +}; -const GalleryHeader: FC = ({ item }) => ( +const GalleryHeader: FC = () => (
- +
- +
- + - +
); -const PictureHeader: FC = ({ item }) => ( +const PictureHeader: FC = () => (
- - + + - +
- +
); -const ImmersiveHeader: FC = ({ item }) => ( -
- -
- -
-
- - -
- -
-); +const ImmersiveHeader: FC = () => { + const itemExtras = useItemExtras(); + return ( +
+ +
+ +
+
+ + +
+ +
+ ); +}; -const renderArticleHeader = (item: Item): ReactElement => { +const Container: FC = () => { + const { display, design, tags } = useItemExtras(); // Display.Immersive needs to come before Design.Interview - if (item.display === Display.Immersive) { - return ; - } else if (item.design === Design.Interview) { - return ; - } else if (item.display === Display.Showcase) { - return ; - } else if (item.design === Design.Analysis) { - return ; - } else if (item.design === Design.Comment) { - return ; - } else if (item.design === Design.Media) { - return isPicture(item.tags) ? ( - - ) : ( - - ); + if (display === Display.Immersive) { + return ; + } else if (design === Design.Interview) { + return ; + } else if (display === Display.Showcase) { + return ; + } else if (design === Design.Analysis) { + return ; + } else if (design === Design.Comment) { + return ; + } else if (design === Design.Media) { + return isPicture(tags) ? : ; } else { - return ; + return ; } }; -const Container: FC = ({ item }) => { - return <>{renderArticleHeader(item)}; -}; - // ----- Exports ----- // export default Container; diff --git a/src/components/editions/headerMedia.tsx b/src/components/editions/headerMedia.tsx index 0285be52e..0bf1d352c 100644 --- a/src/components/editions/headerMedia.tsx +++ b/src/components/editions/headerMedia.tsx @@ -14,11 +14,10 @@ import HeaderImageCaption, { import StarRating from 'components/editions/starRating'; import { MainMediaKind } from 'headerMedia'; import type { Image } from 'image'; -import type { Item } from 'item'; -import { getFormat, isPicture } from 'item'; +import { isPicture } from 'item'; +import { useItemExtras } from 'itemExtrasContext'; import { maybeRender } from 'lib'; import type { FC } from 'react'; -import { getThemeStyles } from 'themeStyles'; import { sidePadding, tabletArticleMargin, @@ -146,10 +145,6 @@ const getImageStyle = ( `; }; -interface Props { - item: Item; -} - const sizes: Sizes = { mediaQueries: [ { breakpoint: 'tablet', size: '740px' }, @@ -163,14 +158,19 @@ const fullWidthSizes: Sizes = { default: '100vw', }; -const HeaderMedia: FC = ({ item }) => { - const format = getFormat(item); +const HeaderMedia: FC = () => { + const itemExtras = useItemExtras(); const { - cameraIcon: iconColor, - cameraIconBackground: iconBackgroundColor, - } = getThemeStyles(format.theme); - - return maybeRender(item.mainMedia, (media) => { + format, + mainMedia, + tags, + themeStyles: { + cameraIcon: iconColor, + cameraIconBackground: iconBackgroundColor, + }, + } = itemExtras; + + return maybeRender(mainMedia, (media) => { if (media.kind === MainMediaKind.Image) { const { image, @@ -180,14 +180,14 @@ const HeaderMedia: FC = ({ item }) => {
= ({ item }) => { iconColor={iconColor} iconBackgroundColor={iconBackgroundColor} /> - +
); } else { diff --git a/src/components/editions/headline/index.tsx b/src/components/editions/headline/index.tsx index 1b23ff4c7..4971b1d5e 100644 --- a/src/components/editions/headline/index.tsx +++ b/src/components/editions/headline/index.tsx @@ -14,10 +14,9 @@ import { SvgQuote } from '@guardian/src-icons'; import type { Format } from '@guardian/types'; import { Design, Display } from '@guardian/types'; import { headlineTextColour } from 'editorialStyles'; -import type { Item } from 'item'; -import { getFormat } from 'item'; +import type { ItemExtras } from 'itemExtrasContext'; +import { useItemExtras } from 'itemExtrasContext'; import type { FC } from 'react'; -import { getThemeStyles } from 'themeStyles'; import Series from '../series'; import { articleWidthStyles } from '../styles'; @@ -126,16 +125,14 @@ const getSharedStyles = (format: Format): SerializedStyles => css` margin: 0; `; -const getQuoteStyles = (format: Format): SerializedStyles => { - const { kicker } = getThemeStyles(format.theme); - +const getQuoteStyles = (kickerColor: string): SerializedStyles => { return css` margin: 0; svg { margin-bottom: -0.65rem; width: 40px; margin-left: -0.3rem; - fill: ${kicker}; + fill: ${kickerColor}; } ${from.tablet} { @@ -147,22 +144,26 @@ const getQuoteStyles = (format: Format): SerializedStyles => { `; }; -const getDecorativeStyles = (item: Item): JSX.Element | string => { - const format = getFormat(item); +const getDecorativeStyles = (itemExtras: ItemExtras): JSX.Element | string => { + const { + design, + headline, + themeStyles: { kicker }, + } = itemExtras; - if (item.design === Design.Interview) { - return {item.headline}; + if (design === Design.Interview) { + return {headline}; } - if (item.design === Design.Comment) { + if (design === Design.Comment) { return ( - + - {item.headline} + {headline} ); } - return item.headline; + return headline; }; const getHeadlineStyles = ( @@ -216,23 +217,22 @@ const hasSeriesKicker = (format: Format): boolean => // ----- Component ----- // -interface Props { - item: Item; -} - -const Headline: FC = ({ item }) => { - const format = getFormat(item); - const { kicker: kickerColor } = getThemeStyles(format.theme); +const Headline: FC = () => { + const itemExtras = useItemExtras(); + const { + format, + themeStyles: { kicker: kickerColor }, + } = itemExtras; return (
{hasSeriesKicker(format) && (
- +
)}

- {getDecorativeStyles(item)} + {getDecorativeStyles(itemExtras)}

); diff --git a/src/components/editions/pullquote.tsx b/src/components/editions/pullquote.tsx index ff0c6e4ec..46dd85b07 100644 --- a/src/components/editions/pullquote.tsx +++ b/src/components/editions/pullquote.tsx @@ -3,17 +3,16 @@ import { css } from '@emotion/core'; import { from } from '@guardian/src-foundations/mq'; import { headline } from '@guardian/src-foundations/typography'; import { SvgQuote } from '@guardian/src-icons/quote'; -import type { Format, Option } from '@guardian/types'; +import type { Option } from '@guardian/types'; import { map, withDefault } from '@guardian/types'; +import { useItemExtras } from 'itemExtrasContext'; import { pipe2 } from 'lib'; import type { FC, ReactNode } from 'react'; -import { getThemeStyles } from 'themeStyles'; export const pullquoteWidth = '10.875rem'; const pullquoteTailSize = '1.5rem'; -const styles = (format: Format): SerializedStyles => { - const { kicker } = getThemeStyles(format.theme); +const styles = (kickerColor: string): SerializedStyles => { return css` width: ${pullquoteWidth}; position: relative; @@ -21,9 +20,9 @@ const styles = (format: Format): SerializedStyles => { padding: 0 0.5rem 1.5rem 0.5rem; margin: 0.375rem 1rem calc(1rem + ${pullquoteTailSize}) 0; - color: ${kicker}; - border: 1px solid ${kicker}; - border-top: 0.75rem solid ${kicker}; + color: ${kickerColor}; + border: 1px solid ${kickerColor}; + border-top: 0.75rem solid ${kickerColor}; border-bottom: none; float: left; @@ -41,7 +40,7 @@ const styles = (format: Format): SerializedStyles => { left: -1px; width: ${pullquoteTailSize}; height: ${pullquoteTailSize}; - border: 1px solid ${kicker}; + border: 1px solid ${kickerColor}; border-top: none; border-radius: 0 0 100% 0; } @@ -53,14 +52,12 @@ const styles = (format: Format): SerializedStyles => { left: calc(${pullquoteTailSize} + 1px); width: calc(100% - ${pullquoteTailSize}); height: 1px; - border-top: 1px solid ${kicker}; + border-top: 1px solid ${kickerColor}; } `; }; -const quoteStyles = (format: Format): SerializedStyles => { - const { kicker } = getThemeStyles(format.theme); - +const quoteStyles = (kickerColor: string): SerializedStyles => { return css` margin: 0; ${headline.xxsmall({ fontWeight: 'regular' })} @@ -68,7 +65,7 @@ const quoteStyles = (format: Format): SerializedStyles => { margin-bottom: -0.6rem; height: 2rem; margin-left: -0.3rem; - fill: ${kicker}; + fill: ${kickerColor}; } `; }; @@ -80,7 +77,6 @@ const citeStyles = css` type Props = { quote: string; - format: Format; attribution: Option; }; @@ -88,9 +84,12 @@ const blockQuoteStyles = css` margin: 0; `; -const Pullquote: FC = ({ quote, attribution, format }) => { +const Pullquote: FC = ({ quote, attribution }) => { + const { + themeStyles: { kicker }, + } = useItemExtras(); const quoteElement = ( -

+

{quote}

@@ -107,7 +106,7 @@ const Pullquote: FC = ({ quote, attribution, format }) => { ); return ( -