Initial code copied from brianlovin.com

This commit is contained in:
Brian Lovin 2019-01-12 17:52:43 -08:00
parent 32d9b444c7
commit 5fa7d5e7e2
56 changed files with 13802 additions and 0 deletions

14
.babelrc Normal file
View file

@ -0,0 +1,14 @@
{
"presets": ["next/babel"],
"plugins": [
"transform-flow-strip-types",
[
"styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": false
}
]
]
}

126
.eslintrc.json Normal file
View file

@ -0,0 +1,126 @@
{
"extends": [
"airbnb",
"prettier",
"plugin:react/recommended"
],
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 8,
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"impliedStrict": true,
"classes": true
}
},
"env": {
"browser": true,
"node": true,
"jquery": true,
"jest": true
},
"rules": {
"no-debugger": 0,
"no-alert": 0,
"no-unused-vars": [
1,
{
"ignoreSiblings": true,
"argsIgnorePattern": "res|next|^err"
}
],
"prefer-const": [
"error",
{
"destructuring": "all"
}
],
"arrow-body-style": [
2,
"as-needed"
],
"no-unused-expressions": [
2,
{
"allowTaggedTemplates": true
}
],
"no-param-reassign": [
2,
{
"props": false
}
],
"no-console": 0,
"import/prefer-default-export": 0,
"import": 0,
"func-names": 0,
"space-before-function-paren": 0,
"comma-dangle": 0,
"max-len": 0,
"import/extensions": 0,
"no-underscore-dangle": 0,
"consistent-return": 0,
"react/display-name": 1,
"react/no-array-index-key": 0,
"react/react-in-jsx-scope": 0,
"react/prefer-stateless-function": 0,
"react/forbid-prop-types": 0,
"react/no-unescaped-entities": 0,
"jsx-a11y/accessible-emoji": 0,
"react/jsx-one-expression-per-line": 0,
"react/require-default-props": 0,
"react/jsx-filename-extension": [
1,
{
"extensions": [
".js",
".jsx"
]
}
],
"radix": 0,
"no-shadow": [
2,
{
"hoist": "all",
"allow": [
"resolve",
"reject",
"done",
"next",
"err",
"error"
]
}
],
"quotes": [
2,
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"prettier/prettier": [
"error",
{
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80
}
],
"jsx-a11y/href-no-hash": "off",
"jsx-a11y/anchor-is-valid": [
"warn",
{
"aspects": [
"invalidHref"
]
}
]
},
"plugins": [
"prettier"
]
}

26
.flowconfig Normal file
View file

@ -0,0 +1,26 @@
[ignore]
<PROJECT_ROOT>/node_modules
[include]
[libs]
./flow-typed
[options]
suppress_comment=.*\\$FlowFixMe
suppress_comment=.*\\$FlowIssue
esproposal.class_instance_fields=enable
module.system.node.resolve_dirname=node_modules
module.system.node.resolve_dirname=.
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.json
[lints]
untyped-type-import=error
untyped-import=warn
unclear-type=warn
unsafe-getters-setters=error
[version]
0.90.0

1
.gitignore vendored
View file

@ -4,6 +4,7 @@ logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.DS_Store
# Runtime data
pids

11
.prettierrc.json Normal file
View file

@ -0,0 +1,11 @@
{
"prettier.printWidth": 120,
"prettier.tabWidth": 2,
"prettier.singleQuote": true,
"prettier.trailingComma": "none",
"prettier.bracketSpacing": true,
"prettier.parser": "flow",
"prettier.semi": true,
"prettier.useTabs": false,
"prettier.jsxBracketSameLine": false
}

19
.travis.yml Normal file
View file

@ -0,0 +1,19 @@
language: node_js
node_js:
- 10
cache:
directories:
- ~/.npm
- ~/.cache
install:
- npm install
before_script:
- npm run build
- npm run start &
script:
- node --version
- npm --version
- npm run flow
- npm run cypress:run
notifications:
email: false

View file

@ -0,0 +1,9 @@
// @flow
import React from 'react';
import * as Styled from './style';
import type { ButtonProps } from './types';
export default function Button(props: ButtonProps) {
const { children } = props;
return <Styled.Button {...props}>{children}</Styled.Button>;
}

View file

@ -0,0 +1,45 @@
// @flow
// $FlowIssue
import React, { useState } from 'react';
import dynamic from 'next/dynamic';
import * as Styled from './style';
import Icon from '../Icon';
import type { ButtonProps } from './types';
const Clipboard = dynamic(() => import('react-clipboard.js'), {
ssr: false,
loading: () => null,
});
type CopyLinkProps = {
...$Exact<ButtonProps>,
text: string,
};
export default function CopyLinkButton(props: CopyLinkProps) {
const { text, children } = props;
const [isClicked, handleClick] = useState(false);
const onClick = () => {
handleClick(true);
setTimeout(() => handleClick(false), 2000);
};
return (
<Clipboard
style={{ background: 'none' }}
data-clipboard-text={text}
onSuccess={onClick}
component="a"
>
<Styled.CopyLinkButton
data-cy="copy-link-button"
isClicked={isClicked}
{...props}
>
<Icon glyph="link" size={24} />
{isClicked ? 'Copied!' : children}
</Styled.CopyLinkButton>
</Clipboard>
);
}

View file

@ -0,0 +1,15 @@
// @flow
import React from 'react';
import * as Styled from './style';
import Icon from '../Icon';
import type { ButtonProps } from './types';
export default function FacebookButton(props: ButtonProps) {
const { children } = props;
return (
<Styled.FacebookButton {...props}>
<Icon glyph="facebook" size={24} />
{children}
</Styled.FacebookButton>
);
}

View file

@ -0,0 +1,9 @@
// @flow
import React from 'react';
import * as Styled from './style';
import type { ButtonProps } from './types';
export default function GhostButton(props: ButtonProps) {
const { children } = props;
return <Styled.GhostButton {...props}>{children}</Styled.GhostButton>;
}

View file

@ -0,0 +1,9 @@
// @flow
import React from 'react';
import * as Styled from './style';
import type { ButtonProps } from './types';
export default function OutlineButton(props: ButtonProps) {
const { children } = props;
return <Styled.OutlineButton {...props}>{children}</Styled.OutlineButton>;
}

View file

@ -0,0 +1,9 @@
// @flow
import React from 'react';
import * as Styled from './style';
import type { ButtonProps } from './types';
export default function PrimaryButton(props: ButtonProps) {
const { children } = props;
return <Styled.PrimaryButton {...props}>{children}</Styled.PrimaryButton>;
}

View file

@ -0,0 +1,15 @@
// @flow
import React from 'react';
import * as Styled from './style';
import Icon from '../Icon';
import type { ButtonProps } from './types';
export default function TwitterButton(props: ButtonProps) {
const { children } = props;
return (
<Styled.TwitterButton {...props}>
<Icon glyph="twitter" size={24} />
{children}
</Styled.TwitterButton>
);
}

View file

@ -0,0 +1,22 @@
// @flow
import * as Styled from './style';
import Button from './Button';
import CopyLinkButton from './CopyLinkButton';
import FacebookButton from './FacebookButton';
import GhostButton from './GhostButton';
import OutlineButton from './OutlineButton';
import PrimaryButton from './PrimaryButton';
import TwitterButton from './TwitterButton';
const { ButtonRow } = Styled;
export {
Button,
CopyLinkButton,
FacebookButton,
GhostButton,
OutlineButton,
PrimaryButton,
TwitterButton,
ButtonRow,
};

363
components/Button/style.js Normal file
View file

@ -0,0 +1,363 @@
// @flow
import styled, { css } from 'styled-components';
import { hexa, tint } from '../globals';
import type { ButtonSize } from './types';
import { theme } from '../theme';
const getPadding = (size: ButtonSize) => {
switch (size) {
case 'small':
return '4px 8px';
case 'default':
return '10px 20px';
case 'large':
return '14px 28px';
default: {
return '10px 20px';
}
}
};
const getFontSize = (size: ButtonSize) => {
switch (size) {
case 'small':
return '14px';
case 'default':
return '16px';
case 'large':
return '18px';
default: {
return '16px';
}
}
};
const base = css`
-webkit-appearance: none;
display: flex;
flex: none;
align-self: center;
align-items: center;
justify-content: center;
border-radius: 4px;
font-size: ${props => getFontSize(props.size)};
font-weight: 500;
white-space: nowrap;
word-break: keep-all;
transition: all 0.2s ease-in-out;
cursor: pointer;
line-height: 1;
position: relative;
text-align: center;
padding: ${props => getPadding(props.size)};
opacity: ${props => (props.disabled ? '0.64' : '1')};
box-shadow: ${props =>
props.disabled ? 'none' : `0 1px 2px rgba(0,0,0,0.04)`};
&:disabled {
cursor: not-allowed;
}
&:hover {
transition: all 0.2s ease-in-out;
box-shadow: ${props =>
props.disabled ? 'none' : `${theme.shadows.button}`};
}
`;
export const Button = styled.button`
${base}
border: 1px solid ${theme.border.default};
color: ${theme.text.secondary};
background-color: ${theme.bg.default};
background-image: ${props =>
`linear-gradient(to bottom, ${props.theme.bg.default}, ${
props.theme.bg.wash
})`};
&:hover {
color: ${theme.text.default};
}
&:active {
border: 1px solid ${theme.border.active};
background-image: ${props =>
`linear-gradient(to top, ${props.theme.bg.default}, ${
props.theme.bg.wash
})`};
}
&:focus {
box-shadow: 0 0 0 1px ${props => props.theme.bg.default}, 0 0 0 3px ${
theme.border.default
};
}
`;
export const PrimaryButton = styled.button`
${base}
border: 1px solid ${theme.brand.default};
color: ${theme.bg.default};
background-color: ${theme.brand.alt};
background-image: ${props =>
`linear-gradient(to bottom, ${props.theme.brand.alt}, ${
props.theme.brand.default
})`};
text-shadow: 0 1px 1px rgba(0,0,0,0.08);
&:hover {
color: ${theme.text.reverse};
background-image: ${props =>
`linear-gradient(to bottom, ${tint(props.theme.brand.alt, 16)}, ${tint(
props.theme.brand.default,
16
)})`};
box-shadow: ${props => (props.disabled ? 'none' : theme.shadows.button)};
}
&:active {
border: 1px solid ${theme.brand.default};
background-image: ${props =>
`linear-gradient(to top, ${props.theme.brand.alt}, ${
props.theme.brand.default
})`};
}
&:focus {
box-shadow: 0 0 0 1px ${props =>
props.theme.bg.default}, 0 0 0 3px ${props =>
hexa(props.theme.brand.alt, 0.16)};
}
`;
export const GhostButton = styled.button`
${base} border: none;
color: ${theme.text.secondary};
box-shadow: none;
background-color: transparent;
background-image: none;
&:hover {
background: ${props => tint(props.theme.bg.wash, -3)};
color: ${theme.text.default};
box-shadow: none;
}
&:focus {
box-shadow: 0 0 0 1px ${theme.bg.default},
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.08)};
}
`;
export const OutlineButton = styled.button`
${base}
border: 1px solid ${theme.border.default};
color: ${theme.text.secondary};
background-color: transparent;
background-image: none;
&:hover {
color: ${theme.text.default};
border: 1px solid ${theme.border.active};
box-shadow: none;
}
&:active {
border: 1px solid ${theme.text.placeholder};
}
&:focus {
box-shadow: 0 0 0 1px ${props => props.theme.bg.default}, 0 0 0 3px ${
theme.border.default
};
}
`;
export const ButtonRow = styled.div`
display: flex;
align-items: center;
@media (max-width: 968px) {
flex-wrap: nowrap;
button {
margin-top: 8px;
}
}
`;
export const ButtonSegmentRow = styled.div`
display: flex;
align-items: center;
justify-content: center;
position: relative;
button {
z-index: 1;
}
button:active,
button:focus {
z-index: 2;
}
button:first-of-type:not(:last-of-type) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
button:last-of-type:not(:first-of-type) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
button:not(:last-of-type):not(:first-of-type) {
border-radius: 0;
position: relative;
margin: 0 -1px;
}
${PrimaryButton} {
&:focus {
box-shadow: 0 0 0 1px ${theme.bg.default},
0 0 0 3px ${props => hexa(props.theme.brand.alt, 0.16)};
}
}
`;
export const FacebookButton = styled.button`
${base}
border: 1px solid ${theme.social.facebook};
color: ${theme.bg.default};
background-color: ${theme.social.facebook};
background-image: ${props =>
`linear-gradient(to bottom, ${props.theme.social.facebook}, ${
props.theme.social.facebook
})`};
text-shadow: 0 1px 1px rgba(0,0,0,0.08);
.icon {
margin-right: 8px;
margin-left: -4px;
}
&:hover {
color: ${theme.text.reverse};
background-image: ${props =>
`linear-gradient(to bottom, ${tint(
props.theme.social.facebook,
16
)}, ${tint(props.theme.social.facebook, 16)})`};
box-shadow: ${props => (props.disabled ? 'none' : theme.shadows.button)};
}
&:active {
border: 1px solid ${theme.social.facebook};
background-image: ${props =>
`linear-gradient(to top, ${props.theme.social.facebook}, ${
props.theme.social.facebook
})`};
}
&:focus {
box-shadow: 0 0 0 1px ${props =>
props.theme.bg.default}, 0 0 0 3px ${props =>
hexa(props.theme.social.facebook, 0.16)};
}
`;
export const TwitterButton = styled.button`
${base}
border: 1px solid ${theme.social.twitter};
color: ${theme.bg.default};
background-color: ${theme.social.twitter};
background-image: ${props =>
`linear-gradient(to bottom, ${props.theme.social.twitter}, ${
props.theme.social.twitter
})`};
text-shadow: 0 1px 1px rgba(0,0,0,0.08);
.icon {
margin-right: 8px;
margin-left: -4px;
}
&:hover {
color: ${theme.text.reverse};
background-image: ${props =>
`linear-gradient(to bottom, ${tint(
props.theme.social.twitter,
4
)}, ${tint(props.theme.social.twitter, 4)})`};
box-shadow: ${props => (props.disabled ? 'none' : theme.shadows.button)};
}
&:active {
border: 1px solid ${theme.social.twitter};
background-image: ${props =>
`linear-gradient(to top, ${props.theme.social.twitter}, ${
props.theme.social.twitter
})`};
}
&:focus {
box-shadow: 0 0 0 1px ${props =>
props.theme.bg.default}, 0 0 0 3px ${props =>
hexa(props.theme.social.twitter, 0.16)};
}
`;
export const CopyLinkButton = styled.button`
${base}
border: 1px solid ${props =>
props.isClicked
? tint(props.theme.success.default, -10)
: props.theme.border.default};
color: ${props =>
props.isClicked ? props.theme.bg.default : props.theme.text.secondary};
background-color: ${props =>
props.isClicked ? props.theme.success.default : props.theme.bg.default};
background-image: ${props =>
`linear-gradient(to bottom, ${
props.isClicked ? props.theme.success.default : props.theme.bg.default
}, ${
props.isClicked
? tint(props.theme.success.default, -4)
: props.theme.bg.wash
})`};
transition: border 0.2s ease-in-out, background-color 0.2s ease-in-out, background-image 0.2s ease-in-out;
&:hover {
transition: border 0.2s ease-in-out, background-color 0.2s ease-in-out, background-image 0.2s ease-in-out;
color: ${props =>
props.isClicked ? props.theme.bg.default : props.theme.text.default};
}
&:active {
border: 1px solid ${props =>
props.isClicked
? tint(props.theme.success.default, -10)
: props.theme.border.active};
background-image: ${props =>
`linear-gradient(to bottom, ${
props.isClicked
? tint(props.theme.success.default, -4)
: props.theme.bg.default
}, ${
props.isClicked ? props.theme.success.default : props.theme.bg.wash
})`};
}
.icon {
margin-right: 8px;
margin-left: -4px;
}
&:focus {
box-shadow: 0 0 0 1px ${props =>
props.theme.bg.default}, 0 0 0 3px ${props =>
props.isClicked
? hexa(props.theme.success.default, 0.16)
: props.theme.border.default};
}
`;

View file

@ -0,0 +1,9 @@
// @flow
import type { Node } from 'react';
export type ButtonSize = 'small' | 'large' | 'default';
export type ButtonProps = {
size?: ButtonSize,
disabled?: boolean,
children: Node | string,
};

13
components/Card/index.js Normal file
View file

@ -0,0 +1,13 @@
// @flow
import * as React from 'react';
import { StyledCard } from './style';
type Props = {
children: React.Node,
style?: Object,
};
export default function Card(props: Props) {
const { style, children } = props;
return <StyledCard style={style}>{children}</StyledCard>;
}

18
components/Card/style.js Normal file
View file

@ -0,0 +1,18 @@
// @flow
import styled from 'styled-components';
import { Shadows } from '../globals';
export const StyledCard = styled.div`
position: relative;
background: ${props => props.theme.bg.default};
border-radius: 6px;
${Shadows.default};
&:hover {
${Shadows.hover};
}
&:active {
${Shadows.active};
}
`;

View file

@ -0,0 +1,32 @@
// @flow
import React from 'react';
import { Container, Description, Icons } from './style';
import Icon from '../Icon';
export default function Footer() {
return (
<Container data-cy="footer">
<Icons>
<a
href="https://github.com/brianlovin/security-checklist"
target="_blank"
rel="noopener noreferrer"
>
<Icon glyph="github" />
</a>
</Icons>
<Description>
Copyright whenever. This is
<a
href="https://github.com/brianlovin/security-checklist"
target="_blank"
rel="noopener noreferrer"
>
open source
</a>
.
</Description>
</Container>
);
}

View file

@ -0,0 +1,44 @@
// @flow
import styled from 'styled-components';
import { theme } from '../theme';
export const Container = styled.div`
margin-top: 128px;
padding: 0 16px;
width: 100%;
`;
export const Description = styled.p`
font-size: 14px;
color: ${theme.text.tertiary};
max-width: 320px;
display: flex;
flex: 1 0 auto;
align-items: flex-start;
padding-bottom: 16px;
a {
color: ${theme.text.default};
margin-left: 4px;
}
`;
export const Icons = styled.div`
display: flex;
flex: 1 0 auto;
align-items: flex-start;
margin-left: -16px;
padding-bottom: 8px;
a {
color: ${theme.text.tertiary};
}
a:hover {
color: ${theme.text.default};
}
.icon {
margin-left: 16px;
}
`;

View file

@ -0,0 +1,39 @@
// @flow
import * as React from 'react';
import Link from 'next/link';
import { Container, Logo, ButtonRowContainer } from './style';
import { PrimaryButton, GhostButton } from '../Button';
type Props = {
showHeaderShadow: boolean,
};
export default function Header(props: Props) {
const { showHeaderShadow } = props;
return (
<Container showHeaderShadow={showHeaderShadow} data-cy="header">
<Link href="/">
<a style={{ display: 'flex', alignItems: 'center' }}>
<Logo>Security Checklist</Logo>
</a>
</Link>
<ButtonRowContainer>
<Link href="/about">
<a>
<GhostButton>About</GhostButton>
</a>
</Link>
<a
href="https://github.com/brianlovin/security-checklist"
target="_blank"
rel="noopener noreferrer"
>
<PrimaryButton>Contribute</PrimaryButton>
</a>
</ButtonRowContainer>
</Container>
);
}

View file

@ -0,0 +1,43 @@
// @flow
import styled from 'styled-components';
import { theme } from '../theme';
export const Container = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-areas: 'logo actions';
padding: 16px;
position: fixed;
top: 0;
left: 0;
right: 0;
background: ${props =>
props.showHeaderShadow ? props.theme.bg.default : props.theme.bg.wash};
z-index: 3;
box-shadow: ${props =>
props.showHeaderShadow ? '0 4px 8px rgba(0,0,0,0.04)' : 'none'};
transition: all 0.2s ease-in-out;
@media (max-width: 968px) {
padding: 8px 16px;
grid-template-columns: 1fr 1fr;
grid-template-areas: 'logo actions';
}
`;
export const Logo = styled.h1`
grid-area: logo;
font-size: 18px;
font-weight: 700;
color: ${theme.text.default};
`;
export const ButtonRowContainer = styled.div`
display: flex;
justify-content: flex-end;
grid-area: actions;
align-items: center;
@media (max-width: 968px) {
}
`;

101
components/Icon/index.js Normal file
View file

@ -0,0 +1,101 @@
// @flow
import * as React from 'react';
import styled from 'styled-components';
type Props = {
glyph: string,
size?: number,
};
export const InlineSvg = styled.svg`
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 100%;
width: 100%;
color: inherit;
fill: currentColor;
`;
export const SvgWrapper = styled.div`
display: inline-block;
flex: 0 0 ${props => (props.size ? `${props.size}px` : '32px')};
width: ${props => (props.size ? `${props.size}px` : '32px')};
height: ${props => (props.size ? `${props.size}px` : '32px')};
min-width: ${props => (props.size ? `${props.size}px` : '32px')};
min-height: ${props => (props.size ? `${props.size}px` : '32px')};
position: relative;
color: inherit;
`;
type GlyphProps = {
glyph: string,
};
export const Glyph = ({ glyph }: GlyphProps): any => {
switch (glyph) {
case 'facebook':
return (
<g>
<path d="M19.491,27.944c7.731,-0.319 8.509,-2.242 8.509,-11.944c0,-11 -1,-12 -12,-12c-11,0 -12,1 -12,12c0,10.985 0.997,11.997 11.956,12l0,-7.667l-2.956,0l0,-3.377l2.956,0l0,-2.491c0,-2.891 1.789,-4.465 4.403,-4.465c1.251,0 2.327,0.092 2.641,0.133l0,3.021l-1.813,0.001c-1.421,0 -1.696,0.666 -1.696,1.644l0,2.157l3.39,0l-0.442,3.377l-2.948,0l0,7.611Z" />
</g>
);
case 'link':
return (
<g>
<path d="M16.693,16.664c0.376,-0.375 1.001,-0.413 1.377,-0.038l0.083,0.084c0.358,0.357 0.386,0.93 0.032,1.291c-0.026,0.026 -0.051,0.052 -0.077,0.078c-0.867,0.866 -1.671,1.438 -2.514,1.655c0,0 -0.001,0 -0.001,0c-0.078,0.02 -0.157,0.037 -0.236,0.051c0,0 0,0 0,0c-0.802,0.142 -1.646,-0.036 -2.616,-0.582l0,0c-0.907,-0.511 -1.923,-1.343 -3.119,-2.539c-3.959,-3.959 -3.939,-5.959 -1.414,-8.485c2.526,-2.525 4.526,-2.545 8.485,1.414c0.439,0.439 0.828,0.853 1.171,1.247c0.102,0.117 -0.009,0.3 -0.162,0.28c0,0 0,0 -0.001,0c-0.559,-0.074 -1.083,-0.035 -1.58,0.094c-0.299,0.078 -0.624,0.012 -0.842,-0.206c-1.958,-1.958 -3.035,-2.492 -3.63,-2.571c-0.366,-0.049 -0.902,0.032 -2.027,1.156c-1.124,1.125 -1.205,1.661 -1.156,2.027c0.079,0.595 0.613,1.672 2.571,3.63c0.432,0.433 0.822,0.796 1.173,1.1c0,0 0,0 0,0c0.046,0.04 0.091,0.079 0.136,0.117c0,0 0,0 0,0c0.841,0.712 1.45,1.073 1.891,1.24c0,0 0,0 0,0c0.166,0.062 0.308,0.098 0.429,0.114c0,0 0,0 0,0c0.367,0.049 0.903,-0.032 2.027,-1.157Zm3.07,-1.099c-0.912,-0.79 -1.563,-1.181 -2.027,-1.357c0,0 0,0 0,0c-0.166,-0.063 -0.308,-0.098 -0.43,-0.114c0,0 0,0 0,0c-0.367,-0.049 -0.902,0.032 -2.027,1.156c-0.375,0.376 -1.001,0.414 -1.376,0.038l-0.083,-0.083c-0.358,-0.358 -0.387,-0.931 -0.032,-1.291c0.025,-0.026 0.051,-0.052 0.077,-0.078c0.866,-0.866 1.671,-1.438 2.514,-1.655l0,0c0.873,-0.225 1.786,-0.07 2.853,0.531c0,0 0,0 0,0c0.906,0.51 1.923,1.343 3.118,2.538c3.96,3.96 3.94,5.96 1.414,8.486c-2.525,2.525 -4.525,2.545 -8.485,-1.415c-0.438,-0.438 -0.828,-0.852 -1.171,-1.246c-0.102,-0.117 0.009,-0.301 0.163,-0.28c0.559,0.074 1.083,0.035 1.581,-0.094c0.299,-0.078 0.623,-0.012 0.841,0.206c1.958,1.958 3.035,2.492 3.63,2.571c0.367,0.049 0.903,-0.032 2.027,-1.157c1.125,-1.124 1.206,-1.66 1.157,-2.027c-0.079,-0.595 -0.613,-1.672 -2.571,-3.63c-0.433,-0.432 -0.822,-0.795 -1.173,-1.099Z" />
</g>
);
case 'share':
return (
<g fillRule="nonzero">
<path d="M16.707,5.294c-0.39,-0.39 -1.024,-0.39 -1.414,0l-3,3c-0.391,0.391 -0.391,1.024 0,1.415c0.39,0.39 1.024,0.39 1.414,0l1.293,-1.293l0,9.585c0,0.553 0.448,1 1,1c0.552,0 1,-0.447 1,-1l0,-9.585l1.293,1.293c0.39,0.39 1.024,0.39 1.414,0c0.391,-0.391 0.391,-1.024 0,-1.415l-3,-3Zm-5.817,7.023c0.588,-0.114 1.11,0.36 1.11,0.959l0,0.426c0,0.265 -0.198,0.487 -0.459,0.531l-0.002,0c-1.042,0.17 -1.486,0.416 -1.706,0.612c-0.191,0.171 -0.42,0.489 -0.588,1.31l-0.007,0.03c-0.191,0.926 -0.238,2.106 -0.238,3.815l0,0.003c0,1.709 0.047,2.889 0.238,3.814l0.007,0.031c0.168,0.821 0.397,1.139 0.588,1.309c0.219,0.197 0.662,0.442 1.699,0.612l0.017,0.002c1.094,0.182 2.493,0.231 4.45,0.23l0.002,0c1.957,0.001 3.356,-0.048 4.45,-0.23l0.017,-0.002c1.037,-0.17 1.48,-0.415 1.699,-0.611c0.191,-0.171 0.42,-0.489 0.588,-1.31l0.007,-0.031c0.191,-0.925 0.238,-2.105 0.238,-3.814l0,-0.003c0,-1.709 -0.047,-2.889 -0.238,-3.815l-0.007,-0.03c-0.168,-0.821 -0.397,-1.139 -0.588,-1.31c-0.22,-0.196 -0.664,-0.442 -1.706,-0.612l-0.002,0c-0.262,-0.044 -0.459,-0.266 -0.459,-0.531l0,-0.426c0,-0.599 0.522,-1.073 1.11,-0.959c3.362,0.655 3.89,2.553 3.89,7.684c0,7.059 -1,8 -9,8c-8,0 -9,-0.941 -9,-8c0,-5.131 0.528,-7.029 3.89,-7.684Z" />
</g>
);
case 'twitter':
return (
<g>
<path d="M16,28c11,0 12,-1 12,-12c0,-11 -1,-12 -12,-12c-11,0 -12,1 -12,12c0,11 1,12 12,12Zm5.825,-13.901c0,3.669 -2.889,7.901 -8.172,7.901l0,0c-1.622,0 -3.132,-0.46 -4.403,-1.248c0.225,0.026 0.454,0.039 0.685,0.039c1.346,0 2.585,-0.444 3.568,-1.189c-1.258,-0.022 -2.318,-0.825 -2.684,-1.928c0.175,0.032 0.355,0.05 0.54,0.05c0.262,0 0.516,-0.034 0.758,-0.098c-1.315,-0.255 -2.305,-1.377 -2.305,-2.722c0,-0.013 0,-0.024 0.001,-0.036c0.387,0.208 0.829,0.333 1.301,0.348c-0.772,-0.498 -1.279,-1.348 -1.279,-2.312c0,-0.509 0.143,-0.985 0.389,-1.396c1.417,1.681 3.534,2.786 5.921,2.902c-0.049,-0.204 -0.074,-0.416 -0.074,-0.633c0,-1.533 1.286,-2.777 2.872,-2.777c0.826,0 1.573,0.338 2.097,0.877c0.654,-0.124 1.269,-0.356 1.824,-0.674c-0.215,0.649 -0.67,1.192 -1.263,1.536c0.581,-0.067 1.134,-0.216 1.649,-0.437c-0.384,0.557 -0.872,1.046 -1.433,1.438c0.006,0.119 0.008,0.239 0.008,0.359Z" />
</g>
);
case 'view-forward':
return (
<g>
<path d="M12.982,23.89c-0.354,-0.424 -0.296,-1.055 0.128,-1.408c1.645,-1.377 5.465,-4.762 6.774,-6.482c-1.331,-1.749 -5.1,-5.085 -6.774,-6.482c-0.424,-0.353 -0.482,-0.984 -0.128,-1.408c0.353,-0.425 0.984,-0.482 1.409,-0.128c1.839,1.532 5.799,4.993 7.2,6.964c0.219,0.312 0.409,0.664 0.409,1.054c0,0.39 -0.19,0.742 -0.409,1.053c-1.373,1.932 -5.399,5.462 -7.2,6.964l-0.001,0.001c-0.424,0.354 -1.055,0.296 -1.408,-0.128Z" />
</g>
);
case 'github':
return (
<g>
<path d="M18.837,27.966c8.342,-0.241 9.163,-1.997 9.163,-11.966c0,-11 -1,-12 -12,-12c-11,0 -12,1 -12,12c0,9.995 0.826,11.734 9.228,11.968c0.073,-0.091 0.1,-0.205 0.1,-0.321c0,-0.25 -0.01,-2.816 -0.015,-3.699c-3.037,0.639 -3.678,-1.419 -3.678,-1.419c-0.497,-1.222 -1.213,-1.548 -1.213,-1.548c-0.991,-0.656 0.075,-0.643 0.075,-0.643c1.096,0.075 1.673,1.091 1.673,1.091c0.974,1.617 2.556,1.15 3.178,0.879c0.099,-0.683 0.381,-1.15 0.693,-1.414c-2.425,-0.267 -4.974,-1.175 -4.974,-5.23c0,-1.155 0.426,-2.099 1.124,-2.839c-0.113,-0.268 -0.487,-1.344 0.107,-2.8c0,0 0.917,-0.285 3.003,1.084c0.871,-0.235 1.805,-0.352 2.734,-0.356c0.927,0.004 1.861,0.121 2.734,0.356c2.085,-1.369 3,-1.084 3,-1.084c0.596,1.456 0.221,2.532 0.108,2.8c0.7,0.74 1.123,1.684 1.123,2.839c0,4.065 -2.553,4.96 -4.986,5.221c0.392,0.327 0.741,0.973 0.741,1.96c0,0.946 -0.006,2.619 -0.01,3.728c-0.002,0.549 -0.003,0.959 -0.003,1.074c0,0.109 0.029,0.224 0.095,0.319Z" />
</g>
);
default:
return null;
}
};
export default function Icon(props: Props) {
const { size = 32, glyph } = props;
return (
<SvgWrapper size={size} className="icon">
<InlineSvg
fillRule="evenodd"
clipRule="evenodd"
strokeLinejoin="round"
strokeMiterlimit="1.414"
xmlns="http://www.w3.org/2000/svg"
aria-label={glyph}
viewBox="0 0 32 32"
preserveAspectRatio="xMidYMid meet"
fit
>
<title>{glyph}</title>
<Glyph glyph={glyph} />
</InlineSvg>
</SvgWrapper>
);
}

85
components/Page/index.js Normal file
View file

@ -0,0 +1,85 @@
// @flow
// $FlowIssue
import React, { useState, useEffect } from 'react';
import type { Node } from 'react';
import { ThemeProvider } from 'styled-components';
import { throttle } from 'throttle-debounce';
import Icon from '../Icon';
import Header from '../Header';
import Footer from '../Footer';
import { theme } from '../theme';
import {
Container,
SectionHeading,
Heading,
Subheading,
LargeHeading,
LargeSubheading,
InnerContainer,
ScrollToTop,
} from './style';
import * as gtag from '../../lib/gtag';
export { SectionHeading, Heading, Subheading, LargeHeading, LargeSubheading };
type Props = {
children: Node,
};
export default function Page(props: Props) {
const { children } = props;
const [lastTrackedPageview, setLastTrackedPageview] = useState(null);
const [showHeaderShadow, setHeaderShadow] = useState(false);
const [scrollToTopVisible, setScrollToTopVisible] = useState(false);
function handleScroll() {
const headerShadowState = window && window.pageYOffset > 0;
const scrollToTopState = window && window.pageYOffset > 240;
setHeaderShadow(headerShadowState);
setScrollToTopVisible(scrollToTopState);
}
const throttledScroll = throttle(300, handleScroll);
const scrollToTop = () => {
if (window) {
window.scrollTo(0, 0);
}
};
useEffect(() => {
if (window) {
window.addEventListener('scroll', throttledScroll);
}
return () => {
if (window) {
window.removeEventListener('scroll', throttledScroll);
setLastTrackedPageview(null);
}
};
}, []);
useEffect(() => {
if (document) {
const newLocation = document.location.pathname;
if (newLocation !== lastTrackedPageview) {
gtag.pageview(document.location.pathname);
setLastTrackedPageview(newLocation);
}
}
});
return (
<ThemeProvider theme={theme}>
<Container>
<Header showHeaderShadow={showHeaderShadow} />
<InnerContainer>{children}</InnerContainer>
<Footer />
<ScrollToTop isVisible={scrollToTopVisible} onClick={scrollToTop}>
<Icon glyph="view-forward" size={32} />
</ScrollToTop>
</Container>
</ThemeProvider>
);
}

126
components/Page/style.js Normal file
View file

@ -0,0 +1,126 @@
// @flow
import styled from 'styled-components';
import { tint } from '../globals';
import { theme } from '../theme';
export const Container = styled.div`
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
height: 100%;
max-width: 100%;
`;
export const InnerContainer = styled.div`
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
flex: 1 0 auto;
padding-top: 64px;
padding-left: 32px;
padding-right: 32px;
position: relative;
width: 100%;
max-width: 768px;
@media (max-width: 752px) {
align-items: flex-start;
max-width: 100%;
padding-left: 16px;
padding-right: 16px;
padding-top: 48px;
}
`;
export const SectionHeading = styled.div`
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
margin: 72px 0 0;
@media (max-width: 968px) {
align-items: flex-start;
max-width: 100%;
}
`;
export const Heading = styled.h3`
font-size: 24px;
font-weight: 700;
color: ${theme.text.default};
@media (max-width: 968px) {
max-width: 100%;
}
`;
export const Subheading = styled.h4`
font-size: 18px;
font-weight: 400;
color: ${theme.text.tertiary};
a {
color: ${theme.text.default};
font-weight: 500;
}
@media (max-width: 968px) {
max-width: 100%;
}
`;
export const LargeHeading = styled(Heading)`
font-size: 32px;
`;
export const LargeSubheading = styled(Subheading)`
font-size: 20px;
`;
export const ScrollToTop = styled.button`
width: 48px;
height: 48px;
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
bottom: 16px;
right: 16px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
transition: all 0.2s ease-in-out;
opacity: ${props => (props.isVisible ? '1' : '0')};
background: ${theme.text.default};
color: ${theme.bg.default};
transform: translateY(${props => (props.isVisible ? '0' : '80px')});
cursor: pointer;
z-index: 9999;
&:hover {
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
transform: translateY(-3px);
transition: all 0.2s ease-in-out;
}
&:active {
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.09);
transform: translateY(-2px);
transition: all 0.2s ease-in-out;
}
.icon {
transform: rotate(270deg);
}
@media (max-width: 968px) {
bottom: 16px;
right: 16px;
}
@media (max-width: 556px) {
display: none;
}
`;

View file

@ -0,0 +1,28 @@
// @flow
import * as React from 'react';
import { FacebookButton, TwitterButton, CopyLinkButton } from '../Button';
import { Container } from './style';
export default function ShareButtons() {
return (
<Container>
<a
href="https://www.facebook.com/sharer/sharer.php?u=https://securitycheckli.st"
target="_blank"
rel="noopener noreferrer"
>
<FacebookButton>Share</FacebookButton>
</a>
<a
href="https://twitter.com/share?text=Security Checklist: A checklist for staying safe on the internet"
target="_blank"
rel="noopener noreferrer"
>
<TwitterButton>Tweet</TwitterButton>
</a>
<CopyLinkButton text="https://securitycheckli.st">Copy</CopyLinkButton>
</Container>
);
}

View file

@ -0,0 +1,22 @@
// @flow
import styled from 'styled-components';
export const Container = styled.div`
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 16px;
button {
width: 100%;
}
@media (max-width: 440px) {
grid-template-columns: 1fr;
grid-gap: 0;
button {
margin-top: 16px;
width: 100%;
}
}
`;

164
components/globals/index.js Normal file
View file

@ -0,0 +1,164 @@
// @flow
import { css } from 'styled-components';
import { theme } from '../theme';
export const hexa = (hex: string, alpha: number) => {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
if (alpha >= 0) {
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
return `rgb(${r}, ${g}, ${b})`;
};
export const tint = (hex: string, amount: number) => {
let R = parseInt(hex.substring(1, 3), 16);
let G = parseInt(hex.substring(3, 5), 16);
let B = parseInt(hex.substring(5, 7), 16);
const getSingle = (number: number) =>
parseInt((number * (100 + amount)) / 100, 10);
R = getSingle(R);
G = getSingle(G);
B = getSingle(B);
R = R < 255 ? R : 255;
G = G < 255 ? G : 255;
B = B < 255 ? B : 255;
const getDouble = (number: number) =>
number.toString(16).length === 1
? `0${number.toString(16)}`
: number.toString(16);
const RR = getDouble(R);
const GG = getDouble(G);
const BB = getDouble(B);
return `#${RR}${GG}${BB}`;
};
export const Shadows = {
default: css`
box-shadow: ${theme.shadows.default};
transition: ${theme.animations.default};
`,
hover: css`
box-shadow: ${theme.shadows.hover};
transition: ${theme.animations.hover};
`,
active: css`
box-shadow: ${theme.shadows.active};
transition: ${theme.animations.active};
`,
};
export const Content = css`
h1 {
font-size: 40px;
font-weight: 700;
color: ${props => props.theme.text.default};
margin-top: 28px;
}
h2 {
font-size: 32px;
font-weight: 700;
color: ${props => props.theme.text.default};
margin-top: 26px;
}
h3 {
font-size: 24px;
font-weight: 600;
color: ${props => props.theme.text.default};
margin-top: 24px;
}
h4 {
font-size: 20px;
font-weight: 600;
color: ${props => props.theme.text.default};
margin-top: 16px;
}
h5 {
font-size: 18px;
font-weight: 600;
color: ${props => props.theme.text.default};
margin-top: 16px;
}
h6 {
font-size: 16px;
font-weight: 500;
color: ${props => props.theme.text.default};
margin-top: 16px;
text-transform: uppercase;
}
p {
font-size: 18px;
font-weight: 400;
line-height: 1.6;
color: ${props => props.theme.text.secondary};
margin-top: 16px;
}
a {
color: ${props => props.theme.brand.default};
font-weight: 500;
}
a:hover {
text-decoration: none;
color: ${props => tint(props.theme.brand.default, -40)};
}
a:hover button {
text-decoration: none !important;
}
ul,
ol {
margin-left: 24px;
margin-top: 12px;
margin-bottom: 16px;
font-size: 18px;
font-weight: 400;
line-height: 1.5;
color: ${props => props.theme.text.secondary};
margin-top: 16px;
}
li {
line-height: 1.6;
padding: 4px 0;
}
strong {
font-weight: 600;
}
`;
export const Truncate = (width: number) => css`
width: ${width}px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
export const shuffleArray = (array: Array<any>) => {
for (let i = array.length - 1; i > 0; i -= 1) {
const j = Math.floor(Math.random() * (i + 1));
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
};

45
components/theme/index.js Normal file
View file

@ -0,0 +1,45 @@
export const theme = {
bg: {
wash: '#F6F7F8',
default: '#FFF',
},
border: {
default: '#D6DCE7',
active: '#C9CED8',
},
text: {
default: '#000',
secondary: '#212325',
tertiary: '#5C6166',
placeholder: '#91989F',
},
brand: {
default: '#067AE4',
alt: '#0684F8',
},
social: {
facebook: '#3B5998',
twitter: '#00ACED',
},
success: {
default: '#21BE7C',
},
warn: {
default: '#B00A0A',
},
spectrum: {
default: '#4400CC',
alt: '#7B16FF',
},
shadows: {
default: '0 1px 2px rgba(0,0,0,0.08)',
hover: '0 12px 32px rgba(0,0,0,0.10)',
active: '0 6px 20px rgba(0,0,0,0.09)',
button: '0 4px 12px rgba(0,0,0,0.08)',
},
animations: {
default: '0.15s ease-out',
hover: '0.15s ease-in',
active: '0.15s ease-in-out',
},
};

27
config/next-seo.js Normal file
View file

@ -0,0 +1,27 @@
export default {
title: 'Security Checklist',
description: 'A checklist for staying safe on the internet',
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://securitycheckli.st/',
title: 'Security Checklist',
description: 'A checklist for staying safe on the internet',
defaultImageWidth: 470,
defaultImageHeight: 470,
images: [
{
url: 'https://securitycheckli.st/static/og-image.jpg',
width: 470,
height: 470,
alt: 'Brian Lovin',
},
],
site_name: 'Brian Lovin',
},
twitter: {
handle: '@brian_lovin',
site: '@brian_lovin',
cardType: 'summary_large_image',
},
};

9
cypress.json Normal file
View file

@ -0,0 +1,9 @@
{
"baseUrl": "http://localhost:3000",
"viewportWidth": 1300,
"defaultCommandTimeout": 20000,
"video": false,
"blacklistHosts": [
"*.google-analytics.com"
]
}

View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1,9 @@
describe('About', () => {
before(() => {
cy.visit('/about');
});
it('should render about', () => {
cy.contains('About');
});
});

View file

@ -0,0 +1,26 @@
describe('Home', () => {
before(() => {
cy.visit('/');
});
it('should render footer', () => {
cy.get('[data-cy="footer"]')
.scrollIntoView()
.should('be.visible');
cy.get(`[href="https://github.com/brianlovin/security-checklist"]`).should(
'be.visible'
);
});
it('should render header', () => {
cy.get('[data-cy="header"]')
.scrollIntoView()
.should('be.visible');
cy.get(`[href="/about"]`).should('be.visible');
cy.get(`[href="https://github.com/brianlovin/security-checklist"]`).should(
'be.visible'
);
});
});

7
cypress/plugins/index.js Normal file
View file

@ -0,0 +1,7 @@
const browserify = require('@cypress/browserify-preprocessor');
module.exports = (on, config) => {
const options = browserify.defaultOptions;
options.browserifyOptions.transform[1][1].presets.push('@babel/preset-flow');
on('file:preprocessor', browserify(options));
};

View file

1
cypress/support/index.js Normal file
View file

@ -0,0 +1 @@
import './commands';

207
flow-typed/npm/@sentry/browser_vx.x.x.js vendored Normal file
View file

@ -0,0 +1,207 @@
// flow-typed signature: 7d693fcd258473de86327595c9369eaa
// flow-typed version: <<STUB>>/@sentry/browser_v4.5.0/flow_v0.90.0
/**
* This is an autogenerated libdef stub for:
*
* '@sentry/browser'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module '@sentry/browser' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module '@sentry/browser/build/bundle' {
declare module.exports: any;
}
declare module '@sentry/browser/build/bundle.min' {
declare module.exports: any;
}
declare module '@sentry/browser/dist/index' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/backend' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/client' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/index' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/breadcrumbs' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/globalhandlers' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/helpers' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/index' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/linkederrors' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/pluggable/ember' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/pluggable/reportingobserver' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/pluggable/vue' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/trycatch' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/integrations/useragent' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/md5' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/parsers' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/sdk' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/tracekit' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/transports/base' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/transports/beacon' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/transports/fetch' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/transports/index' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/transports/xhr' {
declare module.exports: any;
}
declare module '@sentry/browser/esm/version' {
declare module.exports: any;
}
// Filename aliases
declare module '@sentry/browser/build/bundle.js' {
declare module.exports: $Exports<'@sentry/browser/build/bundle'>;
}
declare module '@sentry/browser/build/bundle.min.js' {
declare module.exports: $Exports<'@sentry/browser/build/bundle.min'>;
}
declare module '@sentry/browser/dist/index.js' {
declare module.exports: $Exports<'@sentry/browser/dist/index'>;
}
declare module '@sentry/browser/esm/backend.js' {
declare module.exports: $Exports<'@sentry/browser/esm/backend'>;
}
declare module '@sentry/browser/esm/client.js' {
declare module.exports: $Exports<'@sentry/browser/esm/client'>;
}
declare module '@sentry/browser/esm/index.js' {
declare module.exports: $Exports<'@sentry/browser/esm/index'>;
}
declare module '@sentry/browser/esm/integrations/breadcrumbs.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/breadcrumbs'>;
}
declare module '@sentry/browser/esm/integrations/globalhandlers.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/globalhandlers'>;
}
declare module '@sentry/browser/esm/integrations/helpers.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/helpers'>;
}
declare module '@sentry/browser/esm/integrations/index.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/index'>;
}
declare module '@sentry/browser/esm/integrations/linkederrors.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/linkederrors'>;
}
declare module '@sentry/browser/esm/integrations/pluggable/ember.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/pluggable/ember'>;
}
declare module '@sentry/browser/esm/integrations/pluggable/reportingobserver.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/pluggable/reportingobserver'>;
}
declare module '@sentry/browser/esm/integrations/pluggable/vue.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/pluggable/vue'>;
}
declare module '@sentry/browser/esm/integrations/trycatch.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/trycatch'>;
}
declare module '@sentry/browser/esm/integrations/useragent.js' {
declare module.exports: $Exports<'@sentry/browser/esm/integrations/useragent'>;
}
declare module '@sentry/browser/esm/md5.js' {
declare module.exports: $Exports<'@sentry/browser/esm/md5'>;
}
declare module '@sentry/browser/esm/parsers.js' {
declare module.exports: $Exports<'@sentry/browser/esm/parsers'>;
}
declare module '@sentry/browser/esm/sdk.js' {
declare module.exports: $Exports<'@sentry/browser/esm/sdk'>;
}
declare module '@sentry/browser/esm/tracekit.js' {
declare module.exports: $Exports<'@sentry/browser/esm/tracekit'>;
}
declare module '@sentry/browser/esm/transports/base.js' {
declare module.exports: $Exports<'@sentry/browser/esm/transports/base'>;
}
declare module '@sentry/browser/esm/transports/beacon.js' {
declare module.exports: $Exports<'@sentry/browser/esm/transports/beacon'>;
}
declare module '@sentry/browser/esm/transports/fetch.js' {
declare module.exports: $Exports<'@sentry/browser/esm/transports/fetch'>;
}
declare module '@sentry/browser/esm/transports/index.js' {
declare module.exports: $Exports<'@sentry/browser/esm/transports/index'>;
}
declare module '@sentry/browser/esm/transports/xhr.js' {
declare module.exports: $Exports<'@sentry/browser/esm/transports/xhr'>;
}
declare module '@sentry/browser/esm/version.js' {
declare module.exports: $Exports<'@sentry/browser/esm/version'>;
}

109
flow-typed/npm/next-seo_vx.x.x.js vendored Normal file
View file

@ -0,0 +1,109 @@
// flow-typed signature: 3434dafbe8393bee0a8c757095611d92
// flow-typed version: <<STUB>>/next-seo_v1.8.0/flow_v0.90.0
/**
* This is an autogenerated libdef stub for:
*
* 'next-seo'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'next-seo' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'next-seo/dist/index' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/article' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/blog' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/breadcrumb' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/course' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/localBusiness' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/logo' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/product' {
declare module.exports: any;
}
declare module 'next-seo/dist/jsonld/socialProfile' {
declare module.exports: any;
}
declare module 'next-seo/dist/meta/buildTags' {
declare module.exports: any;
}
declare module 'next-seo/dist/meta/defaultSEO' {
declare module.exports: any;
}
declare module 'next-seo/dist/utils/markup' {
declare module.exports: any;
}
// Filename aliases
declare module 'next-seo/dist/index.js' {
declare module.exports: $Exports<'next-seo/dist/index'>;
}
declare module 'next-seo/dist/jsonld/article.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/article'>;
}
declare module 'next-seo/dist/jsonld/blog.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/blog'>;
}
declare module 'next-seo/dist/jsonld/breadcrumb.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/breadcrumb'>;
}
declare module 'next-seo/dist/jsonld/course.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/course'>;
}
declare module 'next-seo/dist/jsonld/localBusiness.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/localBusiness'>;
}
declare module 'next-seo/dist/jsonld/logo.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/logo'>;
}
declare module 'next-seo/dist/jsonld/product.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/product'>;
}
declare module 'next-seo/dist/jsonld/socialProfile.js' {
declare module.exports: $Exports<'next-seo/dist/jsonld/socialProfile'>;
}
declare module 'next-seo/dist/meta/buildTags.js' {
declare module.exports: $Exports<'next-seo/dist/meta/buildTags'>;
}
declare module 'next-seo/dist/meta/defaultSEO.js' {
declare module.exports: $Exports<'next-seo/dist/meta/defaultSEO'>;
}
declare module 'next-seo/dist/utils/markup.js' {
declare module.exports: $Exports<'next-seo/dist/utils/markup'>;
}

599
flow-typed/npm/next_vx.x.x.js vendored Normal file
View file

@ -0,0 +1,599 @@
// flow-typed signature: e2b9b2f7381f1b2d8bafc4108f71fda7
// flow-typed version: <<STUB>>/next_v7.0.2/flow_v0.90.0
/**
* This is an autogenerated libdef stub for:
*
* 'next'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'next' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'next/app' {
declare module.exports: any;
}
declare module 'next/asset' {
declare module.exports: any;
}
declare module 'next/babel' {
declare module.exports: any;
}
declare module 'next/client' {
declare module.exports: any;
}
declare module 'next/config' {
declare module.exports: any;
}
declare module 'next/constants' {
declare module.exports: any;
}
declare module 'next/dist/build/babel/plugins/react-loadable-plugin' {
declare module.exports: any;
}
declare module 'next/dist/build/babel/preset' {
declare module.exports: any;
}
declare module 'next/dist/build/index' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/loaders/emit-file-loader' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/loaders/hot-self-accept-loader' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/loaders/next-babel-loader' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/build-manifest-plugin' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/chunk-names-plugin' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/nextjs-require-cache-hot-reloader' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/nextjs-ssr-import' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/nextjs-ssr-module-cache' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/pages-manifest-plugin' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/pages-plugin' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/react-loadable-plugin' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/plugins/unlink-file-plugin' {
declare module.exports: any;
}
declare module 'next/dist/build/webpack/utils' {
declare module.exports: any;
}
declare module 'next/dist/client/dev-error-overlay/eventsource' {
declare module.exports: any;
}
declare module 'next/dist/client/dev-error-overlay/format-webpack-messages' {
declare module.exports: any;
}
declare module 'next/dist/client/dev-error-overlay/hot-dev-client' {
declare module.exports: any;
}
declare module 'next/dist/client/error-boundary' {
declare module.exports: any;
}
declare module 'next/dist/client/head-manager' {
declare module.exports: any;
}
declare module 'next/dist/client/index' {
declare module.exports: any;
}
declare module 'next/dist/client/next-dev' {
declare module.exports: any;
}
declare module 'next/dist/client/next' {
declare module.exports: any;
}
declare module 'next/dist/client/noop' {
declare module.exports: any;
}
declare module 'next/dist/client/on-demand-entries-client' {
declare module.exports: any;
}
declare module 'next/dist/client/source-map-support' {
declare module.exports: any;
}
declare module 'next/dist/client/webpack-hot-middleware-client' {
declare module.exports: any;
}
declare module 'next/dist/export/index' {
declare module.exports: any;
}
declare module 'next/dist/lib/app' {
declare module.exports: any;
}
declare module 'next/dist/lib/asset' {
declare module.exports: any;
}
declare module 'next/dist/lib/constants' {
declare module.exports: any;
}
declare module 'next/dist/lib/dynamic' {
declare module.exports: any;
}
declare module 'next/dist/lib/error-debug' {
declare module.exports: any;
}
declare module 'next/dist/lib/error' {
declare module.exports: any;
}
declare module 'next/dist/lib/EventEmitter' {
declare module.exports: any;
}
declare module 'next/dist/lib/head' {
declare module.exports: any;
}
declare module 'next/dist/lib/link' {
declare module.exports: any;
}
declare module 'next/dist/lib/loadable-capture' {
declare module.exports: any;
}
declare module 'next/dist/lib/loadable' {
declare module.exports: any;
}
declare module 'next/dist/lib/p-queue' {
declare module.exports: any;
}
declare module 'next/dist/lib/page-loader' {
declare module.exports: any;
}
declare module 'next/dist/lib/promisify' {
declare module.exports: any;
}
declare module 'next/dist/lib/router/index' {
declare module.exports: any;
}
declare module 'next/dist/lib/router/router' {
declare module.exports: any;
}
declare module 'next/dist/lib/router/with-router' {
declare module.exports: any;
}
declare module 'next/dist/lib/runtime-config' {
declare module.exports: any;
}
declare module 'next/dist/lib/shallow-equals' {
declare module.exports: any;
}
declare module 'next/dist/lib/side-effect' {
declare module.exports: any;
}
declare module 'next/dist/lib/utils' {
declare module.exports: any;
}
declare module 'next/dist/pages/_app' {
declare module.exports: any;
}
declare module 'next/dist/pages/_document' {
declare module.exports: any;
}
declare module 'next/dist/pages/_error' {
declare module.exports: any;
}
declare module 'next/dist/server/config' {
declare module.exports: any;
}
declare module 'next/dist/server/document' {
declare module.exports: any;
}
declare module 'next/dist/server/hot-reloader' {
declare module.exports: any;
}
declare module 'next/dist/server/lib/error-overlay-middleware' {
declare module.exports: any;
}
declare module 'next/dist/server/lib/path-match' {
declare module.exports: any;
}
declare module 'next/dist/server/lib/start-server' {
declare module.exports: any;
}
declare module 'next/dist/server/lib/utils' {
declare module.exports: any;
}
declare module 'next/dist/server/next-dev-server' {
declare module.exports: any;
}
declare module 'next/dist/server/next-server' {
declare module.exports: any;
}
declare module 'next/dist/server/next' {
declare module.exports: any;
}
declare module 'next/dist/server/on-demand-entry-handler' {
declare module.exports: any;
}
declare module 'next/dist/server/render' {
declare module.exports: any;
}
declare module 'next/dist/server/require' {
declare module.exports: any;
}
declare module 'next/dist/server/router' {
declare module.exports: any;
}
declare module 'next/dist/server/utils' {
declare module.exports: any;
}
declare module 'next/document' {
declare module.exports: any;
}
declare module 'next/dynamic' {
declare module.exports: any;
}
declare module 'next/error' {
declare module.exports: any;
}
declare module 'next/head' {
declare module.exports: any;
}
declare module 'next/link' {
declare module.exports: any;
}
declare module 'next/prefetch' {
declare module.exports: any;
}
declare module 'next/router' {
declare module.exports: any;
}
// Filename aliases
declare module 'next/app.js' {
declare module.exports: $Exports<'next/app'>;
}
declare module 'next/asset.js' {
declare module.exports: $Exports<'next/asset'>;
}
declare module 'next/babel.js' {
declare module.exports: $Exports<'next/babel'>;
}
declare module 'next/client.js' {
declare module.exports: $Exports<'next/client'>;
}
declare module 'next/config.js' {
declare module.exports: $Exports<'next/config'>;
}
declare module 'next/constants.js' {
declare module.exports: $Exports<'next/constants'>;
}
declare module 'next/dist/build/babel/plugins/react-loadable-plugin.js' {
declare module.exports: $Exports<'next/dist/build/babel/plugins/react-loadable-plugin'>;
}
declare module 'next/dist/build/babel/preset.js' {
declare module.exports: $Exports<'next/dist/build/babel/preset'>;
}
declare module 'next/dist/build/index.js' {
declare module.exports: $Exports<'next/dist/build/index'>;
}
declare module 'next/dist/build/webpack.js' {
declare module.exports: $Exports<'next/dist/build/webpack'>;
}
declare module 'next/dist/build/webpack/loaders/emit-file-loader.js' {
declare module.exports: $Exports<'next/dist/build/webpack/loaders/emit-file-loader'>;
}
declare module 'next/dist/build/webpack/loaders/hot-self-accept-loader.js' {
declare module.exports: $Exports<'next/dist/build/webpack/loaders/hot-self-accept-loader'>;
}
declare module 'next/dist/build/webpack/loaders/next-babel-loader.js' {
declare module.exports: $Exports<'next/dist/build/webpack/loaders/next-babel-loader'>;
}
declare module 'next/dist/build/webpack/plugins/build-manifest-plugin.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/build-manifest-plugin'>;
}
declare module 'next/dist/build/webpack/plugins/chunk-names-plugin.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/chunk-names-plugin'>;
}
declare module 'next/dist/build/webpack/plugins/nextjs-require-cache-hot-reloader.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/nextjs-require-cache-hot-reloader'>;
}
declare module 'next/dist/build/webpack/plugins/nextjs-ssr-import.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/nextjs-ssr-import'>;
}
declare module 'next/dist/build/webpack/plugins/nextjs-ssr-module-cache.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/nextjs-ssr-module-cache'>;
}
declare module 'next/dist/build/webpack/plugins/pages-manifest-plugin.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/pages-manifest-plugin'>;
}
declare module 'next/dist/build/webpack/plugins/pages-plugin.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/pages-plugin'>;
}
declare module 'next/dist/build/webpack/plugins/react-loadable-plugin.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/react-loadable-plugin'>;
}
declare module 'next/dist/build/webpack/plugins/unlink-file-plugin.js' {
declare module.exports: $Exports<'next/dist/build/webpack/plugins/unlink-file-plugin'>;
}
declare module 'next/dist/build/webpack/utils.js' {
declare module.exports: $Exports<'next/dist/build/webpack/utils'>;
}
declare module 'next/dist/client/dev-error-overlay/eventsource.js' {
declare module.exports: $Exports<'next/dist/client/dev-error-overlay/eventsource'>;
}
declare module 'next/dist/client/dev-error-overlay/format-webpack-messages.js' {
declare module.exports: $Exports<'next/dist/client/dev-error-overlay/format-webpack-messages'>;
}
declare module 'next/dist/client/dev-error-overlay/hot-dev-client.js' {
declare module.exports: $Exports<'next/dist/client/dev-error-overlay/hot-dev-client'>;
}
declare module 'next/dist/client/error-boundary.js' {
declare module.exports: $Exports<'next/dist/client/error-boundary'>;
}
declare module 'next/dist/client/head-manager.js' {
declare module.exports: $Exports<'next/dist/client/head-manager'>;
}
declare module 'next/dist/client/index.js' {
declare module.exports: $Exports<'next/dist/client/index'>;
}
declare module 'next/dist/client/next-dev.js' {
declare module.exports: $Exports<'next/dist/client/next-dev'>;
}
declare module 'next/dist/client/next.js' {
declare module.exports: $Exports<'next/dist/client/next'>;
}
declare module 'next/dist/client/noop.js' {
declare module.exports: $Exports<'next/dist/client/noop'>;
}
declare module 'next/dist/client/on-demand-entries-client.js' {
declare module.exports: $Exports<'next/dist/client/on-demand-entries-client'>;
}
declare module 'next/dist/client/source-map-support.js' {
declare module.exports: $Exports<'next/dist/client/source-map-support'>;
}
declare module 'next/dist/client/webpack-hot-middleware-client.js' {
declare module.exports: $Exports<'next/dist/client/webpack-hot-middleware-client'>;
}
declare module 'next/dist/export/index.js' {
declare module.exports: $Exports<'next/dist/export/index'>;
}
declare module 'next/dist/lib/app.js' {
declare module.exports: $Exports<'next/dist/lib/app'>;
}
declare module 'next/dist/lib/asset.js' {
declare module.exports: $Exports<'next/dist/lib/asset'>;
}
declare module 'next/dist/lib/constants.js' {
declare module.exports: $Exports<'next/dist/lib/constants'>;
}
declare module 'next/dist/lib/dynamic.js' {
declare module.exports: $Exports<'next/dist/lib/dynamic'>;
}
declare module 'next/dist/lib/error-debug.js' {
declare module.exports: $Exports<'next/dist/lib/error-debug'>;
}
declare module 'next/dist/lib/error.js' {
declare module.exports: $Exports<'next/dist/lib/error'>;
}
declare module 'next/dist/lib/EventEmitter.js' {
declare module.exports: $Exports<'next/dist/lib/EventEmitter'>;
}
declare module 'next/dist/lib/head.js' {
declare module.exports: $Exports<'next/dist/lib/head'>;
}
declare module 'next/dist/lib/link.js' {
declare module.exports: $Exports<'next/dist/lib/link'>;
}
declare module 'next/dist/lib/loadable-capture.js' {
declare module.exports: $Exports<'next/dist/lib/loadable-capture'>;
}
declare module 'next/dist/lib/loadable.js' {
declare module.exports: $Exports<'next/dist/lib/loadable'>;
}
declare module 'next/dist/lib/p-queue.js' {
declare module.exports: $Exports<'next/dist/lib/p-queue'>;
}
declare module 'next/dist/lib/page-loader.js' {
declare module.exports: $Exports<'next/dist/lib/page-loader'>;
}
declare module 'next/dist/lib/promisify.js' {
declare module.exports: $Exports<'next/dist/lib/promisify'>;
}
declare module 'next/dist/lib/router/index.js' {
declare module.exports: $Exports<'next/dist/lib/router/index'>;
}
declare module 'next/dist/lib/router/router.js' {
declare module.exports: $Exports<'next/dist/lib/router/router'>;
}
declare module 'next/dist/lib/router/with-router.js' {
declare module.exports: $Exports<'next/dist/lib/router/with-router'>;
}
declare module 'next/dist/lib/runtime-config.js' {
declare module.exports: $Exports<'next/dist/lib/runtime-config'>;
}
declare module 'next/dist/lib/shallow-equals.js' {
declare module.exports: $Exports<'next/dist/lib/shallow-equals'>;
}
declare module 'next/dist/lib/side-effect.js' {
declare module.exports: $Exports<'next/dist/lib/side-effect'>;
}
declare module 'next/dist/lib/utils.js' {
declare module.exports: $Exports<'next/dist/lib/utils'>;
}
declare module 'next/dist/pages/_app.js' {
declare module.exports: $Exports<'next/dist/pages/_app'>;
}
declare module 'next/dist/pages/_document.js' {
declare module.exports: $Exports<'next/dist/pages/_document'>;
}
declare module 'next/dist/pages/_error.js' {
declare module.exports: $Exports<'next/dist/pages/_error'>;
}
declare module 'next/dist/server/config.js' {
declare module.exports: $Exports<'next/dist/server/config'>;
}
declare module 'next/dist/server/document.js' {
declare module.exports: $Exports<'next/dist/server/document'>;
}
declare module 'next/dist/server/hot-reloader.js' {
declare module.exports: $Exports<'next/dist/server/hot-reloader'>;
}
declare module 'next/dist/server/lib/error-overlay-middleware.js' {
declare module.exports: $Exports<'next/dist/server/lib/error-overlay-middleware'>;
}
declare module 'next/dist/server/lib/path-match.js' {
declare module.exports: $Exports<'next/dist/server/lib/path-match'>;
}
declare module 'next/dist/server/lib/start-server.js' {
declare module.exports: $Exports<'next/dist/server/lib/start-server'>;
}
declare module 'next/dist/server/lib/utils.js' {
declare module.exports: $Exports<'next/dist/server/lib/utils'>;
}
declare module 'next/dist/server/next-dev-server.js' {
declare module.exports: $Exports<'next/dist/server/next-dev-server'>;
}
declare module 'next/dist/server/next-server.js' {
declare module.exports: $Exports<'next/dist/server/next-server'>;
}
declare module 'next/dist/server/next.js' {
declare module.exports: $Exports<'next/dist/server/next'>;
}
declare module 'next/dist/server/on-demand-entry-handler.js' {
declare module.exports: $Exports<'next/dist/server/on-demand-entry-handler'>;
}
declare module 'next/dist/server/render.js' {
declare module.exports: $Exports<'next/dist/server/render'>;
}
declare module 'next/dist/server/require.js' {
declare module.exports: $Exports<'next/dist/server/require'>;
}
declare module 'next/dist/server/router.js' {
declare module.exports: $Exports<'next/dist/server/router'>;
}
declare module 'next/dist/server/utils.js' {
declare module.exports: $Exports<'next/dist/server/utils'>;
}
declare module 'next/document.js' {
declare module.exports: $Exports<'next/document'>;
}
declare module 'next/dynamic.js' {
declare module.exports: $Exports<'next/dynamic'>;
}
declare module 'next/error.js' {
declare module.exports: $Exports<'next/error'>;
}
declare module 'next/head.js' {
declare module.exports: $Exports<'next/head'>;
}
declare module 'next/link.js' {
declare module.exports: $Exports<'next/link'>;
}
declare module 'next/prefetch.js' {
declare module.exports: $Exports<'next/prefetch'>;
}
declare module 'next/router.js' {
declare module.exports: $Exports<'next/router'>;
}

View file

@ -0,0 +1,52 @@
// flow-typed signature: d4f2801b36b918c96c926f52e1462048
// flow-typed version: <<STUB>>/react-clipboard.js_v2.0.2/flow_v0.90.0
/**
* This is an autogenerated libdef stub for:
*
* 'react-clipboard.js'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'react-clipboard.js' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'react-clipboard.js/dist/react-clipboard' {
declare module.exports: any;
}
declare module 'react-clipboard.js/dist/react-clipboard.min' {
declare module.exports: any;
}
declare module 'react-clipboard.js/webpack.config' {
declare module.exports: any;
}
// Filename aliases
declare module 'react-clipboard.js/dist/react-clipboard.js' {
declare module.exports: $Exports<'react-clipboard.js/dist/react-clipboard'>;
}
declare module 'react-clipboard.js/dist/react-clipboard.min.js' {
declare module.exports: $Exports<'react-clipboard.js/dist/react-clipboard.min'>;
}
declare module 'react-clipboard.js/index' {
declare module.exports: $Exports<'react-clipboard.js'>;
}
declare module 'react-clipboard.js/index.js' {
declare module.exports: $Exports<'react-clipboard.js'>;
}
declare module 'react-clipboard.js/webpack.config.js' {
declare module.exports: $Exports<'react-clipboard.js/webpack.config'>;
}

View file

@ -0,0 +1,130 @@
// flow-typed signature: 8aedeb94bd13de37f787f9439e160b03
// flow-typed version: <<STUB>>/styled-components_v4.1.3/flow_v0.90.0
/**
* This is an autogenerated libdef stub for:
*
* 'styled-components'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'styled-components' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'styled-components/dist/styled-components-macro.cjs' {
declare module.exports: any;
}
declare module 'styled-components/dist/styled-components-macro.esm' {
declare module.exports: any;
}
declare module 'styled-components/dist/styled-components.browser.cjs' {
declare module.exports: any;
}
declare module 'styled-components/dist/styled-components.browser.esm' {
declare module.exports: any;
}
declare module 'styled-components/dist/styled-components.cjs' {
declare module.exports: any;
}
declare module 'styled-components/dist/styled-components.esm' {
declare module.exports: any;
}
declare module 'styled-components/dist/styled-components' {
declare module.exports: any;
}
declare module 'styled-components/dist/styled-components.min' {
declare module.exports: any;
}
declare module 'styled-components/native/dist/styled-components.native.cjs' {
declare module.exports: any;
}
declare module 'styled-components/native/dist/styled-components.native.esm' {
declare module.exports: any;
}
declare module 'styled-components/primitives/dist/styled-components-primitives.cjs' {
declare module.exports: any;
}
declare module 'styled-components/primitives/dist/styled-components-primitives.esm' {
declare module.exports: any;
}
declare module 'styled-components/scripts/postinstall' {
declare module.exports: any;
}
declare module 'styled-components/test-utils/index' {
declare module.exports: any;
}
declare module 'styled-components/test-utils/setupTestFramework' {
declare module.exports: any;
}
// Filename aliases
declare module 'styled-components/dist/styled-components-macro.cjs.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components-macro.cjs'>;
}
declare module 'styled-components/dist/styled-components-macro.esm.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components-macro.esm'>;
}
declare module 'styled-components/dist/styled-components.browser.cjs.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components.browser.cjs'>;
}
declare module 'styled-components/dist/styled-components.browser.esm.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components.browser.esm'>;
}
declare module 'styled-components/dist/styled-components.cjs.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components.cjs'>;
}
declare module 'styled-components/dist/styled-components.esm.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components.esm'>;
}
declare module 'styled-components/dist/styled-components.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components'>;
}
declare module 'styled-components/dist/styled-components.min.js' {
declare module.exports: $Exports<'styled-components/dist/styled-components.min'>;
}
declare module 'styled-components/native/dist/styled-components.native.cjs.js' {
declare module.exports: $Exports<'styled-components/native/dist/styled-components.native.cjs'>;
}
declare module 'styled-components/native/dist/styled-components.native.esm.js' {
declare module.exports: $Exports<'styled-components/native/dist/styled-components.native.esm'>;
}
declare module 'styled-components/primitives/dist/styled-components-primitives.cjs.js' {
declare module.exports: $Exports<'styled-components/primitives/dist/styled-components-primitives.cjs'>;
}
declare module 'styled-components/primitives/dist/styled-components-primitives.esm.js' {
declare module.exports: $Exports<'styled-components/primitives/dist/styled-components-primitives.esm'>;
}
declare module 'styled-components/scripts/postinstall.js' {
declare module.exports: $Exports<'styled-components/scripts/postinstall'>;
}
declare module 'styled-components/test-utils/index.js' {
declare module.exports: $Exports<'styled-components/test-utils/index'>;
}
declare module 'styled-components/test-utils/setupTestFramework.js' {
declare module.exports: $Exports<'styled-components/test-utils/setupTestFramework'>;
}

View file

@ -0,0 +1,39 @@
// flow-typed signature: d1da24f577f523d4438cb8caa832ec6a
// flow-typed version: <<STUB>>/throttle-debounce_v2.0.1/flow_v0.90.0
/**
* This is an autogenerated libdef stub for:
*
* 'throttle-debounce'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'throttle-debounce' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'throttle-debounce/index.cjs' {
declare module.exports: any;
}
declare module 'throttle-debounce/index.esm' {
declare module.exports: any;
}
// Filename aliases
declare module 'throttle-debounce/index.cjs.js' {
declare module.exports: $Exports<'throttle-debounce/index.cjs'>;
}
declare module 'throttle-debounce/index.esm.js' {
declare module.exports: $Exports<'throttle-debounce/index.esm'>;
}

26
lib/gtag.js Normal file
View file

@ -0,0 +1,26 @@
// @flow
export const GA_TRACKING_ID = 'UA-31162386-5';
// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
export const pageview = (url: string) => {
try {
window.gtag('config', GA_TRACKING_ID, {
page_location: url,
});
} catch (err) {
// dont crash the page if ga fails
}
};
// https://developers.google.com/analytics/devguides/collection/gtagjs/events
export const event = ({ action, category, label, value }: any) => {
try {
window.gtag('event', action, {
event_category: category,
event_label: label,
value,
});
} catch (err) {
// dont crash the page if ga fails
}
};

23
lib/localStorage.js Normal file
View file

@ -0,0 +1,23 @@
export const getItemFromStorage = key => {
if (!localStorage) return;
try {
return JSON.parse(localStorage.getItem(key));
} catch (err) {}
};
export const storeItem = (key, value) => {
if (!localStorage) return;
try {
return localStorage.setItem(key, JSON.stringify(value));
} catch (err) {}
};
export const removeItemFromStorage = key => {
if (!localStorage) return;
try {
return localStorage.removeItem(key);
} catch (err) {}
};

1
next.config.js Normal file
View file

@ -0,0 +1 @@
module.exports = {};

11
now.json Normal file
View file

@ -0,0 +1,11 @@
{
"version": 2,
"alias": ["securitycheckli.st"],
"github": {
"silent": true
},
"name": "security-checklist",
"builds": [
{ "src": "next.config.js", "use": "@now/next" }
]
}

10378
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

69
package.json Normal file
View file

@ -0,0 +1,69 @@
{
"name": "security-checklist",
"version": "0.1.0",
"description": "A checklist for staying safe on the internet",
"scripts": {
"now-build": "next build",
"dev": "next",
"start": "next start",
"build": "next build",
"flow": "flow",
"flow start": "flow start",
"flow stop": "flow stop",
"flow status": "flow status",
"flow coverage": "flow coverage",
"prettier": "prettier",
"cypress:open": "cypress open",
"cypress:run": "cypress run",
"lint:staged": "lint-staged"
},
"dependencies": {
"@sentry/browser": "^4.5.0",
"next": "^7.0.2",
"next-seo": "^1.8.0",
"react": "^16.8.0-alpha.0",
"react-clipboard.js": "^2.0.2",
"react-dom": "^16.8.0-alpha.0",
"styled-components": "^4.1.3",
"throttle-debounce": "^2.0.1"
},
"devDependencies": {
"@babel/preset-flow": "^7.0.0",
"@cypress/browserify-preprocessor": "^1.1.2",
"babel-eslint": "^10.0.1",
"babel-plugin-styled-components": "^1.10.0",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"cypress": "^3.1.4",
"eslint": "^5.12.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-config-prettier": "^3.3.0",
"eslint-config-react-app": "^3.0.6",
"eslint-plugin-flowtype": "^3.2.1",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.2",
"eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-react": "^7.12.3",
"flow-bin": "^0.90.0",
"lint-staged": "^8.1.0",
"prettier": "^1.15.3",
"prettier-eslint": "^8.8.2"
},
"lint-staged": {
"*.js": [
"prettier --write",
"eslint --fix",
"git add"
]
},
"pre-commit": "lint:staged",
"repository": {
"type": "git",
"url": "git+https://github.com/brianlovin/security-checklist.git"
},
"author": "Brian Lovin",
"license": "MIT",
"bugs": {
"url": "https://github.com/brianlovin/security-checklist/issues"
},
"homepage": "https://github.com/brianlovin/security-checklist#readme"
}

81
pages/_app.js Normal file
View file

@ -0,0 +1,81 @@
// @flow
import App, { Container } from 'next/app';
import * as React from 'react';
import Head from 'next/head';
import * as Sentry from '@sentry/browser';
import NextSeo from 'next-seo';
import { GlobalStyles } from '../static/normalize';
import defaultSEO from '../config/next-seo.js';
const SENTRY_PUBLIC_DSN =
'https://42334f0365364b63bc57f4245d111b87@sentry.io/1370339';
class SecurityChecklistApp extends App {
constructor() {
super();
Sentry.init({ dsn: SENTRY_PUBLIC_DSN });
}
// $FlowFixMe
componentDidCatch(error: mixed, errorInfo: any) {
Sentry.configureScope(scope => {
Object.keys(errorInfo).forEach(key => {
scope.setExtra(key, errorInfo[key]);
});
});
Sentry.captureException(error);
// This is needed to render errors correctly in development / production
super.componentDidCatch(error, errorInfo);
}
componentDidMount() {
Sentry.init({
dsn: 'https://b92b29b696884e5798e161962eac36de@sentry.io/1318151',
});
}
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<GlobalStyles />
<Head>
<meta name="theme-color" content="#16171A" key="theme-color" />
<meta
name="description"
content="A checklist for staying safe on the internet"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="static/meta/apple-touch-icon.png"
/>
<link rel="manifest" href="/static/meta/site.webmanifest" />
<link
rel="mask-icon"
href="/static/meta/safari-pinned-tab.svg"
color="#16171A"
/>
<meta name="msapplication-TileColor" content="#ffffff" />
<script
src="https://browser.sentry-cdn.com/4.2.4/bundle.min.js"
crossOrigin="anonymous"
/>
{this.props.styleTags}
</Head>
<NextSeo config={defaultSEO} />
<Component {...pageProps} />
</Container>
);
}
}
export default SecurityChecklistApp;

71
pages/_document.js Normal file
View file

@ -0,0 +1,71 @@
// @flow
import * as React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
import { GA_TRACKING_ID } from '../lib/gtag';
export default class MyDocument extends Document {
// $FlowFixMe
static getInitialProps({ renderPage }) {
const sheet = new ServerStyleSheet();
const page = renderPage(App => props =>
sheet.collectStyles(<App {...props} />)
);
const styleTags = sheet.getStyleElement();
return { ...page, styleTags };
}
render() {
return (
<html lang="en">
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1"
key="viewport"
/>
<meta charSet="utf-8" />
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/static/meta/favicon-96x96.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/static/meta/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/static/meta/favicon-16x16.png"
/>
{this.props.styleTags}
</Head>
<body>
<Main />
<NextScript />
{/* Global Site Tag (gtag.js) - Google Analytics */}
<script
async
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
/>
<script
// eslint-disable-next-line
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}');
`,
}}
/>
</body>
</html>
);
}
}

