mirror of
https://github.com/brianlovin/security-checklist.git
synced 2026-03-11 08:55:31 +00:00
Merge branch 'master' into patch-1
This commit is contained in:
commit
9b0d411f84
20 changed files with 460 additions and 212 deletions
|
|
@ -23,4 +23,4 @@ unclear-type=warn
|
|||
unsafe-getters-setters=error
|
||||
|
||||
[version]
|
||||
0.91.0
|
||||
0.92.1
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
// @flow
|
||||
// $FlowIssue
|
||||
import React, { useState } from 'react';
|
||||
import dynamic from 'next/dynamic';
|
||||
import * as Styled from './style';
|
||||
import { CopyLinkButton as StyledCopyLinkButton } 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,
|
||||
|
|
@ -26,20 +20,18 @@ export default function CopyLinkButton(props: CopyLinkProps) {
|
|||
};
|
||||
|
||||
return (
|
||||
<Clipboard
|
||||
style={{ background: 'none' }}
|
||||
<StyledCopyLinkButton
|
||||
data-clipboard-text={text}
|
||||
onSuccess={onClick}
|
||||
component="a"
|
||||
component="button"
|
||||
data-cy="copy-link-button"
|
||||
isClicked={isClicked}
|
||||
aria-label="Copy the website’s address to your clipboard."
|
||||
type="button"
|
||||
{...props}
|
||||
>
|
||||
<Styled.CopyLinkButton
|
||||
data-cy="copy-link-button"
|
||||
isClicked={isClicked}
|
||||
{...props}
|
||||
>
|
||||
<Icon glyph="link" size={24} />
|
||||
{isClicked ? 'Copied!' : children}
|
||||
</Styled.CopyLinkButton>
|
||||
</Clipboard>
|
||||
<Icon glyph="link" size={24} />
|
||||
<span>{isClicked ? 'Copied!' : children}</span>
|
||||
</StyledCopyLinkButton>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ import styled, { css } from 'styled-components';
|
|||
import { hexa, tint } from '../globals';
|
||||
import type { ButtonSize } from './types';
|
||||
import { theme } from '../theme';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const Clipboard = dynamic(() => import('react-clipboard.js'), {
|
||||
ssr: false,
|
||||
loading: () => null,
|
||||
});
|
||||
|
||||
const getPadding = (size: ButtonSize) => {
|
||||
switch (size) {
|
||||
|
|
@ -32,7 +38,7 @@ const getFontSize = (size: ButtonSize) => {
|
|||
}
|
||||
};
|
||||
|
||||
const base = css`
|
||||
export const base = css`
|
||||
-webkit-appearance: none;
|
||||
display: flex;
|
||||
flex: none;
|
||||
|
|
@ -58,11 +64,15 @@ const base = css`
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:hover, &:active, &:focus {
|
||||
transition: all 0.2s ease-in-out;
|
||||
box-shadow: ${props =>
|
||||
props.disabled ? 'none' : `${theme.shadows.button}`};
|
||||
}
|
||||
&:active, &:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.5)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const Button = styled.button`
|
||||
|
|
@ -126,7 +136,7 @@ export const PrimaryButton = styled.button`
|
|||
&:focus {
|
||||
box-shadow: 0 0 0 1px ${props =>
|
||||
props.theme.bg.default}, 0 0 0 3px ${props =>
|
||||
hexa(props.theme.brand.alt, 0.16)};
|
||||
hexa(props.theme.brand.alt, 0.5)};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -137,15 +147,15 @@ export const GhostButton = styled.button`
|
|||
background-color: transparent;
|
||||
background-image: none;
|
||||
|
||||
&:hover {
|
||||
background: ${props => tint(props.theme.bg.wash, -3)};
|
||||
&:hover, &:active, &:focus {
|
||||
background: ${props => tint(props.theme.bg.wash, -8)};
|
||||
color: ${theme.text.default};
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
&:active, &:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.08)};
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -220,12 +230,12 @@ export const ButtonSegmentRow = styled.div`
|
|||
${PrimaryButton} {
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.brand.alt, 0.16)};
|
||||
0 0 0 3px ${props => hexa(props.theme.brand.alt, 0.5)};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const FacebookButton = styled.button`
|
||||
export const FacebookButton = styled.a`
|
||||
${base}
|
||||
border: 1px solid ${theme.social.facebook};
|
||||
color: ${theme.bg.default};
|
||||
|
|
@ -262,11 +272,11 @@ export const FacebookButton = styled.button`
|
|||
&:focus {
|
||||
box-shadow: 0 0 0 1px ${props =>
|
||||
props.theme.bg.default}, 0 0 0 3px ${props =>
|
||||
hexa(props.theme.social.facebook, 0.16)};
|
||||
hexa(props.theme.social.facebook, 0.5)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const TwitterButton = styled.button`
|
||||
export const TwitterButton = styled.a`
|
||||
${base}
|
||||
border: 1px solid ${theme.social.twitter};
|
||||
color: ${theme.bg.default};
|
||||
|
|
@ -303,12 +313,13 @@ export const TwitterButton = styled.button`
|
|||
&:focus {
|
||||
box-shadow: 0 0 0 1px ${props =>
|
||||
props.theme.bg.default}, 0 0 0 3px ${props =>
|
||||
hexa(props.theme.social.twitter, 0.16)};
|
||||
hexa(props.theme.social.twitter, 0.5)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const CopyLinkButton = styled.button`
|
||||
export const CopyLinkButton = styled(Clipboard)`
|
||||
${base}
|
||||
transition: all ${theme.animations.default};
|
||||
border: 1px solid ${props =>
|
||||
props.isClicked
|
||||
? tint(props.theme.success.default, -10)
|
||||
|
|
@ -356,8 +367,9 @@ export const CopyLinkButton = styled.button`
|
|||
&: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};
|
||||
props.isClicked
|
||||
? hexa(props.theme.success.default, 0.5)
|
||||
: props.theme.border.default};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ export const AppRow = ({ app }: Props) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<AppRowContainer href={app.url} target="_blank" rel="noopener noreferrer">
|
||||
<AppMeta>
|
||||
<AppRowContainer>
|
||||
<AppMeta href={app.url} target="_blank" rel="noopener noreferrer" title={`go to: ${app.name}`}>
|
||||
{app.image && <AppIcon alt={app.name} src={app.image} />}
|
||||
<AppName>{app.name}</AppName>
|
||||
</AppMeta>
|
||||
|
|
@ -49,4 +49,4 @@ export const AppRow = ({ app }: Props) => {
|
|||
{app.offer && <Offer offer={app.offer} />}
|
||||
</AppRowContainer>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
@ -1,23 +1,39 @@
|
|||
// @flow
|
||||
// $FlowIssue
|
||||
import React, { useState } from 'react';
|
||||
import { AppsContainer, SectionHeading, ExpandContainer } from './style';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { AppsContainer, SectionHeading, ExpandContainer, ExpandContent } from './style';
|
||||
import { Button } from '../Button';
|
||||
import type { ChecklistResource } from '../../types';
|
||||
import { AppRow } from './App';
|
||||
|
||||
type Props = {
|
||||
resource: ChecklistResource,
|
||||
handleAppsExpand: Function,
|
||||
};
|
||||
|
||||
export const Apps = ({ resource }: Props) => {
|
||||
export const Apps = ({ resource, handleAppsExpand }: Props) => {
|
||||
const [overflowExpanded, setOverflowExpanded] = useState(false);
|
||||
const [contentHeight, setcontentHeight] = useState(2000);
|
||||
|
||||
const expandContentContainer = useRef(null);
|
||||
|
||||
function handleExpand() {
|
||||
let expandContentHeight =
|
||||
expandContentContainer.current
|
||||
? expandContentContainer.current.scrollHeight
|
||||
: contentHeight;
|
||||
|
||||
setcontentHeight(expandContentHeight)
|
||||
setOverflowExpanded(!overflowExpanded)
|
||||
|
||||
handleAppsExpand(overflowExpanded ? -expandContentHeight : expandContentHeight);
|
||||
}
|
||||
|
||||
if (!resource.apps) return null;
|
||||
|
||||
let appList = resource.apps;
|
||||
let overflowAppList;
|
||||
if (appList.length > 3) {
|
||||
if (appList && appList.length > 3) {
|
||||
overflowAppList = appList.slice(3, appList.length);
|
||||
appList = appList.slice(0, 3);
|
||||
}
|
||||
|
|
@ -25,19 +41,34 @@ export const Apps = ({ resource }: Props) => {
|
|||
return (
|
||||
<AppsContainer overflowExpanded={overflowExpanded}>
|
||||
<SectionHeading>Apps</SectionHeading>
|
||||
{appList.map(app => (
|
||||
{appList && appList.map(app => (
|
||||
<AppRow key={app.name} app={app} />
|
||||
))}
|
||||
|
||||
{overflowAppList && !overflowExpanded && (
|
||||
<ExpandContainer onClick={() => setOverflowExpanded(true)}>
|
||||
<Button>Show more choices</Button>
|
||||
</ExpandContainer>
|
||||
{overflowAppList && (
|
||||
<React.Fragment>
|
||||
<ExpandContent
|
||||
id={`apps_${resource.id}`}
|
||||
role="region"
|
||||
tabindex="-1"
|
||||
ref={expandContentContainer}
|
||||
style={{ '--maxHeight': `${contentHeight}px` }}
|
||||
aria-hidden={!overflowExpanded}
|
||||
>
|
||||
{overflowAppList.map(app => <AppRow key={app.name} app={app} />)}
|
||||
</ExpandContent>
|
||||
|
||||
<ExpandContainer
|
||||
onClick={handleExpand}
|
||||
role="button"
|
||||
aria-expanded={overflowExpanded}
|
||||
aria-controls={`apps_${resource.id}`}
|
||||
>
|
||||
<Button type="button">Show {overflowExpanded ? "less" : "more"} choices</Button>
|
||||
</ExpandContainer>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{overflowAppList &&
|
||||
overflowExpanded &&
|
||||
overflowAppList.map(app => <AppRow key={app.name} app={app} />)}
|
||||
</AppsContainer>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Title, Description, Uncollapse } from './style';
|
||||
import { Title, Uncollapse } from './style';
|
||||
import type { ChecklistResource } from '../../types';
|
||||
|
||||
type Props = {
|
||||
|
|
@ -13,10 +13,14 @@ export const Heading = ({ resource, isCollapsed, handleCollapse }: Props) => (
|
|||
<React.Fragment>
|
||||
<Title>
|
||||
{resource.title}
|
||||
<Uncollapse onClick={handleCollapse}>
|
||||
<Uncollapse
|
||||
onClick={handleCollapse}
|
||||
aria-controls={`content_${resource.id}`}
|
||||
aria-expanded={!isCollapsed}
|
||||
type="button"
|
||||
>
|
||||
{isCollapsed ? 'Show details' : 'Hide details'}
|
||||
</Uncollapse>
|
||||
</Title>
|
||||
{!isCollapsed && <Description source={resource.description} />}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ import { Resources } from './Resources';
|
|||
import {
|
||||
Container,
|
||||
CheckboxContainer,
|
||||
Checkbox,
|
||||
CardContent,
|
||||
ResourceContent,
|
||||
Divider,
|
||||
Description,
|
||||
Content,
|
||||
} from './style';
|
||||
|
||||
type Props = {
|
||||
|
|
@ -24,10 +25,18 @@ type State = {
|
|||
isChecked: boolean,
|
||||
isLoading: boolean,
|
||||
isCollapsed: boolean,
|
||||
contentHeight: number,
|
||||
};
|
||||
|
||||
class ChecklistItem extends React.Component<Props, State> {
|
||||
state = { isChecked: false, isLoading: true, isCollapsed: true };
|
||||
state = { isChecked: false, isLoading: true, isCollapsed: true, contentHeight: 2000, };
|
||||
contentContainer: { current: null | HTMLDivElement }
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.contentContainer = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { resource } = this.props;
|
||||
|
|
@ -39,6 +48,14 @@ class ChecklistItem extends React.Component<Props, State> {
|
|||
});
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
||||
if (prevState.isLoading && !this.state.isLoading && this.contentContainer.current) {
|
||||
return this.setState({
|
||||
contentHeight: this.contentContainer.current.scrollHeight,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleSetChecked = () => {
|
||||
const { isChecked } = this.state;
|
||||
const { resource } = this.props;
|
||||
|
|
@ -46,11 +63,19 @@ class ChecklistItem extends React.Component<Props, State> {
|
|||
return this.setState({ isChecked: !isChecked, isCollapsed: !isChecked });
|
||||
};
|
||||
|
||||
uncollapse = () =>
|
||||
this.setState(state => ({ isCollapsed: !state.isCollapsed }));
|
||||
uncollapse = () => {
|
||||
this.setState(state => ({ isCollapsed: !state.isCollapsed }));
|
||||
this.contentContainer.current && this.contentContainer.current.focus();
|
||||
};
|
||||
|
||||
handleAppsExpand = (appsContainerHeight: number) => {
|
||||
return this.contentContainer.current && this.setState({
|
||||
contentHeight: this.contentContainer.current.scrollHeight + appsContainerHeight,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isChecked, isLoading, isCollapsed } = this.state;
|
||||
const { isChecked, isLoading, isCollapsed, contentHeight } = this.state;
|
||||
const { resource } = this.props;
|
||||
|
||||
if (isLoading) return <LoadingChecklistItem />;
|
||||
|
|
@ -59,30 +84,60 @@ class ChecklistItem extends React.Component<Props, State> {
|
|||
<Container>
|
||||
<Card isChecked={isChecked}>
|
||||
<CardContent isCollapsed={isCollapsed}>
|
||||
<CheckboxContainer onClick={this.handleSetChecked}>
|
||||
<Checkbox isChecked={isChecked} />
|
||||
<CheckboxContainer>
|
||||
<input
|
||||
aria-expanded={!isCollapsed}
|
||||
type="checkbox"
|
||||
checked={isChecked}
|
||||
id={`checkbox_${resource.id}`}
|
||||
onChange={this.handleSetChecked}
|
||||
aria-controls={`content_${resource.id}`}
|
||||
/>
|
||||
<label htmlFor={`checkbox_${resource.id}`}>
|
||||
{resource.title}
|
||||
</label>
|
||||
</CheckboxContainer>
|
||||
|
||||
<ResourceContent isChecked={isChecked} isCollapsed={isCollapsed}>
|
||||
<ResourceContent
|
||||
isChecked={isChecked}
|
||||
isCollapsed={isCollapsed}
|
||||
>
|
||||
<Heading
|
||||
resource={resource}
|
||||
isCollapsed={isCollapsed}
|
||||
handleCollapse={this.uncollapse}
|
||||
/>
|
||||
|
||||
{!isCollapsed && resource.apps && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Apps resource={resource} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
<Content
|
||||
aria-hidden={isCollapsed}
|
||||
id={`content_${resource.id}`}
|
||||
role="region"
|
||||
tabindex="-1"
|
||||
ref={this.contentContainer}
|
||||
style={{ '--maxHeight': `${contentHeight}px` }}
|
||||
>
|
||||
|
||||
<Description source={resource.description} />
|
||||
|
||||
{resource.apps && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Apps
|
||||
resource={resource}
|
||||
handleAppsExpand={this.handleAppsExpand}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{resource.resources && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Resources resource={resource} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
</Content>
|
||||
|
||||
{!isCollapsed && resource.resources && (
|
||||
<React.Fragment>
|
||||
<Divider />
|
||||
<Resources resource={resource} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
</ResourceContent>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import styled, { css } from 'styled-components';
|
||||
import Markdown from 'react-markdown';
|
||||
import { theme } from '../theme';
|
||||
import { Shadows, tint } from '../globals';
|
||||
import { Shadows, tint, hexa } from '../globals';
|
||||
|
||||
export const Container = styled.div`
|
||||
margin-bottom: 24px;
|
||||
|
|
@ -69,35 +69,29 @@ export const CheckboxContainer = styled.div`
|
|||
margin-top: 4px;
|
||||
width: 32px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Checkbox = styled.span`
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid
|
||||
${props => (props.isChecked ? theme.bg.default : theme.border.default)};
|
||||
background: ${props =>
|
||||
props.isChecked ? theme.success.default : theme.bg.wash};
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
background-image: ${props =>
|
||||
props.isChecked
|
||||
? 'radial-gradient(circle at top right, #a913de, #6ac9ff)'
|
||||
: 'none'};
|
||||
box-shadow: ${props =>
|
||||
props.isChecked ? 'inset 0 0 1px rgba(0,0,0,0.4)' : 'none'};
|
||||
|
||||
&:hover {
|
||||
${props => !props.isChecked && Shadows.default};
|
||||
background: ${theme.bg.default};
|
||||
background-image: ${props =>
|
||||
props.isChecked
|
||||
? 'radial-gradient(circle at top right, #a913de, #6ac9ff)'
|
||||
: 'none'};
|
||||
input[type="checkbox"] {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
&:after {
|
||||
input[type="checkbox"] + label {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid ${theme.border.default};
|
||||
background: ${theme.bg.wash};
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-indent: -1000px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label:hover {
|
||||
${Shadows.default};
|
||||
background: ${theme.bg.default};
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
|
|
@ -105,11 +99,49 @@ export const Checkbox = styled.span`
|
|||
top: 6px;
|
||||
width: 6px;
|
||||
height: 12px;
|
||||
border: solid
|
||||
${props => (props.isChecked ? theme.bg.default : theme.border.active)};
|
||||
border: solid ${theme.border.active};
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label {
|
||||
border: 1px solid ${theme.bg.default};
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label::after {
|
||||
border: solid ${theme.bg.default};
|
||||
border-width: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
/* This ::before pseudo-element is used to animate the gradient
|
||||
which does not support transitions. */
|
||||
input[type="checkbox"] + label::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
transition: opacity ${theme.animations.default};
|
||||
opacity: 0;
|
||||
background-image: radial-gradient(circle at top right, #a913de, #6ac9ff);
|
||||
box-shadow: inset 0 0 1px rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label::before {
|
||||
opacity: 1;
|
||||
background-color: ${theme.success.default};
|
||||
}
|
||||
|
||||
input[type="checkbox"]:active + label, input[type="checkbox"]:focus + label {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.brand.default, 0.5)};
|
||||
}
|
||||
input[type="checkbox"]:active:checked + label, input[type="checkbox"]:focus:checked + label {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.spectrum.default, 0.5)};
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
export const ResourceContent = styled.div`
|
||||
|
|
@ -129,12 +161,7 @@ export const ResourceContent = styled.div`
|
|||
|
||||
export const AppsContainer = styled.div``;
|
||||
|
||||
export const AppMeta = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const AppRowContainer = styled.a`
|
||||
export const AppRowContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
|
@ -170,6 +197,19 @@ export const AppRowContainer = styled.a`
|
|||
}
|
||||
`;
|
||||
|
||||
export const AppMeta = styled.a`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 6px;
|
||||
border-radius: 8px;
|
||||
|
||||
&:active, &:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
background: ${theme.bg.wash};
|
||||
}
|
||||
`;
|
||||
|
||||
export const AppIcon = styled.img`
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
|
@ -207,8 +247,7 @@ export const AppSourcesListItem = styled.li`
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
color: ${theme.text.tertiary};
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
padding: 2px 8px;
|
||||
min-width: 56px;
|
||||
transition: all 0.1s ease-in-out;
|
||||
|
||||
|
|
@ -217,6 +256,19 @@ export const AppSourcesListItem = styled.li`
|
|||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px;
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
color: ${theme.text.default};
|
||||
}
|
||||
|
||||
&:active, &:focus {
|
||||
color: ${theme.text.default};
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
background: ${theme.bg.wash};
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
|
@ -225,9 +277,6 @@ export const AppSourcesListItem = styled.li`
|
|||
left: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: ${theme.text.default};
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 4px;
|
||||
|
|
@ -280,11 +329,16 @@ export const ResourceRowContainer = styled.a`
|
|||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:hover, &:active, &:focus {
|
||||
background: ${theme.bg.wash};
|
||||
color: ${theme.text.default};
|
||||
}
|
||||
|
||||
&:active, &:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: calc(100% + 40px);
|
||||
border-radius: 0;
|
||||
|
|
@ -292,7 +346,7 @@ export const ResourceRowContainer = styled.a`
|
|||
margin-left: -24px;
|
||||
padding-left: 24px;
|
||||
|
||||
&:hover {
|
||||
&:hover, &:active, &:focus {
|
||||
background: ${theme.bg.default}!important;
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +363,7 @@ export const ResourceName = styled.p`
|
|||
font-weight: 400;
|
||||
`;
|
||||
|
||||
export const Divider = styled.div`
|
||||
export const Divider = styled.hr`
|
||||
border-bottom: 1px solid ${tint(theme.bg.wash, -4)};
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
|
|
@ -321,7 +375,27 @@ export const Divider = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
export const Uncollapse = styled.span`
|
||||
export const Content = styled.div`
|
||||
transition:
|
||||
max-height ${theme.animations.default},
|
||||
opacity ${theme.animations.default},
|
||||
visibility ${theme.animations.default};
|
||||
|
||||
max-height: 2000px;
|
||||
max-height: var(--maxHeight);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
export const Uncollapse = styled.button`
|
||||
background: ${theme.bg.wash};
|
||||
border-radius: 20px;
|
||||
padding: 8px 16px;
|
||||
|
|
@ -344,6 +418,12 @@ export const Uncollapse = styled.span`
|
|||
color: ${theme.text.default};
|
||||
background: ${tint(theme.bg.wash, -4)};
|
||||
}
|
||||
&:active, &:focus {
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const OfferContainer = styled.a`
|
||||
|
|
@ -379,6 +459,12 @@ export const OfferContainer = styled.a`
|
|||
&:hover {
|
||||
color: ${theme.text.secondary};
|
||||
}
|
||||
&:active, &:focus {
|
||||
box-shadow: inset 0 0 1px ${theme.border.active},
|
||||
0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
background: ${theme.bg.wash};
|
||||
}
|
||||
`;
|
||||
|
||||
export const LeftBorder = styled.div`
|
||||
|
|
@ -417,3 +503,22 @@ export const ExpandContainer = styled.div`
|
|||
width: calc(100% + 40px);
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
export const ExpandContent = styled.div`
|
||||
transition:
|
||||
max-height ${theme.animations.default},
|
||||
opacity ${theme.animations.default},
|
||||
visibility ${theme.animations.default};
|
||||
max-height: 2000px;
|
||||
max-height: var(--maxHeight);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
`
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import styled from 'styled-components';
|
||||
import { theme } from '../theme';
|
||||
import { hexa } from '../globals';
|
||||
|
||||
export const Container = styled.div`
|
||||
margin-top: 128px;
|
||||
|
|
@ -21,24 +22,32 @@ export const Description = styled.p`
|
|||
color: ${theme.text.default};
|
||||
margin-left: 4px;
|
||||
}
|
||||
a:active, a:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
}
|
||||
`;
|
||||
|
||||
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};
|
||||
margin-right: 16px;
|
||||
line-height: 1;
|
||||
border-radius: 10px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
a:hover, a:active, a:focus {
|
||||
color: ${theme.text.default};
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: 16px;
|
||||
a:active, a:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
}
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Container, ButtonRowContainer, Label } from './style';
|
||||
import { Container, ButtonRowContainer, Label, LogoLink } from './style';
|
||||
import { PrimaryButton, GhostButton } from '../Button';
|
||||
import Logo from './Logo';
|
||||
|
||||
|
|
@ -14,27 +14,30 @@ export default function Header(props: Props) {
|
|||
|
||||
return (
|
||||
<Container showHeaderShadow={showHeaderShadow} data-cy="header">
|
||||
<Link href="/">
|
||||
<a style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Label>Security Checklist</Label>
|
||||
<Logo />
|
||||
</a>
|
||||
</Link>
|
||||
<div>
|
||||
<Link href="/">
|
||||
<LogoLink href="/">
|
||||
<Label>Security Checklist</Label>
|
||||
<Logo />
|
||||
</LogoLink>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<ButtonRowContainer>
|
||||
<Link href="/about">
|
||||
<a>
|
||||
<GhostButton>About</GhostButton>
|
||||
</a>
|
||||
<GhostButton as="a" href="/about">
|
||||
About
|
||||
</GhostButton>
|
||||
</Link>
|
||||
|
||||
<a
|
||||
<PrimaryButton
|
||||
href="https://github.com/brianlovin/security-checklist"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
as="a"
|
||||
>
|
||||
<PrimaryButton>Contribute</PrimaryButton>
|
||||
</a>
|
||||
Contribute
|
||||
</PrimaryButton>
|
||||
</ButtonRowContainer>
|
||||
</Container>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import styled from 'styled-components';
|
||||
import { theme } from '../theme';
|
||||
import { hexa } from '../globals';
|
||||
|
||||
export const Container = styled.div`
|
||||
display: grid;
|
||||
|
|
@ -18,10 +19,6 @@ export const Container = styled.div`
|
|||
props.showHeaderShadow ? '0 4px 8px rgba(0,0,0,0.04)' : 'none'};
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
a {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 968px) {
|
||||
padding: 8px 16px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
|
@ -41,6 +38,26 @@ export const ButtonRowContainer = styled.div`
|
|||
justify-content: flex-end;
|
||||
grid-area: actions;
|
||||
align-items: center;
|
||||
|
||||
a {
|
||||
margin-left: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const LogoLink = styled.a`
|
||||
transition: all ${props => props.theme.animations.default};
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
&:active, &:focus {
|
||||
transform: scale(1.2);
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
}
|
||||
`;
|
||||
|
||||
export const Label = styled.h1`
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export const Glyph = ({ glyph }: GlyphProps): any => {
|
|||
);
|
||||
case 'ios':
|
||||
return (
|
||||
<g>
|
||||
<g transform="translate(3.5 1.5)">
|
||||
<path d="M16.6437 15.5861C16.3385 16.2848 15.9772 16.928 15.5586 17.5193C14.9881 18.3255 14.5209 18.8835 14.1609 19.1934C13.6027 19.702 13.0048 19.9625 12.3644 19.9773C11.9047 19.9773 11.3504 19.8477 10.705 19.5847C10.0576 19.323 9.46262 19.1934 8.91858 19.1934C8.34801 19.1934 7.73608 19.323 7.08155 19.5847C6.42601 19.8477 5.89793 19.9847 5.49417 19.9983C4.88012 20.0242 4.26806 19.7563 3.65713 19.1934C3.2672 18.8563 2.77947 18.2786 2.1952 17.4601C1.56832 16.586 1.05294 15.5725 0.649179 14.417C0.216767 13.1689 5.70276e-08 11.9603 5.70276e-08 10.7902C5.70276e-08 9.44984 0.292262 8.29382 0.877656 7.32509C1.33773 6.54696 1.94978 5.93315 2.71581 5.48255C3.48185 5.03195 4.30955 4.80232 5.20091 4.78763C5.68863 4.78763 6.32822 4.93713 7.12303 5.23095C7.9156 5.52576 8.42451 5.67526 8.64762 5.67526C8.81444 5.67526 9.37977 5.50045 10.3382 5.15194C11.2445 4.82874 12.0094 4.69492 12.636 4.74763C14.334 4.88343 15.6097 5.54675 16.4581 6.74177C14.9395 7.6536 14.1883 8.93072 14.2032 10.5691C14.2169 11.8452 14.6841 12.9071 15.6022 13.7503C16.0183 14.1417 16.483 14.4441 17 14.6589C16.8879 14.9812 16.7695 15.2898 16.6437 15.5861ZM12.7494 0.400111C12.7494 1.40034 12.3806 2.33425 11.6456 3.19867C10.7586 4.22629 9.68574 4.8201 8.5223 4.7264C8.50747 4.6064 8.49888 4.48011 8.49888 4.3474C8.49888 3.38718 8.9207 2.35956 9.66979 1.51934C10.0438 1.09392 10.5194 0.740188 11.0962 0.458011C11.6718 0.180044 12.2162 0.0263202 12.7282 8.94779e-09C12.7431 0.133712 12.7494 0.267436 12.7494 0.400099V0.400111Z" />
|
||||
</g>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,11 @@ export default function Page(props: Props) {
|
|||
<Header showHeaderShadow={showHeaderShadow} />
|
||||
<InnerContainer>{children}</InnerContainer>
|
||||
<Footer />
|
||||
<ScrollToTop isVisible={scrollToTopVisible} onClick={scrollToTop}>
|
||||
<ScrollToTop
|
||||
isVisible={scrollToTopVisible}
|
||||
onClick={scrollToTop}
|
||||
type="button"
|
||||
>
|
||||
<Icon glyph="view-forward" size={32} />
|
||||
</ScrollToTop>
|
||||
</Container>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import styled from 'styled-components';
|
||||
import { tint } from '../globals';
|
||||
import { hexa, tint } from '../globals';
|
||||
import { theme } from '../theme';
|
||||
|
||||
export const Container = styled.div`
|
||||
|
|
@ -47,7 +47,7 @@ export const SectionHeading = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
export const Heading = styled.h3`
|
||||
export const Heading = styled.h2`
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
color: ${theme.text.default};
|
||||
|
|
@ -58,7 +58,7 @@ export const Heading = styled.h3`
|
|||
}
|
||||
`;
|
||||
|
||||
export const Subheading = styled.h4`
|
||||
export const Subheading = styled.p`
|
||||
font-size: 22px;
|
||||
font-weight: 400;
|
||||
color: ${theme.text.tertiary};
|
||||
|
|
@ -69,6 +69,18 @@ export const Subheading = styled.h4`
|
|||
color: ${theme.text.default};
|
||||
font-weight: 500;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: ${theme.text.tertiary};
|
||||
}
|
||||
a:active, a:focus {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.text.tertiary, 0.25)};
|
||||
}
|
||||
|
||||
& + & {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 968px) {
|
||||
max-width: 100%;
|
||||
|
|
@ -113,8 +125,11 @@ export const ScrollToTop = styled.button`
|
|||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.09);
|
||||
&:active, &:focus {
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.09),
|
||||
0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.brand.default, 0.5)};
|
||||
outline: none;
|
||||
transform: translateY(-2px);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,21 +6,21 @@ import { Container } from './style';
|
|||
export default function ShareButtons() {
|
||||
return (
|
||||
<Container>
|
||||
<a
|
||||
<FacebookButton
|
||||
href="https://www.facebook.com/sharer/sharer.php?u=https://securitycheckli.st"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<FacebookButton>Share</FacebookButton>
|
||||
</a>
|
||||
Share
|
||||
</FacebookButton>
|
||||
|
||||
<a
|
||||
<TwitterButton
|
||||
href="http://twitter.com/share?text=Check out Security Checklist, a checklist to help people stay safe online&url=https://securitycheckli.st"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<TwitterButton>Tweet</TwitterButton>
|
||||
</a>
|
||||
Tweet
|
||||
</TwitterButton>
|
||||
|
||||
<CopyLinkButton text="https://securitycheckli.st">
|
||||
Share Link
|
||||
|
|
|
|||
|
|
@ -13,10 +13,8 @@ export const Container = styled.div`
|
|||
|
||||
@media (max-width: 568px) {
|
||||
grid-template-columns: 1fr;
|
||||
grid-gap: 0;
|
||||
|
||||
button {
|
||||
margin-top: 16px;
|
||||
a, button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export const getItemFromStorage = key => {
|
|||
if (!localStorage) return;
|
||||
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(key));
|
||||
return JSON.parse(localStorage.getItem(key) || false);
|
||||
} catch (err) {}
|
||||
};
|
||||
|
||||
|
|
|
|||
101
package-lock.json
generated
101
package-lock.json
generated
|
|
@ -3679,9 +3679,9 @@
|
|||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint": {
|
||||
"version": "5.12.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.12.1.tgz",
|
||||
"integrity": "sha512-54NV+JkTpTu0d8+UYSA8mMKAG4XAsaOrozA9rCW7tgneg1mevcL7wIotPC+fZ0SkWwdhNqoXoxnQCTBp7UvTsg==",
|
||||
"version": "5.13.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.13.0.tgz",
|
||||
"integrity": "sha512-nqD5WQMisciZC5EHZowejLKQjWGuFS5c70fxqSKlnDME+oz9zmE8KTlX+lHSg+/5wsC/kf9Q9eMkC8qS3oM2fg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
|
|
@ -3713,7 +3713,6 @@
|
|||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.8.2",
|
||||
"path-is-inside": "^1.0.2",
|
||||
"pluralize": "^7.0.0",
|
||||
"progress": "^2.0.0",
|
||||
"regexpp": "^2.0.1",
|
||||
"semver": "^5.5.1",
|
||||
|
|
@ -3752,9 +3751,9 @@
|
|||
}
|
||||
},
|
||||
"slice-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz",
|
||||
"integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
|
||||
"integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.0",
|
||||
|
|
@ -3772,14 +3771,14 @@
|
|||
}
|
||||
},
|
||||
"table": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-5.2.1.tgz",
|
||||
"integrity": "sha512-qmhNs2GEHNqY5fd2Mo+8N1r2sw/rvTAAvBZTaTx+Y7PHLypqyrxr1MdIu0pLw6Xvl/Gi4ONu/sdceP8vvUjkyA==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-5.2.2.tgz",
|
||||
"integrity": "sha512-f8mJmuu9beQEDkKHLzOv4VxVYlU68NpdzjbGPl69i4Hx0sTopJuNxuzJd17iV2h24dAfa93u794OnDA5jqXvfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.6.1",
|
||||
"lodash": "^4.17.11",
|
||||
"slice-ansi": "2.0.0",
|
||||
"slice-ansi": "^2.0.0",
|
||||
"string-width": "^2.1.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -3943,9 +3942,9 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.0.tgz",
|
||||
"integrity": "sha512-KpibpIdKT0nbDG7G/ILWoZoN5G9cj3h1IHARxzvHk5Nt2LQ7oPUutbO9QbT1FKNHLPZB6BaoA1ASSLOiJZVEUQ==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz",
|
||||
"integrity": "sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aria-query": "^3.0.0",
|
||||
|
|
@ -4032,9 +4031,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz",
|
||||
"integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==",
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.7.tgz",
|
||||
"integrity": "sha512-HNJNgE60C9eOTgn974Tlp3dpLZdUr+SoxxDwPaY9J/kDNOLQTkaDgwBUXAF4SSsrAwD9RpdxuHK/EbuF+W9Ahw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
|
@ -4564,9 +4563,9 @@
|
|||
}
|
||||
},
|
||||
"flow-bin": {
|
||||
"version": "0.91.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.91.0.tgz",
|
||||
"integrity": "sha512-j+L+xNiUYnZZ27MjVI0y2c9474ZHOvdSQq0Tjwh56mEA7tfxYqp5Dcb6aZSwvs3tGMTjCrZow9aUlZf3OoRyDQ==",
|
||||
"version": "0.92.1",
|
||||
"resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.92.1.tgz",
|
||||
"integrity": "sha512-F5kC5oQOR2FXROAeybJHFqgZP+moKV9fa/53QK4Q4WayTQHdA0KSl48KD1gP0A9mioRLiKUegTva/7I15cX3Iw==",
|
||||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
|
|
@ -5666,26 +5665,32 @@
|
|||
}
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
|
||||
"integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz",
|
||||
"integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^3.0.0",
|
||||
"chalk": "^2.0.0",
|
||||
"ansi-escapes": "^3.2.0",
|
||||
"chalk": "^2.4.2",
|
||||
"cli-cursor": "^2.1.0",
|
||||
"cli-width": "^2.0.0",
|
||||
"external-editor": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^2.0.0",
|
||||
"lodash": "^4.17.10",
|
||||
"lodash": "^4.17.11",
|
||||
"mute-stream": "0.0.7",
|
||||
"run-async": "^2.2.0",
|
||||
"rxjs": "^6.1.0",
|
||||
"rxjs": "^6.4.0",
|
||||
"string-width": "^2.1.0",
|
||||
"strip-ansi": "^5.0.0",
|
||||
"through": "^2.3.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-escapes": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
|
||||
"integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz",
|
||||
|
|
@ -5693,9 +5698,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.3.3",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
|
||||
"integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
|
||||
"integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
|
|
@ -6268,9 +6273,9 @@
|
|||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.1.tgz",
|
||||
"integrity": "sha512-6C9tmmCedjDYQMzHydT5mXRtmEgpGUQDoIl+Ser8cfI/n9grsRUsuG2jd1BWqGf62OV+BV+6n/Drt82uYTCgJg==",
|
||||
"version": "8.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.3.tgz",
|
||||
"integrity": "sha512-6TGkikL1B+6mIOuSNq2TV6oP21IhPMnV8q0cf9oYZ296ArTVNcbFh1l1pfVOHHbBIYLlziWNsQ2q45/ffmJ4AA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@iamstarkov/listr-update-renderer": "0.4.1",
|
||||
|
|
@ -7963,9 +7968,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "1.16.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz",
|
||||
"integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==",
|
||||
"version": "1.16.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz",
|
||||
"integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==",
|
||||
"dev": true
|
||||
},
|
||||
"prettier-eslint": {
|
||||
|
|
@ -8412,14 +8417,14 @@
|
|||
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
|
||||
},
|
||||
"react": {
|
||||
"version": "16.8.0-alpha.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.8.0-alpha.0.tgz",
|
||||
"integrity": "sha512-B/nJJkNqV4JAJQ1M0Q38ZvhZ6BoYsjyZq29hbsIIPYayn/0DcYhu7tExpfzdtTC0SnUcA+RnDBTlXTEJ5b9PEg==",
|
||||
"version": "16.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.8.1.tgz",
|
||||
"integrity": "sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.13.0-alpha.0"
|
||||
"scheduler": "^0.13.1"
|
||||
}
|
||||
},
|
||||
"react-clipboard.js": {
|
||||
|
|
@ -8432,14 +8437,14 @@
|
|||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.8.0-alpha.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.0-alpha.0.tgz",
|
||||
"integrity": "sha512-OGfLUXGxtMgqLB1BqnB9flVCvc8VvAnhQYeFr+EUzwiODcD34dPrxtfa7ccK4dwzcPi8HRLSyBcaQi2OvVoUww==",
|
||||
"version": "16.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.1.tgz",
|
||||
"integrity": "sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.13.0-alpha.0"
|
||||
"scheduler": "^0.13.1"
|
||||
}
|
||||
},
|
||||
"react-error-overlay": {
|
||||
|
|
@ -8895,9 +8900,9 @@
|
|||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.13.0-alpha.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.0-alpha.0.tgz",
|
||||
"integrity": "sha512-+DbRwO53hlLso4gzrSIqcfNe8eRMMaV4gd4eySGisbyLBrp5unTpAMR0UAbrqlQLTGhnOFNoQAfaZTz4iPj1RQ==",
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.1.tgz",
|
||||
"integrity": "sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
|
|
|
|||
10
package.json
10
package.json
|
|
@ -37,18 +37,18 @@
|
|||
"babel-plugin-styled-components": "^1.10.0",
|
||||
"babel-plugin-transform-define": "^1.3.1",
|
||||
"cypress": "^3.1.5",
|
||||
"eslint": "^5.12.1",
|
||||
"eslint": "^5.13.0",
|
||||
"eslint-config-airbnb": "^17.1.0",
|
||||
"eslint-config-prettier": "^4.0.0",
|
||||
"eslint-config-react-app": "^3.0.6",
|
||||
"eslint-plugin-flowtype": "^3.2.1",
|
||||
"eslint-plugin-import": "^2.16.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||
"eslint-plugin-prettier": "^3.0.1",
|
||||
"eslint-plugin-react": "^7.12.4",
|
||||
"flow-bin": "^0.91.0",
|
||||
"lint-staged": "^8.1.1",
|
||||
"prettier": "^1.16.3",
|
||||
"flow-bin": "^0.92.1",
|
||||
"lint-staged": "^8.1.3",
|
||||
"prettier": "^1.16.4",
|
||||
"prettier-eslint": "^8.8.2"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@ export default function About() {
|
|||
.
|
||||
</Subheading>
|
||||
|
||||
<div style={{ padding: '8px' }} />
|
||||
|
||||
<Subheading>
|
||||
The code that powers this website is{' '}
|
||||
<a
|
||||
|
|
|
|||
Loading…
Reference in a new issue