Skip to content
This repository has been archived by the owner on Aug 1, 2023. It is now read-only.

Commit

Permalink
feat: adds onboarding screens
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed Jun 2, 2020
1 parent 38e9f9f commit 6a1d69d
Show file tree
Hide file tree
Showing 34 changed files with 660 additions and 86 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
module.exports = {
extends: ['@blockstack/eslint-config'],
extends: ['@blockstack/eslint-config', 'plugin:react-hooks/recommended'],
parser: '@typescript-eslint/parser',
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json',
ecmaVersion: 2019,
sourceType: 'module',
createDefaultProgram: true,
},
};
15 changes: 6 additions & 9 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@
".dockerignore": "ignore",
".eslintignore": "ignore"
},

"javascript.validate.enable": false,
"javascript.format.enable": false,
"typescript.format.enable": false,

"files.exclude": {
"app/node_modules/": true,
"app/dist/": true,
"dll": true,
},
"search.exclude": {
".git": true,
".eslintcache": true,
"app/dist": true,
"app/main.prod.js": true,
"app/main.prod.js.map": true,
"bower_components": true,
"dll": true,
"release": true,
"node_modules": true,
Expand All @@ -27,10 +29,5 @@
"yarn.lock": true,
"*.{css,sass,scss}.d.ts": true
},
"cSpell.words": [
"DEVTOOLS"
],
"cSpell.ignoreWords": [
"woff"
]
"editor.formatOnSave": true
}
34 changes: 34 additions & 0 deletions app/components/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { Box, BoxProps, Text, Flex } from '@blockstack/ui';

interface CardProps extends BoxProps {
title: string;
}

export const Card: React.FC<CardProps> = ({ title, children, ...rest }) => {
return (
<Box
borderRadius="6px"
border="1px solid"
borderColor="#E5E5EC"
boxShadow="mid"
textAlign="center"
{...rest}
>
<Flex
borderBottom="1px solid"
borderColor="#E5E5EC"
height="40px"
justifyContent="center"
alignItems="center"
>
<Text textStyle="caption" color="ink.600">
{title}
</Text>
</Flex>
<Box px={10} py={5}>
<Text>{children}</Text>
</Box>
</Box>
);
};
15 changes: 15 additions & 0 deletions app/components/error-label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { Flex, Box, FlexProps } from '@blockstack/ui';

import { ExclamationMark } from './exclamation-mark';

type ErrorLabelProps = FlexProps;

export const ErrorLabel: React.FC<ErrorLabelProps> = ({ children, ...rest }) => (
<Flex mt={3} {...rest}>
<Box mr={1} position="relative" top="1px">
<ExclamationMark />
</Box>
<Box mr={5}>{children}</Box>
</Flex>
);
13 changes: 13 additions & 0 deletions app/components/exclamation-mark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';

export const ExclamationMark: React.FC = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="none" viewBox="0 0 12 12">
<circle cx="6" cy="6" r="6" fill="#DE0014"></circle>
<path
fill="#fff"
d="M6.62 3.64a.622.622 0 10-1.244 0l.083 2.983a.54.54 0 001.081 0l.08-2.984zM6 9c.368 0 .687-.31.69-.694A.7.7 0 006 7.617.69.69 0 006 9z"
></path>
</svg>
);
};
2 changes: 1 addition & 1 deletion app/components/hr.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { Box, BoxProps } from '@blockstack/ui';