21
pages/_error.js Normal file
View file

@ -0,0 +1,21 @@
// @flow
import * as React from 'react';
import type { GetInitialProps } from '../types';
import Home from './index';
class Error extends React.Component<{}> {
static async getInitialProps({ res }: GetInitialProps) {
if (res && res.setHeader) {
const cacheAge = 60 * 60 * 24 * 30;
res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);
}
return {};
}
render() {
return <Home />;
}
}
export default Error;

73
pages/about.js Normal file
View file

@ -0,0 +1,73 @@
// @flow
import * as React from 'react';
import NextSeo from 'next-seo';
import Page, { SectionHeading, Heading, Subheading } from '../components/Page';
export default function About() {
return (
<Page showEmailCapture={false}>
<NextSeo
config={{
title: 'Security Checklist · About',
description: 'A checklist for staying safe on the internet',
openGraph: {
title: 'Security Checklist · About',
description: 'A checklist for staying safe on the internet',
url: 'https://securitycheckli.st/about',
},
}}
/>
<SectionHeading>
<Heading>About</Heading>
<div style={{ padding: '8px' }} />
<Subheading>
This website provides a beginners checklist for staying safe on the
internet. This website is the result of a conversation started during
a{' '}
<a
href="https://spec.fm/podcasts/design-details/249464"
target="_blank"
rel="noreferrer noopener"
>
recent episode
</a>{' '}
of the{' '}
<a
href="https://spec.fm/podcasts/design-details/"
target="_blank"
rel="noreferrer noopener"
>
Design Details Podcast
</a>{' '}
and a subsequent tweet by{' '}
<a
href="https://twitter.com/mknepprath/status/1083966912420372481"
target="_blank"
rel="noreferrer noopener"
>
Michael Knepprath
</a>
.
</Subheading>
<div style={{ padding: '8px' }} />
<Subheading>
The code that powers this website is{' '}
<a
href="https://github.com/brianlovin/security-checklist"
target="_blank"
rel="noopener noreferrer"
>
open source
</a>
. Please contribute if youd like to see additional resources added to
this checklist.
</Subheading>
</SectionHeading>
</Page>
);
}

26
pages/index.js Normal file
View file

@ -0,0 +1,26 @@
// @flow
import * as React from 'react';
import Page, { SectionHeading, Heading, Subheading } from '../components/Page';
import type { GetInitialProps } from '../types';
class Index extends React.Component<{}> {
static async getInitialProps({ res }: GetInitialProps) {
if (res && res.setHeader) {
// cache podcasts for a month
const cacheAge = 60 * 60 * 24 * 30;
res.setHeader('Cache-Control', `public,s-maxage=${cacheAge}`);
}
return {};
}
render() {
return (
<Page>
<SectionHeading />
</Page>
);
}
}
export default Index;

331
static/normalize.js Normal file

File diff suppressed because one or more lines are too long

13
types/index.js Normal file
View file

@ -0,0 +1,13 @@
// @flow
export type GetInitialProps = {
pathname: string,
query: any,
req?: any,
res?: any,
jsonPageRes?: any,
err?: any,
ctx?: any,
Component: {
getInitialProps?: (ctx: any) => void,
},
};