This commit is contained in:
Fred Carlsen
2019-06-21 10:53:03 +02:00
committed by fabioberger
parent 5ac5fed513
commit 48052fc3e4
18 changed files with 1198 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
import { Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
import { Button } from 'ts/components/button';
import { SearchInput } from 'ts/components/docs/search_input';
import { Icon } from 'ts/components/icon';
import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { Heading, Paragraph } from 'ts/components/text';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
interface WrapperProps {
type?: 'standard' | 'alert' | 'success';
}
export interface CalloutConfig extends WrapperProps {
text: string;
}
const ThemeSettings = {
success: {
bgColor: 'rgba(0, 174, 153, 0.1)',
icon: (
<svg width="28" height="28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 27c7.18 0 13-5.82 13-13S21.18 1 14 1 1 6.82 1 14s5.82 13 13 13z" stroke="#00AE99" strokeWidth="1.054" strokeMiterlimit="10"/>
<path d="M14.002 26.977c7.167 0 12.977-5.81 12.977-12.976 0-7.166-5.81-12.976-12.976-12.976-7.167 0-12.977 5.81-12.977 12.976 0 7.167 5.81 12.976 12.976 12.976z" stroke="#003831" strokeWidth="1.5" strokeMiterlimit="10"/>
<path d="M9 14.667L12.125 18 19 10" stroke="#003831" strokeWidth="1.5"/>
</svg>
)
},
standard: {
bgColor: '#F2F2F2',
icon: (
<svg width="28" height="28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 27c7.18 0 13-5.82 13-13S21.18 1 14 1 1 6.82 1 14s5.82 13 13 13z" stroke="#00AE99" strokeWidth="1.054" strokeMiterlimit="10"/>
<path d="M14.002 26.977c7.167 0 12.977-5.81 12.977-12.976 0-7.166-5.81-12.976-12.976-12.976-7.167 0-12.977 5.81-12.977 12.976 0 7.167 5.81 12.976 12.976 12.976z" stroke="#003831" strokeWidth="1.5" strokeMiterlimit="10"/>
<path d="M15.298 9.494V7.641h-1.972v1.853h1.972zm-.034 1.853h-1.921V20h1.921v-8.653z" fill="#003831"/>
</svg>
)
},
alert: {
bgColor: '#FFFAF3',
icon: (
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.0025 26.9774C21.169 26.9774 26.9786 21.1678 26.9786 14.0013C26.9786 6.83476 21.169 1.02515 14.0025 1.02515C6.83598 1.02515 1.02637 6.83476 1.02637 14.0013C1.02637 21.1678 6.83598 26.9774 14.0025 26.9774Z" stroke="#EA9928" strokeWidth="1.5" strokeMiterlimit="10"/>
<path d="M12.819 7.862V12.826L13.176 16.566H14.417L14.774 12.826V7.862H12.819ZM14.893 20V17.722H12.7V20H14.893Z" fill="#EA9928"/>
</svg>
)
},
}
export const Callout: React.FunctionComponent<CalloutConfig> = ({ type, text }: CalloutConfig) => (
<Wrapper type={type}>
{ThemeSettings[type].icon}
<Text>{text}</Text>
</Wrapper>
);
Callout.defaultProps = {
type: 'standard',
};
const Wrapper = styled.a<WrapperProps>`
background-color: ${props => ThemeSettings[props.type].bgColor};
color: ${colors.textDarkPrimary};
padding: 1rem 1rem 1rem 1rem;
display: flex;
align-items: center;
margin-bottom: 1rem;
`;
const Text = styled.span`
font-size: 1rem;
margin-left: 1rem;
`;

View File

@@ -0,0 +1,54 @@
import { Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
import { Button } from 'ts/components/button';
import { SearchInput } from 'ts/components/docs/search_input';
import { Icon } from 'ts/components/icon';
import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { Heading, Paragraph } from 'ts/components/text';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
export interface CommunityLinkProps {
heading: string;
icon: string;
description?: string;
url: string;
shouldOpenInNewTab?: boolean;
isHome?: boolean;
}
interface WrapperProps {
isHome?: boolean;
}
export const CommunityLink: React.FunctionComponent<CommunityLinkProps> = (props: CommunityLinkProps) => (
<>
<Wrapper isHome={props.isHome} href={props.url}>
<div>
<Icon color={colors.brandLight} name={props.icon} size={100} margin={[0, 0, 24, 0]} />
<Heading size="small" marginBottom="8px">{props.heading}</Heading>
<Paragraph size="default" marginBottom="0">{props.description}</Paragraph>
</div>
</Wrapper>
</>
);
CommunityLink.defaultProps = {
isHome: false,
};
const Wrapper = styled.a<WrapperProps>`
background-color: ${colors.backgroundLight};
border: 1px solid #DBDFDD;
padding: 50px 50px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
`;

View File

@@ -0,0 +1,220 @@
import { Link } from '@0x/react-shared';
import _ from 'lodash';
import * as React from 'react';
import MediaQuery from 'react-responsive';
import styled, { css, withTheme } from 'styled-components';
import Headroom from 'react-headroom';
import { SearchInput } from 'ts/components/docs/search_input';
import { Hamburger } from 'ts/components/hamburger';
import { Logo } from 'ts/components/logo';
import { MobileNav } from 'ts/components/mobileNav';
import { FlexWrap } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
interface HeaderProps {
location?: Location;
isNavToggled?: boolean;
toggleMobileNav?: () => void;
theme: ThemeValuesInterface;
}
interface NavItemProps {
url?: string;
id?: string;
text?: string;
dropdownWidth?: number;
dropdownComponent?: React.FunctionComponent<any>;
}
interface DropdownWrapInterface {
width?: number;
}
const navItems: NavItemProps[] = [
{
id: 'why',
url: WebsitePaths.Why,
text: 'Core Concepts',
},
{
id: 'api-explorer',
url: WebsitePaths.AboutMission,
text: 'API Explorer',
},
{
id: 'tutorials',
url: WebsitePaths.AboutMission,
text: 'Tutorials',
},
{
id: 'tools',
url: WebsitePaths.AboutMission,
text: 'Tools',
},
];
class HeaderBase extends React.Component<HeaderProps> {
public onUnpin = () => {
if (this.props.isNavToggled) {
this.props.toggleMobileNav();
}
};
public render(): React.ReactNode {
const { isNavToggled, toggleMobileNav, theme } = this.props;
return (
<Headroom
onUnpin={this.onUnpin}
downTolerance={4}
upTolerance={10}
wrapperStyle={{ position: 'relative', zIndex: 2 }}
>
<StyledHeader isNavToggled={isNavToggled}>
<HeaderWrap>
<LogoWrap>
<Link to={WebsitePaths.Home}>
<Logo />
</Link>
<DocsLogo />
</LogoWrap>
<NavLinks>
{_.map(navItems, (link, index) => (
<NavItem key={`navlink-${index}`} link={link} />
))}
</NavLinks>
<MediaQuery minWidth={990}>
<SearchInput isHome={false} />
</MediaQuery>
<Hamburger isOpen={isNavToggled} onClick={toggleMobileNav} />
<MobileNav isToggled={isNavToggled} toggleMobileNav={toggleMobileNav} />
</HeaderWrap>
</StyledHeader>
</Headroom>
);
}
}
export const Header = withTheme(HeaderBase);
const NavItem = (props: { link: NavItemProps; key: string }) => {
const { link } = props;
const Subnav = link.dropdownComponent;
const linkElement =
link.url === undefined ? (
<StyledAnchor href="#">{link.text}</StyledAnchor>
) : (
<StyledNavLink to={link.url}>{link.text}</StyledNavLink>
);
return (
<LinkWrap>
{linkElement}
</LinkWrap>
);
};
const DocsLogo = () => {
return (
<DocsLogoWrap>
/ <DocsLogoLink to={WebsitePaths.Docs}>Docs</DocsLogoLink>
</DocsLogoWrap>
);
};
const StyledHeader = styled.header<HeaderProps>`
padding: 30px;
background-color: ${props => colors.backgroundLight};
`;
const DocsLogoWrap = styled.div`
position: relative;
display: flex;
align-items: center;
font-size: 1.411764706rem;
color: rgba(0, 0, 0, 0.5);
margin-left: 0.875rem;
a {
display: block;
}
`;
const DocsLogoLink = styled(Link)`
font-size: inherit;
color: inherit;
margin-left: 0.625rem;
`;
const LinkWrap = styled.li`
position: relative;
a {
display: block;
}
@media (min-width: 800px) {
&:hover > div {
display: block;
visibility: visible;
opacity: 1;
transform: translate3d(0, 0, 0);
transition: opacity 0.35s, transform 0.35s, visibility 0s;
}
}
`;
const linkStyles = css`
color: ${props => props.theme.textColor};
opacity: 0.5;
transition: opacity 0.35s;
padding: 15px 0;
margin: 0 30px;
&:hover {
opacity: 1;
}
`;
const StyledNavLink = styled(Link).attrs({
activeStyle: { opacity: 1 },
})`
${linkStyles};
`;
const StyledAnchor = styled.a`
${linkStyles};
cursor: default;
`;
const HeaderWrap = styled(FlexWrap)`
justify-content: space-between;
align-items: center;
@media (max-width: 800px) {
padding-top: 0;
display: flex;
padding-bottom: 0;
}
`;
const NavLinks = styled.ul`
display: flex;
align-items: center;
justify-content: space-between;
@media (max-width: 800px) {
display: none;
}
`;
const LogoWrap = styled.div`
display: flex;
align-items: center;
`;

View File

@@ -0,0 +1,51 @@
import { Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
import { Button } from 'ts/components/button';
import { SearchInput } from 'ts/components/docs/search_input';
import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { Heading, Paragraph } from 'ts/components/text';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
interface Props {
isHome?: boolean;
title?: string;
description?: string;
}
interface LinkConfig {
label: string;
url: string;
shouldOpenInNewTab?: boolean;
}
export const Hero: React.FunctionComponent<Props> = (props: Props) => (
<>
<Wrapper isHome={props.isHome}>
<Heading size="large" isCentered={true} marginBottom={props.isHome || props.description ? '30px' : '0'}>{props.title}</Heading>
{props.description && <Paragraph isCentered={true}>{props.description}</Paragraph>}
{props.isHome && <SearchInput isHome={true} />}
</Wrapper>
</>
);
Hero.defaultProps = {
isHome: false,
};
const Wrapper = styled.div<Props>`
background-color: ${colors.backgroundLight};
padding-top: ${props => props.isHome && `63px`};
padding-bottom: 80px;
margin-bottom: 60px;
min-height: 15rem;
min-height: 21.875rem;
display: flex;
flex-direction: column;
justify-content: center;
`;

View File

@@ -0,0 +1,86 @@
import { Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
import { Button } from 'ts/components/button';
import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { Heading } from 'ts/components/text';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
interface Props {
isHome?: boolean;
}
interface LinkConfig {
label: string;
url: string;
shouldOpenInNewTab?: boolean;
}
export const SearchInput: React.FunctionComponent<Props> = (props: Props) => (
<>
<Wrapper isHome={props.isHome}>
<Label>
<LabelText>Search query</LabelText>
<Input isHome={props.isHome} />
</Label>
</Wrapper>
</>
);
SearchInput.defaultProps = {
isHome: false,
};
const Wrapper = styled.div<Props>`
width: 100%;
max-width: 240px;
${props => props.isHome && `
max-width: 890px;
margin: 0 auto;
`};
`;
const Label = styled.label`
position: relative;
`;
const LabelText = styled.span`
position: absolute;
opacity: 0;
visibility: hidden;
`;
const Input = styled.input.attrs({
placeholder: 'Search docs...',
})<Props>`
background: transparent left center url("data:image/svg+xml,%3Csvg width='24' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' fill-opacity='.01' d='M0 0h24v24H0z'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M5 10.5a5.5 5.5 0 1 1 11 0 5.5 5.5 0 0 1-11 0zM10.5 3a7.5 7.5 0 1 0 4.55 13.463l4.743 4.744 1.414-1.414-4.744-4.744A7.5 7.5 0 0 0 10.5 3z' fill='%235C5C5C'/%3E%3C/svg%3E") no-repeat ;
font-size: 1.375rem;
padding: 18px 18px 21px 35px;
width: 100%;
border: 0;
border-bottom: 1px solid #B4BEBD;
outline: none;
${props => !props.isHome && `
background-color: #EBEEEC;
border-bottom: 0;
padding: 13px 21px 15px 52px;
background-position: left 21px center;
font-size: 1.125rem;
`};
&:before {
content: '';
width: 30px;
height: 30px;
opacity: 0.15;
position: absolute;
top: 0;
left: 0;
}
`;

View File

@@ -0,0 +1,51 @@
import { Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
import { Button } from 'ts/components/button';
import { SearchInput } from 'ts/components/docs/search_input';
import { Icon } from 'ts/components/icon';
import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { Heading, Paragraph } from 'ts/components/text';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
export interface LinkProps {
heading: string;
icon: string;
description?: string;
url: string;
shouldOpenInNewTab?: boolean;
isHome?: boolean;
}
interface WrapperProps {
isHome?: boolean;
}
export const ShortcutLink: React.FunctionComponent<LinkProps> = (props: LinkProps) => (
<>
<Wrapper isHome={props.isHome} href={props.url}>
<Icon color={colors.brandLight} name={props.icon} size={80} margin={[0, 40, 0, 0]} />
<div>
<Heading size="small" marginBottom="8px">{props.heading}</Heading>
<Paragraph size="default" marginBottom="0">{props.description}</Paragraph>
</div>
</Wrapper>
</>
);
ShortcutLink.defaultProps = {
isHome: false,
};
const Wrapper = styled.a<WrapperProps>`
background-color: ${colors.backgroundLight};
border: 1px solid #DBDFDD;
padding: 50px 50px;
display: flex;
align-items: center;
`;

View File

@@ -0,0 +1,159 @@
import * as React from 'react';
import styled, { ThemeProvider } from 'styled-components';
import { colors } from 'ts/style/colors';
import { Header } from 'ts/components/docs/header';
import { Footer } from 'ts/components/footer';
import { GlobalStyles } from 'ts/constants/globalStyle';
interface Props {
theme?: 'dark' | 'light' | 'gray';
isFullScreen?: boolean;
children: any;
}
interface State {
isMobileNavOpen: boolean;
}
interface MainProps {
isNavToggled: boolean;
isFullScreen?: boolean;
}
export interface ThemeValuesInterface {
bgColor: string;
darkBgColor?: string;
lightBgColor: string;
introTextColor: string;
textColor: string;
paragraphColor: string;
linkColor: string;
mobileNavBgUpper: string;
mobileNavBgLower: string;
mobileNavColor: string;
dropdownBg: string;
dropdownButtonBg: string;
dropdownBorderColor?: string;
dropdownColor: string;
headerButtonBg: string;
footerBg: string;
footerColor: string;
}
export interface ThemeInterface {
[key: string]: ThemeValuesInterface;
}
const GLOBAL_THEMES: ThemeInterface = {
dark: {
bgColor: '#000000',
darkBgColor: '#111A19',
lightBgColor: '#003831',
introTextColor: 'rgba(255, 255, 255, 0.75)',
textColor: '#FFFFFF',
paragraphColor: '#FFFFFF',
linkColor: colors.brandLight,
mobileNavBgUpper: '#003831',
mobileNavBgLower: '#022924',
mobileNavColor: '#FFFFFF',
dropdownBg: '#111A19',
dropdownButtonBg: '#003831',
dropdownColor: '#FFFFFF',
headerButtonBg: '#00AE99',
footerBg: '#181818',
footerColor: '#FFFFFF',
},
light: {
bgColor: '#FFFFFF',
lightBgColor: '#F3F6F4',
darkBgColor: '#003831',
introTextColor: 'rgba(92, 92, 92, 0.87)',
textColor: '#000000',
paragraphColor: '#474747',
linkColor: colors.brandDark,
mobileNavBgUpper: '#FFFFFF',
mobileNavBgLower: '#F3F6F4',
mobileNavColor: '#000000',
dropdownBg: '#FBFBFB',
dropdownButtonBg: '#F3F6F4',
dropdownColor: '#003831',
dropdownBorderColor: '#E4E4E4',
headerButtonBg: '#003831',
footerBg: '#F2F2F2',
footerColor: '#000000',
},
gray: {
bgColor: '#e0e0e0',
lightBgColor: '#003831',
introTextColor: 'rgba(92, 92, 92, 0.87)',
textColor: '#000000',
paragraphColor: '#777777',
linkColor: colors.brandDark,
mobileNavBgUpper: '#FFFFFF',
mobileNavBgLower: '#F3F6F4',
mobileNavColor: '#000000',
dropdownBg: '#FFFFFF',
dropdownButtonBg: '#F3F6F4',
dropdownColor: '#003831',
headerButtonBg: '#003831',
footerBg: '#181818',
footerColor: '#FFFFFF',
},
};
export class SiteWrap extends React.Component<Props, State> {
public state = {
isMobileNavOpen: false,
};
public componentDidMount(): void {
document.documentElement.style.overflowY = 'auto';
window.scrollTo(0, 0);
}
public toggleMobileNav = () => {
this.setState({
isMobileNavOpen: !this.state.isMobileNavOpen,
});
};
public render(): React.ReactNode {
const { children, theme = 'dark', isFullScreen } = this.props;
const { isMobileNavOpen } = this.state;
const currentTheme = GLOBAL_THEMES[theme];
return (
<>
<ThemeProvider theme={currentTheme}>
<>
<GlobalStyles />
<Header isNavToggled={isMobileNavOpen} toggleMobileNav={this.toggleMobileNav} />
<Main isNavToggled={isMobileNavOpen} isFullScreen={isFullScreen}>
{children}
</Main>
<Footer />
</>
</ThemeProvider>
</>
);
}
}
const Main = styled.main<MainProps>`
transition: transform 0.5s, opacity 0.5s;
opacity: ${props => props.isNavToggled && '0.5'};
padding-bottom: 70px;
${props =>
props.isFullScreen &&
`
display: flex;
align-items: center;
min-height: calc(100vh - 108px - 381px);
`}
`;

View File

@@ -0,0 +1,55 @@
import { Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
import { Button } from 'ts/components/button';
import { SearchInput } from 'ts/components/docs/search_input';
import { Icon } from 'ts/components/icon';
import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { Heading, Paragraph } from 'ts/components/text';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
export interface StepLinkConfig {
title: string;
url: string;
shouldOpenInNewTab?: boolean;
}
interface WrapperProps {
}
export const StepLink: React.FunctionComponent<StepLinkConfig> = (props: StepLinkConfig) => (
<>
<Wrapper href={props.url}>
<Text>{props.title}</Text>
<svg width="14" height="14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" clipRule="evenodd" d="M2 0h11.5v11H12V2.62L1.06 13.56 0 12.5l11-11H2V0z" fill="currentColor"/>
</svg>
</Wrapper>
</>
);
const Wrapper = styled.a<WrapperProps>`
color: ${colors.brandDark};
padding: 21px 25px 19px;
display: flex;
align-items: center;
justify-content: space-between;
&:hover {
background-color: ${colors.brandDark};
color: ${colors.white};
}
& + & {
border-top: 1px solid #DBDFDD;
}
`;
const Text = styled.span`
font-size: 1.25rem;
`;

View File

@@ -0,0 +1,36 @@
import { Link } from '@0x/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
import { Button } from 'ts/components/button';
import { SearchInput } from 'ts/components/docs/search_input';
import { StepLink, StepLinkConfig } from 'ts/components/docs/step_link';
import { Icon } from 'ts/components/icon';
import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout';
import { ThemeValuesInterface } from 'ts/components/siteWrap';
import { Heading, Paragraph } from 'ts/components/text';
import { colors } from 'ts/style/colors';
import { WebsitePaths } from 'ts/types';
import { constants } from 'ts/utils/constants';
export interface LinkProps {
links: StepLinkConfig[];
}
export const StepLinks: React.FunctionComponent<LinkProps> = (props: LinkProps) => (
<>
<Wrapper>
{props.links.map((shortcut, index) => <StepLink key={`step-${index}`} {...shortcut} />)}
</Wrapper>
</>
);
StepLinks.defaultProps = {
links: [],
};
const Wrapper = styled.div`
background-color: ${colors.backgroundLight};
border: 1px solid #DBDFDD;
`;

View File

@@ -0,0 +1,49 @@
import * as _ from 'lodash';
import * as React from 'react';
import styled, { withTheme } from 'styled-components';
export interface Props {
children: React.ReactNode;
}
interface WrapperProps {
}
export const TutorialSteps: React.FunctionComponent<Props> = (props: Props) => (
<>
<Wrapper>
{props.children}
</Wrapper>
</>
);
TutorialSteps.defaultProps = {
};
const Wrapper = styled.ul<WrapperProps>`
list-style-type: none;
counter-reset: tutorialSteps;
margin-bottom: 16rem;
li {
font-size: 1rem;
display: flex;
align-items: center;
counter-increment: tutorialSteps;
margin-bottom: 1rem;
line-height: 1;
}
li:before {
border-radius: 50%;
background-color: rgba(0, 174, 153, 0.1);
content: counter(tutorialSteps);
display: flex;
justify-content: center;
font-feature-settings: 'tnum' on, 'lnum' on;
align-items: center;
width: 30px;
height: 30px;
margin-right: 1rem;
}
`;