diff --git a/dotcom-rendering/src/components/ExpandableMarketingCard.stories.tsx b/dotcom-rendering/src/components/ExpandableMarketingCard.stories.tsx index 8924fbcf7cf..a8a87b2721c 100644 --- a/dotcom-rendering/src/components/ExpandableMarketingCard.stories.tsx +++ b/dotcom-rendering/src/components/ExpandableMarketingCard.stories.tsx @@ -32,8 +32,6 @@ export const Default = { chromatic: { viewports: [ breakpoints.mobile, - breakpoints.mobileMedium, - breakpoints.phablet, breakpoints.tablet, breakpoints.desktop, ], diff --git a/dotcom-rendering/src/components/ExpandableMarketingCard.tsx b/dotcom-rendering/src/components/ExpandableMarketingCard.tsx index 01546958e18..dde37329e26 100644 --- a/dotcom-rendering/src/components/ExpandableMarketingCard.tsx +++ b/dotcom-rendering/src/components/ExpandableMarketingCard.tsx @@ -24,10 +24,44 @@ interface BannersIllustrationProps { styles?: SerializedStyles; } +const smallIllustrationStyles = css` + display: none; + ${from.phablet} { + display: inline; + } + ${from.leftCol} { + display: none; + } +`; +const largeIllustrationStyles = css` + display: inline; + ${from.phablet} { + display: none; + } + ${from.leftCol} { + display: inline; + } +`; + const BannersIllustration = ({ type, styles }: BannersIllustrationProps) => { const { assetOrigin } = useConfig(); - const src = `${assetOrigin}static/frontend/logos/red-blue-banner-${type}.svg`; - return ; + const smallSrc = `${assetOrigin}static/frontend/logos/red-blue-small-banner-${type}.svg`; + const largeSrc = `${assetOrigin}static/frontend/logos/red-blue-large-banner-${type}.svg`; + + return ( + <> + + + + ); }; const fillBarStyles = css` @@ -64,6 +98,10 @@ const summaryStyles = css` z-index: 1; width: 100%; `; +const contractedSummaryStyles = css` + ${summaryStyles} + cursor: pointer; +`; const headingStyles = css` display: flex; @@ -162,7 +200,6 @@ interface Props { setIsClosed: Dispatch>; } -// todo - semantic html accordion-details? export const ExpandableMarketingCard = ({ guardianBaseURL, heading, @@ -182,7 +219,8 @@ export const ExpandableMarketingCard = ({ styles={imageTopStyles} />
{ @@ -220,6 +258,7 @@ export const ExpandableMarketingCard = ({

{heading}

+ topOfBody.getBoundingClientRect().top < 0; const isFirstArticle = () => { const [dailyCount = {} as DailyArticle] = getDailyArticleCount() ?? []; @@ -32,11 +34,43 @@ const isNewUSUser = async () => { return !hasUserSelectedNonUSEdition && !isNewUser; }; -// todo - semantic html accordion-details? +const stickyContainerStyles = css` + position: sticky; + top: 0; + ${getZIndex('expandableMarketingCardOverlay')}; + animation: slidein 2.4s linear; + + @keyframes slidein { + from { + transform: translateX(-1200px); + } + + to { + transform: translateX(0); + } + } +`; + +const absoluteContainerStyles = css` + position: absolute; + width: 100%; +`; + +interface Props { + guardianBaseURL: string; +} + export const ExpandableMarketingCardWrapper = ({ guardianBaseURL }: Props) => { const [isExpanded, setIsExpanded] = useState(false); const [isClosed, setIsClosed] = useState(false); const [isApplicableUser, setIsApplicableUser] = useState(false); + const [topOfBody, setTopOfBody] = useState(null); + + /** + * On screen sizes below leftCol (<1140px), only display the card + * when the user scrolls past the top of the article. + */ + const [shouldDisplayCard, setShouldDisplayCard] = useState(false); const abTestAPI = useAB()?.api; const isInVariantFree = !!abTestAPI?.isUserInVariant( @@ -57,6 +91,41 @@ export const ExpandableMarketingCardWrapper = ({ guardianBaseURL }: Props) => { }); }, []); + useEffect(() => { + setTopOfBody(document.querySelector('[data-gu-name="body"]')); + }, []); + + useEffect(() => { + if (!topOfBody) return; + + /** + * It's possible that the viewport does not start at the top of the page. + */ + if (isViewportBelowTopOfBody(topOfBody)) { + setShouldDisplayCard(true); + return; + } + + /** + * Show the card when the top of the body moves out of the viewport. + */ + const observer = new window.IntersectionObserver( + ([entry]) => { + if (!entry) return; + if (entry.isIntersecting) { + setShouldDisplayCard(true); + } + }, + { rootMargin: '0px 0px -100%' }, + ); + + observer.observe(topOfBody); + + return () => { + observer.disconnect(); + }; + }, [topOfBody]); + if (!isInEitherVariant || !isApplicableUser || isClosed) { return null; } @@ -70,13 +139,33 @@ export const ExpandableMarketingCardWrapper = ({ guardianBaseURL }: Props) => { : 'Why the Guardian has no paywall'; return ( - + <> + + + + + {shouldDisplayCard && ( +
+
+ +
+
+ )} +
+ ); }; diff --git a/dotcom-rendering/src/layouts/CommentLayout.tsx b/dotcom-rendering/src/layouts/CommentLayout.tsx index 4232f296e73..bba543f4b72 100644 --- a/dotcom-rendering/src/layouts/CommentLayout.tsx +++ b/dotcom-rendering/src/layouts/CommentLayout.tsx @@ -600,6 +600,24 @@ export const CommentLayout = (props: WebProps | AppsProps) => { + {isWeb && ( + + + + + + )}
{
+ {isWeb && ( + + + + + + )} { /> - {isWeb && ( - - - - - - - - )} diff --git a/dotcom-rendering/src/layouts/ShowcaseLayout.tsx b/dotcom-rendering/src/layouts/ShowcaseLayout.tsx index bda4ad0f2c3..7b1b281a22b 100644 --- a/dotcom-rendering/src/layouts/ShowcaseLayout.tsx +++ b/dotcom-rendering/src/layouts/ShowcaseLayout.tsx @@ -580,6 +580,24 @@ export const ShowcaseLayout = (props: WebProps | AppsProps) => { + {isWeb && ( + + + + + + )} { )} + {isWeb && ( + + + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dotcom-rendering/src/static/logos/red-blue-small-banner-faded.svg b/dotcom-rendering/src/static/logos/red-blue-small-banner-faded.svg new file mode 100644 index 00000000000..4ded194ae58 --- /dev/null +++ b/dotcom-rendering/src/static/logos/red-blue-small-banner-faded.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dotcom-rendering/src/static/logos/red-blue-small-banner-top.svg b/dotcom-rendering/src/static/logos/red-blue-small-banner-top.svg new file mode 100644 index 00000000000..8e80855e76a --- /dev/null +++ b/dotcom-rendering/src/static/logos/red-blue-small-banner-top.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +