Opening the privacy policy as an overlay when possible

It still exists as a separate page, but will open as an overlay for a
simple click
This commit is contained in:
Jeff Avallone 2019-01-18 16:24:10 -05:00
parent 83de8ebcbc
commit 2c8b779793
8 changed files with 550 additions and 132 deletions

View File

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import Modal from 'react-modal';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { I18nextProvider } from 'react-i18next'; import { I18nextProvider } from 'react-i18next';
@ -7,6 +8,25 @@ import Layout from 'components/Layout';
import 'site.css'; import 'site.css';
Modal.setAppElement('#___gatsby');
Modal.defaultStyles.overlay = {
...Modal.defaultStyles.overlay,
backgroundColor: 'rgba(0, 0, 0, 0.25)'
};
Modal.defaultStyles.content = {
...Modal.defaultStyles.content,
background: 'transparent',
border: '0 solid',
borderRadius: '0',
overflow: null,
padding: '2rem',
top: '7rem',
bottom: '7rem',
left: '2rem',
right: '2rem'
};
export const onClientEntry = () => { export const onClientEntry = () => {
Sentry.getCurrentHub().getClient().getOptions().enabled = Sentry.getCurrentHub().getClient().getOptions().enabled =
(navigator.doNotTrack !== '1' && window.doNotTrack !== '1'); (navigator.doNotTrack !== '1' && window.doNotTrack !== '1');

View File

@ -108,6 +108,7 @@
"react-dom": "^16.7.0", "react-dom": "^16.7.0",
"react-feather": "^1.1.5", "react-feather": "^1.1.5",
"react-helmet": "^5.2.0", "react-helmet": "^5.2.0",
"react-i18next": "^9.0.2" "react-i18next": "^9.0.2",
"react-modal": "^3.8.1"
} }
} }

View File

