Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add investigations moment banner #525

Merged
merged 14 commits into from
Sep 24, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ const withBannerData = (
email,
tickerSettings,
isSupporter,
numArticles,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needed to be passed through to so the investigations banner can render the special opt out subheading

};
return <Banner {...props} />;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/modules/src/modules/banners/common/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type BannerId =
| 'contributions-banner'
| 'g200-banner'
| 'aus-moment-banner'
| 'investigations-moment-banner'
| 'subscription-banner'
| 'weekly-banner';

Expand Down Expand Up @@ -56,4 +57,5 @@ export interface BannerRenderProps {
email?: string;
tickerSettings?: TickerSettings;
isSupporter?: boolean;
numArticles?: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import { Story, Meta } from '@storybook/react';
import { InvestigationsMomentBannerUnvalidated as InvestigationsMoment } from './InvestigationsMomentBanner';
import { props } from '../utils/storybook';
import { BannerProps, SecondaryCtaType } from '@sdc/shared/types';

export default {
component: InvestigationsMoment,
title: 'Banners/InvestigationsMoment',
args: props,
} as Meta;

const Template: Story<BannerProps> = (props: BannerProps) => <InvestigationsMoment {...props} />;

export const WithoutArticleCount = Template.bind({});
WithoutArticleCount.args = {
...props,
mobileContent: {
heading: 'Invest in investigative journalism',
messageText:
'Dummy copy In these extraordinary times, millions rely on the Guardian for high-impact, independent journalism that stands for truth and integrity. With no shareholders or billionaire owner, we report on world events with accuracy billionaire owner, we report on world events with accuracy billionaire owner, we report on world events with accuracy',
cta: {
text: 'Support us',
baseUrl: 'https://support.theguardian.com/contribute',
},
secondaryCta: {
type: SecondaryCtaType.Custom,
cta: {
text: 'Learn more',
baseUrl: 'https://theguardian.com',
},
},
},
content: {
heading: 'Invest in investigative journalism',
messageText:
'Fearless, investigative reporting shapes a fairer world. At the Guardian, our independence allows us to chase the truth wherever it takes us. We have no shareholders. No vested interests. Just the determination and passion to bring readers quality reporting, including groundbreaking investigations. We do not shy away. And we provide all this for free, for everyone.',
highlightedText:
'Show your support today from just $1, or sustain us long term with a little more. Thank you.',
cta: {
text: 'Support the Guardian',
baseUrl: 'https://support.theguardian.com/contribute',
},
secondaryCta: {
type: SecondaryCtaType.Custom,
cta: {
text: 'Learn more about us',
baseUrl: 'https://theguardian.com',
},
},
},
numArticles: 0,
};

export const WithArticleCount = Template.bind({});
WithArticleCount.args = {
...WithoutArticleCount.args,
numArticles: 50,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import React from 'react';
import { css } from '@emotion/react';
import { neutral, space } from '@guardian/src-foundations';
import { from } from '@guardian/src-foundations/mq';
import { Container, Hide } from '@guardian/src-layout';
import { BannerRenderProps } from '../common/types';
import { bannerWrapper, validatedBannerWrapper } from '../common/BannerWrapper';
import { InvestigationsMomentBannerHeader } from './components/InvestigationsMomentBannerHeader';
import { InvestigationsMomentBannerArticleCount } from './components/InvestigationsMomentBannerArticleCount';
import { InvestigationsMomentBannerBody } from './components/InvestigationsMomentBannerBody';
import { InvestigationsMomentBannerCtas } from './components/InvestigationsMomentBannerCtas';
import { InvestigationsMomentBannerCloseButton } from './components/InvestigationsMomentBannerCloseButton';

const styles = {
container: css`
position: relative;
overflow: hidden;
background: ${neutral[0]};
border-top: 1px solid ${neutral[0]};

* {
box-sizing: border-box;
}

${from.tablet} {
background: ${neutral[100]};
}
`,
desktopShadowRight: css`
position: absolute;
pointer-events: none;
display: flex;
justify-content: flex-end;
top: 0;
right: 0;
width: 100px;
height: 80px;

${from.tablet} {
bottom: 0;
width: auto;
height: auto;
}

svg {
display: block;
height: 100%;

${from.tablet} {
height: 90%;
}

${from.desktop} {
height: 95%;
}

${from.leftCol} {
height: 90%;
}
}
`,
desktopShadowBottom: css`
position: absolute;
pointer-events: none;
bottom: 0;
left: 0;
right: 20px;

svg {
display: block;
}

${from.wide} {
height: 125px;
width: 1250px;
right: auto;
}
`,
headerContainer: css`
margin: 0 -${space[3]}px;

${from.mobileLandscape} {
margin: 0 -${space[5]}px;
}

${from.tablet} {
margin: 0;
}
`,
bottomContainer: css`
padding: ${space[2]}px 0 ${space[3]}px;

${from.tablet} {
max-width: 70%;
padding-bottom: 80px;
}
`,
bodyContainer: css`
margin-top: ${space[1]}px;
`,
ctasContainer: css`
display: flex;
flex-direction: row;
margin-top: ${space[4]}px;

${from.tablet} {
margin-top: ${space[6]}px;
justify-content: flex-end;
margin-right: -65px;
}
`,
closeButtonContainer: css`
position: absolute;
top: ${space[2]}px;
right: ${space[4]}px;

${from.leftCol} {
top: ${space[3]}px;
right: ${space[5]}px;
}
`,
};

function InvestigationsMomentBanner({
content,
onCloseClick,
numArticles,
onCtaClick,
onSecondaryCtaClick,
}: BannerRenderProps) {
return (
<Container cssOverrides={styles.container}>
<div css={styles.headerContainer}>
<InvestigationsMomentBannerHeader
heading={content.mainContent.heading}
mobileHeading={content.mobileContent?.heading ?? null}
/>
</div>

<div css={styles.bottomContainer}>
{numArticles !== undefined && numArticles > 5 && (
<section>
<InvestigationsMomentBannerArticleCount numArticles={numArticles} />
</section>
)}

<section css={styles.bodyContainer}>
<InvestigationsMomentBannerBody
messageText={content.mainContent.messageText}
mobileMessageText={content.mobileContent?.messageText ?? null}
highlightedText={content.mainContent.highlightedText ?? null}
mobileHighlightedText={content.mobileContent?.highlightedText ?? null}
/>
</section>

<section css={styles.ctasContainer}>
<InvestigationsMomentBannerCtas
primaryCta={content.mainContent.primaryCta}
secondaryCta={content.mainContent.secondaryCta}
mobilePrimaryCta={content.mobileContent?.primaryCta ?? null}
mobileSecondaryCta={content.mobileContent?.secondaryCta ?? null}
onPrimaryCtaClick={onCtaClick}
onSecondaryCtaClick={onSecondaryCtaClick}
/>
</section>
</div>

<Hide above="tablet">
<div css={styles.desktopShadowRight}>
<svg viewBox="0 0 100 80" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 0, 100 0, 100 80" />
</svg>
</div>
</Hide>

<Hide below="tablet" above="desktop">
<div css={styles.desktopShadowRight}>
<svg viewBox="0 0 100 200" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 0, 100 0, 100 200" />
</svg>
</div>

<div css={styles.desktopShadowBottom}>
<svg viewBox="0 0 1000 100" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 100, 1000 100, 0 0" />
</svg>
</div>
</Hide>

<Hide below="desktop" above="leftCol">
<div css={styles.desktopShadowRight}>
<svg viewBox="0 0 300 400" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 0, 300 0, 300 400" />
</svg>
</div>

<div css={styles.desktopShadowBottom}>
<svg viewBox="0 0 1000 100" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 100, 1000 100, 0 0" />
</svg>
</div>
</Hide>

<Hide below="leftCol" above="wide">
<div css={styles.desktopShadowRight}>
<svg viewBox="0 0 350 400" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 0, 350 0, 350 400" />
</svg>
</div>

<div css={styles.desktopShadowBottom}>
<svg viewBox="0 0 1000 100" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 100, 1000 100, 0 0" />
</svg>
</div>
</Hide>

<Hide below="wide">
<div css={styles.desktopShadowRight}>
<svg viewBox="0 0 530 400" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 0, 530 0, 530 400" />
</svg>
</div>

<div css={styles.desktopShadowBottom}>
<svg viewBox="0 0 1000 100" xmlns="http://www.w3.org/2000/svg">
<polygon points="0 100, 1000 100, 0 0" />
</svg>
</div>
</Hide>

<div css={styles.closeButtonContainer}>
<InvestigationsMomentBannerCloseButton onCloseClick={onCloseClick} />
</div>
</Container>
);
}

const unvalidated = bannerWrapper(InvestigationsMomentBanner, 'investigations-moment-banner');
const validated = validatedBannerWrapper(
InvestigationsMomentBanner,
'investigations-moment-banner',
);

export {
validated as InvestigationsMomentBanner,
unvalidated as InvestigationsMomentBannerUnvalidated,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { css } from '@emotion/react';
import { brandAlt, news } from '@guardian/src-foundations';
import { from } from '@guardian/src-foundations/mq';
import { headline } from '@guardian/src-foundations/typography';
import { ArticleCountOptOutPopup } from '../../../shared/ArticleCountOptOutPopup';
import { Hide } from '@guardian/src-layout';

const styles = {
container: css`
${headline.xxxsmall({ fontWeight: 'bold' })}
font-size: 15px;
color: ${brandAlt[400]};
margin: 0;

${from.tablet} {
font-size: 17px;
color: ${news[400]};
}

${from.desktop} {
font-size: 20px;
}
`,
};

interface InvestigationsMomentBannerArticleCountProps {
numArticles: number;
}

export function InvestigationsMomentBannerArticleCount({
numArticles,
}: InvestigationsMomentBannerArticleCountProps): JSX.Element {
return (
<p css={styles.container}>
You have read{' '}
<Hide above="tablet">
<ArticleCountOptOutPopup
numArticles={numArticles}
nextWord=" articles"
type="banner"
/>
</Hide>
<Hide below="tablet">
<ArticleCountOptOutPopup
numArticles={numArticles}
nextWord=" articles"
type="investigations-moment-banner"
/>
</Hide>{' '}
in the past year
</p>
);
}