export const Hr = (props: BoxProps) => {
export const Hr: React.FC<BoxProps> = props => {
return <Box height="1px" width="100%" backgroundColor="#F0F0F5" {...props} />;
};
10 changes: 0 additions & 10 deletions app/components/onboarding-wrap.tsx

This file was deleted.

6 changes: 6 additions & 0 deletions app/components/onboarding/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from './onboarding';
export * from './onboarding-button';
export * from './onboarding-text';
export * from './onboarding-title';
export * from './onboarding-footer';
export * from './onboarding-footer-link';
20 changes: 20 additions & 0 deletions app/components/onboarding/onboarding-footer-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { Text, BoxProps } from '@blockstack/ui';

export const OnboardingFooterLink: React.FC<BoxProps> = ({ children, ...props }) => {
return (
<Text
display="block"
textStyle="body.small"
color="ink.600"
textDecoration="underline"
textAlign="center"
alignSelf="bottom"
my="loose"
cursor="pointer"
{...props}
>
{children}
</Text>
);
};
10 changes: 10 additions & 0 deletions app/components/onboarding/onboarding-footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { Flex, FlexProps } from '@blockstack/ui';

export const OnboardingFooter: React.FC<FlexProps> = ({ children, ...props }) => {
return (
<Flex flex={1} flexDirection="column" justifyContent="flex-end" {...props}>
{children}
</Flex>
);
};
17 changes: 17 additions & 0 deletions app/components/onboarding/onboarding-text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { Text, BoxProps } from '@blockstack/ui';

export const OnboardingText: React.FC<BoxProps> = ({ children, ...props }) => {
return (
<Text
display="block"
textStyle="body.large"
textAlign="center"
color="ink.900"
mt="tight"
{...props}
>
{children}
</Text>
);
};
12 changes: 12 additions & 0 deletions app/components/onboarding/onboarding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { Flex, FlexProps } from '@blockstack/ui';

export const Onboarding: React.FC<FlexProps> = ({ children, ...props }) => {
return (
<Flex flexDirection="column" height="100%" maxWidth="424px" m="0 auto" {...props}>
<Flex mt="152px" height="100%" flexDirection="column">
{children}
</Flex>
</Flex>
);
};
160 changes: 160 additions & 0 deletions app/components/secret-key-faq.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React from 'react';
import { Flex, Box, Text, BoxProps, ChevronIcon } from '@blockstack/ui';
import { useHover } from 'use-events';

interface FaqItem {
title: string;
body: string;
}

export const onboardingFaq = (appName: string): FaqItem[] => {
return [
{
title: 'Where should I save my Secret Key?',
body: `
Save your Secret Key in a place where only you can find it. For example:
<br><br>
<ul style="list-style: none;">
<li>• A password manager such as 1Password</li>
<li>• Your Notes app, protected with a password</li>
<li>• Written down and kept somewhere safe</li>
</ul>
<br>
Don’t save it anywhere where others can find it, or on a website you do not trust. Anybody with your Secret Key will have access to the apps you use.
`,
},
{
title: 'What if I lose my Secret Key?',
body:
'If you lose your Secret Key, it will be lost forever. Only you know your Secret Key, which means that no one can help you recover it.',
},
{
title: 'When will I need my Secret Key?',
body: `You’ll use your Secret Key to prove it’s you when you want to use ${appName} on a new device, such as your phone or laptop. Your Secret Key will stay active on your devices and keep you private in the apps you use.`,
},
{
title: 'Why don’t I have a password?',
body: `
Your Secret Key keeps you private in the apps you use it with. It does this by protecting everything you do with encryption, so that ${appName} can't see or track your activity.
<br><br>
To access your apps and data, the Secret Key is required. Only you have your Secret Key because it's created independently from ${appName}, so no one else can access your data. Blockstack, an open-source protocol, generated your Secret Key when you signed up for ${appName}.
`,
},
];
};

interface TitleProps extends BoxProps {
isFirst: boolean;
isOpen: boolean;
hovered: boolean;
}

const TitleElement: React.FC<TitleProps> = ({ onClick, isFirst, isOpen, hovered, title }) => (
<Flex
align="center"
borderBottom={!isOpen ? '1px solid' : undefined}
borderTop={isFirst ? '1px solid' : 'unset'}
borderColor="#E5E5EC" // this is not currently in the UI lib, asked jasper about it but he was out of office
// height="48px"
pt={4}
pb={isOpen ? 0 : 4}
justify="space-between"
onClick={onClick}
>
<Box>
<Text textStyle="body.small" color={isOpen || hovered ? 'ink' : 'ink.600'}>
{title}
</Text>
</Box>
<Box color="ink.300">
<ChevronIcon direction={isOpen ? 'up' : 'down'} />
</Box>
</Flex>
);

interface BodyProps {
body: string;
}

const Body: React.FC<BodyProps> = ({ body }) => (
<Box
borderBottom="1px solid"
borderColor="#E5E5EC" // this is not currently in the UI lib, asked jasper about it but he was out of office
py={3}
>
<Text color="ink.600">
<div dangerouslySetInnerHTML={{ __html: body }} />
</Text>
</Box>
);

interface FaqContent {
title: string;
body: string;
tracking?: string;
icon?: string;
}

interface CollapseItemProps extends FaqContent {
handleOpen: (key: number) => void;
id: number;
open: number | null;
}

const CollapseItem: React.FC<CollapseItemProps> = ({ handleOpen, id, title, body, open }) => {
const [hovered, bind] = useHover();
return (
<Box cursor={hovered ? 'pointer' : undefined} lineHeight="16px" {...bind}>
<TitleElement
onClick={() => {
handleOpen(id);
}}
isFirst={id === 0}
title={title}
hovered={hovered}
isOpen={id === open}
/>
{open === id ? <Body body={body} /> : null}
</Box>
);
};

interface CollapseProps extends BoxProps {
content: FaqContent[];
}

/**
* This component renders a list of clickable items that
* will reveal content onClick, then hide it on any other
* onClick of an item
*/
export const Collapse: React.FC<CollapseProps> = ({ content, ...rest }) => {
const [open, setOpen] = React.useState<number | null>(null);
const handleOpen = (key: number) => (key === open ? setOpen(null) : setOpen(key));
return (
<Box fontSize="12px" {...rest}>
{/*
It's important to include the rest of the props
because in certain cases we want to add/adjust spacing,
eg if this is contained in <Stack> it will add
spacing automatically
A pattern we're trying to follow is that these components
will not have margin in and of themselves. No component should
have default whitespace
*/}
{content.map(({ title, body }, key) => {
return (
<CollapseItem
key={key}
id={key}
title={title}
body={body}
open={open}
handleOpen={handleOpen}
/>
);
})}
</Box>
);
};
11 changes: 11 additions & 0 deletions app/components/seed-textarea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from 'styled-components';

export const SeedTextarea = styled.textarea`
width: 100%;
resize: none;
text-align: center;
overflow: hidden;
&:focus {
outline: 0;
}
`;
14 changes: 14 additions & 0 deletions app/components/success-checkmark.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

export const SuccessCheckmark: React.FC = () => (
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20">
<circle cx="10" cy="10" r="8" fill="#00A73E"></circle>
<path
stroke="#fff"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
d="M7.667 10.667l2 1.333 2.666-4"
></path>
</svg>
);
Loading

0 comments on commit 6a1d69d

Please sign in to comment.