@ -1,10 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Header rendering 1`] = ` exports[`Header closing the Privacy Policy modal 1`] = `
<header <Fragment>
<Modal
ariaHideApp={true}
bodyOpenClassName="ReactModal__Body--open"
closeTimeoutMS={0}
isOpen={true}
onRequestClose={[Function]}
parentSelector={[Function]}
portalClassName="ReactModalPortal"
role="dialog"
shouldCloseOnEsc={true}
shouldCloseOnOverlayClick={true}
shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true}
>
<LoadNamespace(PrivacyPolicy) />
<a
className="modalClose"
href="#close"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/>
</a>
</Modal>
<header
className="header" className="header"
data-banner="testing" data-banner={null}
> >
<h1> <h1>
<mockConstructor <mockConstructor
to="/" to="/"
@ -32,6 +59,7 @@ exports[`Header rendering 1`] = `
</li> </li>
<li> <li>
<mockConstructor <mockConstructor
onClick={[Function]}
to="/privacy" to="/privacy"
> >
<WithMergedOptions(TransComponent)> <WithMergedOptions(TransComponent)>
@ -48,14 +76,282 @@ exports[`Header rendering 1`] = `
<LoadNamespace(LocaleSwitcher) /> <LoadNamespace(LocaleSwitcher) />
</li> </li>
</ul> </ul>
</header> </header>
</Fragment>
`;
exports[`Header closing the Privacy Policy modal 2`] = `
<Fragment>
<Modal
ariaHideApp={true}
bodyOpenClassName="ReactModal__Body--open"
closeTimeoutMS={0}
isOpen={false}
onRequestClose={[Function]}
parentSelector={[Function]}
portalClassName="ReactModalPortal"
role="dialog"
shouldCloseOnEsc={true}
shouldCloseOnOverlayClick={true}
shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true}
>
<LoadNamespace(PrivacyPolicy) />
<a
className="modalClose"
href="#close"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/>
</a>
</Modal>
<header
className="header"
data-banner={null}
>
<h1>
<mockConstructor
to="/"
>
Regexper
</mockConstructor>
</h1>
<ul
className="list"
>
<li>
<a
href="https://gitlab.com/javallone/regexper-static"
rel="external noopener noreferrer"
target="_blank"
>
<Gitlab
color="currentColor"
size="24"
/>
<WithMergedOptions(TransComponent)>
Source on GitLab
</WithMergedOptions(TransComponent)>
</a>
</li>
<li>
<mockConstructor
onClick={[Function]}
to="/privacy"
>
<WithMergedOptions(TransComponent)>
Privacy Policy
</WithMergedOptions(TransComponent)>
</mockConstructor>
</li>
<li>
<LoadNamespace(InstallPrompt) />
</li>
<li
data-requires-js={true}
>
<LoadNamespace(LocaleSwitcher) />
</li>
</ul>
</header>
</Fragment>
`;
exports[`Header opening the Privacy Policy modal 1`] = `
<Fragment>
<Modal
ariaHideApp={true}
bodyOpenClassName="ReactModal__Body--open"
closeTimeoutMS={0}
isOpen={true}
onRequestClose={[Function]}
parentSelector={[Function]}
portalClassName="ReactModalPortal"
role="dialog"
shouldCloseOnEsc={true}
shouldCloseOnOverlayClick={true}
shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true}
>
<LoadNamespace(PrivacyPolicy) />
<a
className="modalClose"
href="#close"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/>
</a>
</Modal>
<header
className="header"
data-banner={null}
>
<h1>
<mockConstructor
to="/"
>
Regexper
</mockConstructor>
</h1>
<ul
className="list"
>
<li>
<a
href="https://gitlab.com/javallone/regexper-static"
rel="external noopener noreferrer"
target="_blank"
>
<Gitlab
color="currentColor"
size="24"
/>
<WithMergedOptions(TransComponent)>
Source on GitLab
</WithMergedOptions(TransComponent)>
</a>
</li>
<li>
<mockConstructor
onClick={[Function]}
to="/privacy"
>
<WithMergedOptions(TransComponent)>
Privacy Policy
</WithMergedOptions(TransComponent)>
</mockConstructor>
</li>
<li>
<LoadNamespace(InstallPrompt) />
</li>
<li
data-requires-js={true}
>
<LoadNamespace(LocaleSwitcher) />
</li>
</ul>
</header>
</Fragment>
`;
exports[`Header rendering 1`] = `
<Fragment>
<Modal
ariaHideApp={true}
bodyOpenClassName="ReactModal__Body--open"
closeTimeoutMS={0}
isOpen={false}
onRequestClose={[Function]}
parentSelector={[Function]}
portalClassName="ReactModalPortal"
role="dialog"
shouldCloseOnEsc={true}
shouldCloseOnOverlayClick={true}
shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true}
>
<LoadNamespace(PrivacyPolicy) />
<a
className="modalClose"
href="#close"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/>
</a>
</Modal>
<header
className="header"
data-banner="testing"
>
<h1>
<mockConstructor
to="/"
>
Regexper
</mockConstructor>
</h1>
<ul
className="list"
>
<li>
<a
href="https://gitlab.com/javallone/regexper-static"
rel="external noopener noreferrer"
target="_blank"
>
<Gitlab
color="currentColor"
size="24"
/>
<WithMergedOptions(TransComponent)>
Source on GitLab
</WithMergedOptions(TransComponent)>
</a>
</li>
<li>
<mockConstructor
onClick={[Function]}
to="/privacy"
>
<WithMergedOptions(TransComponent)>
Privacy Policy
</WithMergedOptions(TransComponent)>
</mockConstructor>
</li>
<li>
<LoadNamespace(InstallPrompt) />
</li>
<li
data-requires-js={true}
>
<LoadNamespace(LocaleSwitcher) />
</li>
</ul>
</header>
</Fragment>
`; `;
exports[`Header rendering with no banner 1`] = ` exports[`Header rendering with no banner 1`] = `
<header <Fragment>
<Modal
ariaHideApp={true}
bodyOpenClassName="ReactModal__Body--open"
closeTimeoutMS={0}
isOpen={false}
onRequestClose={[Function]}
parentSelector={[Function]}
portalClassName="ReactModalPortal"
role="dialog"
shouldCloseOnEsc={true}
shouldCloseOnOverlayClick={true}
shouldFocusAfterRender={true}
shouldReturnFocusAfterClose={true}
>
<LoadNamespace(PrivacyPolicy) />
<a
className="modalClose"
href="#close"
onClick={[Function]}
>
<XSquare
color="currentColor"
size="24"
/>
</a>
</Modal>
<header
className="header" className="header"
data-banner={null} data-banner={null}
> >
<h1> <h1>
<mockConstructor <mockConstructor
to="/" to="/"
@ -83,6 +379,7 @@ exports[`Header rendering with no banner 1`] = `
</li> </li>
<li> <li>
<mockConstructor <mockConstructor
onClick={[Function]}
to="/privacy" to="/privacy"
> >
<WithMergedOptions(TransComponent)> <WithMergedOptions(TransComponent)>
@ -99,5 +396,6 @@ exports[`Header rendering with no banner 1`] = `
<LoadNamespace(LocaleSwitcher) /> <LoadNamespace(LocaleSwitcher) />
</li> </li>
</ul> </ul>
</header> </header>
</Fragment>
`; `;

View File

@ -1,16 +1,57 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Modal from 'react-modal';
import { Link } from 'gatsby'; import { Link } from 'gatsby';
import { withNamespaces, Trans } from 'react-i18next'; import { withNamespaces, Trans } from 'react-i18next';
import GitlabIcon from 'react-feather/dist/icons/gitlab'; import GitlabIcon from 'react-feather/dist/icons/gitlab';
import CloseIcon from 'react-feather/dist/icons/x-square';
import LocaleSwitcher from 'components/LocaleSwitcher'; import LocaleSwitcher from 'components/LocaleSwitcher';
import InstallPrompt from 'components/InstallPrompt'; import InstallPrompt from 'components/InstallPrompt';
import PrivacyPolicy from 'components/PrivacyPolicy';
import style from './style.module.css'; import style from './style.module.css';
export const Header = ({ banner }) => ( class Header extends React.PureComponent {
state = {
showModal: false
}
static propTypes = {
banner: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string
]).isRequired
}
handleOpen = event => {
event.preventDefault();
this.setState({ showModal: true });
}
handleClose = event => {
event.preventDefault();
this.setState({ showModal: false });
}
render() {
const { banner } = this.props;
const { showModal } = this.state;
return <>
<Modal
isOpen={ showModal }
onRequestClose={ this.handleClose }
shouldCloseOnOverlayClick={ true }>
<PrivacyPolicy />
<a
href="#close"
className={ style.modalClose }
onClick={ this.handleClose }>
<CloseIcon />
</a>
</Modal>
<header <header
className={ style.header } className={ style.header }
data-banner={ banner || null }> data-banner={ banner || null }>
@ -28,7 +69,7 @@ export const Header = ({ banner }) => (
</a> </a>
</li> </li>
<li> <li>
<Link to="/privacy"> <Link to="/privacy" onClick={ this.handleOpen }>
<Trans>Privacy Policy</Trans> <Trans>Privacy Policy</Trans>
</Link> </Link>
</li> </li>
@ -40,13 +81,9 @@ export const Header = ({ banner }) => (
</li> </li>
</ul> </ul>
</header> </header>
); </>;
}
Header.propTypes = { }
banner: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.string
]).isRequired
};
export { Header };
export default withNamespaces()(Header); export default withNamespaces()(Header);

View File

@ -66,3 +66,23 @@
} }
} }
} }
.modalClose {
position: absolute;
top: 3rem;
right: 2rem;
line-height: 2.8rem;
padding: 1rem;
&:hover svg,
&:active svg {
color: var(--color-white);
}
& svg {
display: inline-block;
width: 2.8rem;
height: 2.8rem;
vertical-align: middle;
}
}

View File

@ -17,4 +17,32 @@ describe('Header', () => {
); );
expect(component).toMatchSnapshot(); expect(component).toMatchSnapshot();
}); });
test('opening the Privacy Policy modal', () => {
const component = shallow(
<Header banner={ false } />
);
const eventObj = { preventDefault: jest.fn() };
component.instance().handleOpen(eventObj);
expect(eventObj.preventDefault).toHaveBeenCalled();
expect(component).toMatchSnapshot();
});
test('closing the Privacy Policy modal', () => {
const component = shallow(
<Header banner={ false } />
);
const eventObj = { preventDefault: jest.fn() };
component.setState({ showModal: true });
expect(component).toMatchSnapshot();
component.instance().handleClose(eventObj);
expect(eventObj.preventDefault).toHaveBeenCalled();
expect(component).toMatchSnapshot();
});
}); });

View File

@ -5,6 +5,9 @@
color: var(--color-black); color: var(--color-black);
margin: var(--spacing-margin) 0; margin: var(--spacing-margin) 0;
box-shadow: 0 0 1rem color(var(--color-black) alpha(0.7)); box-shadow: 0 0 1rem color(var(--color-black) alpha(0.7));
max-height: 100%;
display: flex;
flex-direction: column;
} }
.header { .header {
@ -25,6 +28,7 @@
.content { .content {
padding: var(--spacing-margin); padding: var(--spacing-margin);
overflow: auto;
& p { & p {
margin-top: 0; margin-top: 0;

View File

@ -4810,7 +4810,7 @@ execa@^1.0.0:
signal-exit "^3.0.0" signal-exit "^3.0.0"
strip-eof "^1.0.0" strip-eof "^1.0.0"
exenv@^1.2.1: exenv@^1.2.0, exenv@^1.2.1:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
@ -10542,7 +10542,7 @@ prompts@^0.1.9:
kleur "^2.0.1" kleur "^2.0.1"
sisteransi "^0.1.1" sisteransi "^0.1.1"
prop-types@^15.5.4, prop-types@^15.6.1, prop-types@^15.6.2: prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.6.1, prop-types@^15.6.2:
version "15.6.2" version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==
@ -10834,11 +10834,21 @@ react-is@^16.3.2, react-is@^16.6.1, react-is@^16.7.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa"
integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g== integrity sha512-Z0VRQdF4NPDoI0tsXVMLkJLiwEBa+RP66g0xDHxgxysxSoCUccSten4RTF/UFvZF1dZvZ9Zu1sx+MDXwcOR34g==
react-lifecycles-compat@^3.0.4: react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-modal@^3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.8.1.tgz#7300f94a6f92a2e17994de0be6ccb61734464c9e"
integrity sha512-aLKeZM9pgXpIKVwopRHMuvqKWiBajkqisDA8UzocdCF6S4fyKVfLWmZR5G1Q0ODBxxxxf2XIwiCP8G/11GJAuw==
dependencies:
exenv "^1.2.0"
prop-types "^15.5.10"
react-lifecycles-compat "^3.0.0"
warning "^3.0.0"
react-side-effect@^1.1.0: react-side-effect@^1.1.0:
version "1.1.5" version "1.1.5"
resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d" resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d"