mirror of
https://github.com/brianlovin/security-checklist.git
synced 2026-03-11 08:55:31 +00:00
Merge branch 'progress-indicator' into progress-confetti
This commit is contained in:
commit
de348c8c54
7 changed files with 162 additions and 75 deletions
|
|
@ -70,11 +70,11 @@ export const CheckboxContainer = styled.div`
|
|||
width: 32px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
input[type='checkbox'] {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label {
|
||||
input[type='checkbox'] + label {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
|
|
@ -86,12 +86,12 @@ export const CheckboxContainer = styled.div`
|
|||
text-indent: -1000px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label:hover {
|
||||
input[type='checkbox'] + label:hover {
|
||||
${Shadows.default};
|
||||
background: ${theme.bg.default};
|
||||
}
|
||||
|
||||
input[type="checkbox"] + label::after {
|
||||
input[type='checkbox'] + label::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
|
|
@ -104,18 +104,18 @@ export const CheckboxContainer = styled.div`
|
|||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label {
|
||||
input[type='checkbox']:checked + label {
|
||||
border: 1px solid ${theme.bg.default};
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label::after {
|
||||
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 {
|
||||
input[type='checkbox'] + label::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -125,23 +125,24 @@ export const CheckboxContainer = styled.div`
|
|||
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);
|
||||
box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked + label::before {
|
||||
input[type='checkbox']:checked + label::before {
|
||||
opacity: 1;
|
||||
background-color: ${theme.success.default};
|
||||
}
|
||||
|
||||
input[type="checkbox"]:active + label, input[type="checkbox"]:focus + label {
|
||||
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)};
|
||||
0 0 0 3px ${props => hexa(props.theme.brand.default, 0.5)};
|
||||
}
|
||||
input[type="checkbox"]:active:checked + label, input[type="checkbox"]:focus:checked + label {
|
||||
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)};
|
||||
0 0 0 3px ${props => hexa(props.theme.spectrum.default, 0.5)};
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
export const ResourceContent = styled.div`
|
||||
|
|
@ -201,12 +202,12 @@ export const AppMeta = styled.a`
|
|||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 6px;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
&:active, &:focus {
|
||||
&: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};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -257,17 +258,17 @@ export const AppSourcesListItem = styled.li`
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px;
|
||||
border-radius: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
color: ${theme.text.default};
|
||||
}
|
||||
|
||||
&:active, &:focus {
|
||||
&: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};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,15 +278,14 @@ export const AppSourcesListItem = styled.li`
|
|||
left: 4px;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 4px;
|
||||
min-width: 40px;
|
||||
|
||||
.icon {
|
||||
position: relative;
|
||||
top: 5px;
|
||||
left: 7px;
|
||||
top: 3px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
|
@ -329,24 +329,28 @@ export const ResourceRowContainer = styled.a`
|
|||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&:hover, &:active, &:focus {
|
||||
background: ${theme.bg.wash};
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
color: ${theme.text.default};
|
||||
}
|
||||
|
||||
&:active, &:focus {
|
||||
&: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;
|
||||
border-radius: 4px;
|
||||
align-items: flex-start;
|
||||
margin-left: -24px;
|
||||
padding-left: 24px;
|
||||
|
||||
&:hover, &:active, &:focus {
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
background: ${theme.bg.default}!important;
|
||||
}
|
||||
|
||||
|
|
@ -376,24 +380,20 @@ export const Divider = styled.hr`
|
|||
`;
|
||||
|
||||
export const Content = styled.div`
|
||||
transition:
|
||||
max-height ${theme.animations.default},
|
||||
opacity ${theme.animations.default},
|
||||
visibility ${theme.animations.default};
|
||||
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"] {
|
||||
&[aria-hidden='true'] {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
`
|
||||
`;
|
||||
|
||||
export const Uncollapse = styled.button`
|
||||
background: ${theme.bg.wash};
|
||||
|
|
@ -418,7 +418,8 @@ export const Uncollapse = styled.button`
|
|||
color: ${theme.text.default};
|
||||
background: ${tint(theme.bg.wash, -4)};
|
||||
}
|
||||
&:active, &:focus {
|
||||
&:active,
|
||||
&:focus {
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
|
|
@ -459,11 +460,11 @@ export const OfferContainer = styled.a`
|
|||
&:hover {
|
||||
color: ${theme.text.secondary};
|
||||
}
|
||||
&:active, &:focus {
|
||||
&: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};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -504,21 +505,17 @@ export const ExpandContainer = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
|
||||
export const ExpandContent = styled.div`
|
||||
transition:
|
||||
max-height ${theme.animations.default},
|
||||
opacity ${theme.animations.default},
|
||||
visibility ${theme.animations.default};
|
||||
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"] {
|
||||
&[aria-hidden='true'] {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
`
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import {
|
|||
Label,
|
||||
LogoLink,
|
||||
Progression,
|
||||
ProgressBar } from './style';
|
||||
ProgressBar,
|
||||
ProgressLabel } from './style';
|
||||
import { PrimaryButton, GhostButton } from '../Button';
|
||||
import Logo from './Logo';
|
||||
import Confetti from './Confetti';
|
||||
|
|
@ -33,14 +34,6 @@ export default function Header(props: Props) {
|
|||
</Link>
|
||||
</div>
|
||||
|
||||
<Progression isHidden={!displayProgress}>
|
||||
{ currentCount === totalItemsCount && `🎉 `}
|
||||
{currentCount} of {totalItemsCount} completed
|
||||
{ currentCount === totalItemsCount && ` 🎉`}
|
||||
<Confetti fireConfetti={currentCount === totalItemsCount} />
|
||||
<ProgressBar />
|
||||
</Progression>
|
||||
|
||||
<ButtonRowContainer>
|
||||
<Link href="/about">
|
||||
<GhostButton as="a" href="/about">
|
||||
|
|
@ -57,6 +50,28 @@ export default function Header(props: Props) {
|
|||
Contribute
|
||||
</PrimaryButton>
|
||||
</ButtonRowContainer>
|
||||
|
||||
{ displayProgress && (
|
||||
<Progression
|
||||
id="progress"
|
||||
aria-label={`${currentCount} of ${totalItemsCount} completed`}
|
||||
tabIndex="0"
|
||||
>
|
||||
<ProgressBar
|
||||
id="progress_bar"
|
||||
aria-describedby="progress_tooltip"
|
||||
disabled={currentCount > 0 ? false : true}
|
||||
/>
|
||||
<ProgressLabel
|
||||
id="progress_tooltip"
|
||||
role="tooltip"
|
||||
>
|
||||
{ currentCount === totalItemsCount && `🎉 `}
|
||||
{currentCount} of {totalItemsCount} completed
|
||||
{ currentCount === totalItemsCount && ` 🎉`}
|
||||
</ProgressLabel>
|
||||
<Confetti fireConfetti={currentCount === totalItemsCount} />
|
||||
</Progression>)}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,27 +2,24 @@
|
|||
import styled from 'styled-components';
|
||||
import { theme } from '../theme';
|
||||
import { hexa } from '../globals';
|
||||
import { Shadows } from '../globals';
|
||||
|
||||
export const Container = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-areas: 'logo progression actions';
|
||||
padding: 16px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas: "logo actions";
|
||||
padding: 16px 16px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: ${props =>
|
||||
props.showHeaderShadow ? props.theme.bg.default : props.theme.bg.wash};
|
||||
background: ${theme.bg.default};
|
||||
z-index: 3;
|
||||
box-shadow: ${props =>
|
||||
props.showHeaderShadow ? '0 4px 8px rgba(0,0,0,0.04)' : 'none'};
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.04);
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
@media (max-width: 968px) {
|
||||
padding: 8px 16px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas: "logo actions" "progression progression";
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
@ -34,33 +31,86 @@ export const Logo = styled.h1`
|
|||
`;
|
||||
|
||||
export const Progression = styled.div`
|
||||
grid-area: progression;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
bottom: -16px;
|
||||
display: block;
|
||||
background: transparent;
|
||||
|
||||
display: ${props =>
|
||||
props.isHidden ? 'none' : 'block'};
|
||||
&:active, &:focus {
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ProgressBar = styled.div`
|
||||
height: 8px;
|
||||
margin: 6px 0;
|
||||
display: block;
|
||||
height: 4px;
|
||||
width: 100%;
|
||||
margin: 16px 0 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
background-image: linear-gradient(to left, #a913de, #6ac9ff);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.04);
|
||||
z-index: 5;
|
||||
|
||||
&:after {
|
||||
${Progression}:focus &,
|
||||
${Progression}:active & {
|
||||
box-shadow: 0 0 0 1px ${theme.bg.default},
|
||||
0 0 0 3px ${props => hexa(props.theme.brand.default, 0.25)};
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
background: ${theme.border.default};
|
||||
max-width: var(--progress);
|
||||
transition: max-width ${theme.animations.default};
|
||||
transition: max-width ${theme.animations.default}, background ${theme.animations.default};
|
||||
}
|
||||
&[disabled]::after {
|
||||
background: ${theme.bg.default};
|
||||
}
|
||||
`;
|
||||
|
||||
export const ProgressLabel = styled.p`
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
bottom: -25%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: ${theme.bg.default};
|
||||
padding: 8px 16px;
|
||||
|
||||
transition: all ${theme.animations.default};
|
||||
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
white-space: nowrap;
|
||||
${Shadows.default};
|
||||
|
||||
${Progression}:hover &,
|
||||
${Progression}:focus &,
|
||||
${Progression}:active &
|
||||
{
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
bottom: -87.5%;
|
||||
}
|
||||
|
||||
@media (max-width: 968px) {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
`
|
||||
|
||||
export const ButtonRowContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
|
@ -77,6 +127,7 @@ export const LogoLink = styled.a`
|
|||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
height: 100%;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export const Glyph = ({ glyph }: GlyphProps): any => {
|
|||
);
|
||||
case 'android':
|
||||
return (
|
||||
<g>
|
||||
<g transform="translate(2 1)">
|
||||
<path d="M1.98508 7.17365H1.92873C1.20629 7.17365 0.617249 7.76456 0.617249 8.48513V14.1951C0.617249 14.9185 1.20629 15.5075 1.92873 15.5075H1.98604C2.70848 15.5075 3.29752 14.9166 3.29752 14.1951V8.48508C3.29656 7.76456 2.70661 7.17365 1.98508 7.17365Z" />
|
||||
<path d="M3.92507 16.399C3.92507 17.0623 4.46711 17.6024 5.13036 17.6024H6.41837V20.6866C6.41837 21.411 7.00928 22 7.72985 22H7.7862C8.5096 22 9.09956 21.41 9.09956 20.6866V17.6024H10.8996V20.6866C10.8996 21.411 11.4923 22 12.2129 22H12.2684C12.9917 22 13.5807 21.41 13.5807 20.6866V17.6024H14.8697C15.532 17.6024 16.074 17.0623 16.074 16.399V7.38312H3.92507V16.399Z" />
|
||||
<path d="M13.0255 1.91553L14.0486 0.33634C14.1143 0.236737 14.0852 0.10055 13.9847 0.0357013C13.8851 -0.0300621 13.7489 -0.00279859 13.684 0.0995919L12.6234 1.73331C11.8277 1.40732 10.939 1.22414 10.0005 1.22414C9.06101 1.22414 8.17416 1.40732 7.37659 1.73331L6.31785 0.0995919C6.25304 -0.00279859 6.11585 -0.0300621 6.01534 0.0357013C5.91482 0.100506 5.88568 0.236737 5.95145 0.33634L6.97544 1.91553C5.1294 2.82023 3.88465 4.52533 3.88465 6.48125C3.88465 6.6015 3.89218 6.71987 3.9025 6.83729H16.0993C16.1097 6.71987 16.1162 6.6015 16.1162 6.48125C16.1163 4.52533 14.8706 2.82023 13.0255 1.91553ZM7.17273 4.74327C6.84861 4.74327 6.58556 4.48209 6.58556 4.15706C6.58556 3.83203 6.84861 3.57177 7.17273 3.57177C7.49871 3.57177 7.75989 3.83199 7.75989 4.15706C7.75989 4.48213 7.49684 4.74327 7.17273 4.74327ZM12.8273 4.74327C12.5032 4.74327 12.2401 4.48209 12.2401 4.15706C12.2401 3.83203 12.5032 3.57177 12.8273 3.57177C13.1523 3.57177 13.4135 3.83199 13.4135 4.15706C13.4135 4.48209 13.1523 4.74327 12.8273 4.74327Z" />
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export default function Page(props: Props) {
|
|||
<Container>
|
||||
<style>{`
|
||||
:root {
|
||||
--progress: ${100 - progress}%;
|
||||
--progress: ${progress ? 100 - progress : 100}%;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
|
|
|
|||
|
|
@ -69,5 +69,17 @@ export default {
|
|||
url:
|
||||
'https://www.salon.com/2014/02/05/4_ways_google_is_destroying_privacy_and_collecting_your_data_partner/',
|
||||
},
|
||||
{
|
||||
name: 'Privacy-friendly alternatives to Google that don’t track you',
|
||||
url: 'https://nomoregoogle.com/',
|
||||
},
|
||||
{
|
||||
name: 'Opt out of global data surveillance programs like PRISM, XKeyscore and Tempora.',
|
||||
url: 'https://prism-break.org/en/',
|
||||
},
|
||||
{
|
||||
name: 'Knowledge and tools to protect your privacy against global mass surveillance',
|
||||
url: 'https://www.privacytools.io/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -96,5 +96,17 @@ export default {
|
|||
url:
|
||||
'https://www.wired.com/2016/06/hey-stop-using-texts-two-factor-authentication/',
|
||||
},
|
||||
{
|
||||
name: 'List of websites and whether or not they support 2FA.',
|
||||
url: 'https://twofactorauth.org/',
|
||||
},
|
||||
{
|
||||
name: 'Step-by-step instructions on enabling 2FA',
|
||||
url: 'https://www.turnon2fa.com/',
|
||||
},
|
||||
{
|
||||
name: 'List of websites and whether or not they support One Time Passwords (OTP) or Universal 2nd Factor (U2F)',
|
||||
url: 'https://www.dongleauth.info/',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue