diff --git a/packages/website/package.json b/packages/website/package.json
index 0ef0b3d81b..98fb3f57df 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -32,6 +32,8 @@
"@0x/utils": "^4.5.0",
"@0x/web3-wrapper": "^6.0.11",
"@reach/dialog": "^0.1.2",
+ "@reach/tabs": "^0.1.6",
+ "@types/body-scroll-lock": "^2.6.0",
"@types/react-lazyload": "^2.3.1",
"@types/react-loadable": "^5.4.2",
"@types/react-syntax-highlighter": "^0.0.8",
@@ -39,6 +41,7 @@
"accounting": "^0.4.1",
"basscss": "^8.0.3",
"blockies": "^0.0.2",
+ "body-scroll-lock": "^2.6.1",
"bowser": "^1.9.4",
"change-case": "^3.0.2",
"deep-equal": "^1.0.1",
@@ -92,6 +95,7 @@
},
"devDependencies": {
"@0x/tslint-config": "^3.0.1",
+ "@mdx-js/loader": "^1.0.0-rc.4",
"@types/accounting": "^0.4.1",
"@types/blockies": "^0.0.0",
"@types/deep-equal": "^1.0.0",
diff --git a/packages/website/ts/components/docs/callout.tsx b/packages/website/ts/components/docs/callout.tsx
new file mode 100644
index 0000000000..dd5790e6ab
--- /dev/null
+++ b/packages/website/ts/components/docs/callout.tsx
@@ -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: (
+
+
+
+
+
+ )
+ },
+ standard: {
+ bgColor: '#F2F2F2',
+ icon: (
+
+
+
+
+
+ )
+ },
+ alert: {
+ bgColor: '#FFFAF3',
+ icon: (
+
+
+
+
+ )
+ },
+}
+
+export const Callout: React.FunctionComponent = ({ type, text }: CalloutConfig) => (
+
+ {ThemeSettings[type].icon}
+ {text}
+
+);
+
+Callout.defaultProps = {
+ type: 'standard',
+};
+
+const Wrapper = styled.a`
+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;
+`;
diff --git a/packages/website/ts/components/docs/community_link.tsx b/packages/website/ts/components/docs/community_link.tsx
new file mode 100644
index 0000000000..8a1813483e
--- /dev/null
+++ b/packages/website/ts/components/docs/community_link.tsx
@@ -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 = (props: CommunityLinkProps) => (
+ <>
+
+
+
+
{props.heading}
+
{props.description}
+
+
+ >
+);
+
+CommunityLink.defaultProps = {
+ isHome: false,
+};
+
+const Wrapper = styled.a`
+ 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;
+`;
diff --git a/packages/website/ts/components/docs/header.tsx b/packages/website/ts/components/docs/header.tsx
new file mode 100644
index 0000000000..f0a71f1b67
--- /dev/null
+++ b/packages/website/ts/components/docs/header.tsx
@@ -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;
+}
+
+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 {
+ public onUnpin = () => {
+ if (this.props.isNavToggled) {
+ this.props.toggleMobileNav();
+ }
+ };
+
+ public render(): React.ReactNode {
+ const { isNavToggled, toggleMobileNav, theme } = this.props;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {_.map(navItems, (link, index) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export const Header = withTheme(HeaderBase);
+
+const NavItem = (props: { link: NavItemProps; key: string }) => {
+ const { link } = props;
+ const Subnav = link.dropdownComponent;
+ const linkElement =
+ link.url === undefined ? (
+ {link.text}
+ ) : (
+ {link.text}
+ );
+ return (
+
+ {linkElement}
+
+ );
+};
+
+const DocsLogo = () => {
+ return (
+
+ / Docs
+
+ );
+};
+
+const StyledHeader = styled.header`
+ 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;
+`;
diff --git a/packages/website/ts/components/docs/hero.tsx b/packages/website/ts/components/docs/hero.tsx
new file mode 100644
index 0000000000..a1fc88f90d
--- /dev/null
+++ b/packages/website/ts/components/docs/hero.tsx
@@ -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.title}
+ {props.description && {props.description} }
+ {props.isHome && }
+
+ >
+);
+
+Hero.defaultProps = {
+ isHome: false,
+};
+
+const Wrapper = styled.div`
+ 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;
+`;
diff --git a/packages/website/ts/components/docs/search_input.tsx b/packages/website/ts/components/docs/search_input.tsx
new file mode 100644
index 0000000000..3ac0782fdf
--- /dev/null
+++ b/packages/website/ts/components/docs/search_input.tsx
@@ -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) => (
+ <>
+
+
+ Search query
+
+
+
+ >
+);
+
+SearchInput.defaultProps = {
+ isHome: false,
+};
+
+const Wrapper = styled.div`
+ 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...',
+})`
+ 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;
+ }
+`;
diff --git a/packages/website/ts/components/docs/shortcut_link.tsx b/packages/website/ts/components/docs/shortcut_link.tsx
new file mode 100644
index 0000000000..96762857f2
--- /dev/null
+++ b/packages/website/ts/components/docs/shortcut_link.tsx
@@ -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 = (props: LinkProps) => (
+ <>
+
+
+
+
{props.heading}
+
{props.description}
+
+
+ >
+);
+
+ShortcutLink.defaultProps = {
+ isHome: false,
+};
+
+const Wrapper = styled.a`
+ background-color: ${colors.backgroundLight};
+ border: 1px solid #DBDFDD;
+ padding: 50px 50px;
+ display: flex;
+ align-items: center;
+`;
diff --git a/packages/website/ts/components/docs/siteWrap.tsx b/packages/website/ts/components/docs/siteWrap.tsx
new file mode 100644
index 0000000000..4ce9be4041
--- /dev/null
+++ b/packages/website/ts/components/docs/siteWrap.tsx
@@ -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 {
+ 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 (
+ <>
+
+ <>
+
+
+
+
+
+ {children}
+
+
+
+ >
+
+ >
+ );
+ }
+}
+
+const Main = styled.main`
+ 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);
+ `}
+`;
diff --git a/packages/website/ts/components/docs/step_link.tsx b/packages/website/ts/components/docs/step_link.tsx
new file mode 100644
index 0000000000..dc8d90bfdb
--- /dev/null
+++ b/packages/website/ts/components/docs/step_link.tsx
@@ -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 = (props: StepLinkConfig) => (
+ <>
+
+ {props.title}
+
+
+
+
+ >
+);
+
+const Wrapper = styled.a`
+ 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;
+`;
diff --git a/packages/website/ts/components/docs/step_links.tsx b/packages/website/ts/components/docs/step_links.tsx
new file mode 100644
index 0000000000..a68a59eabb
--- /dev/null
+++ b/packages/website/ts/components/docs/step_links.tsx
@@ -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 = (props: LinkProps) => (
+ <>
+
+ {props.links.map((shortcut, index) => )}
+
+ >
+);
+
+StepLinks.defaultProps = {
+ links: [],
+};
+
+const Wrapper = styled.div`
+ background-color: ${colors.backgroundLight};
+ border: 1px solid #DBDFDD;
+`;
diff --git a/packages/website/ts/components/docs/tutorial_steps.tsx b/packages/website/ts/components/docs/tutorial_steps.tsx
new file mode 100644
index 0000000000..112ce6f27b
--- /dev/null
+++ b/packages/website/ts/components/docs/tutorial_steps.tsx
@@ -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.children}
+
+ >
+);
+
+TutorialSteps.defaultProps = {
+};
+
+const Wrapper = styled.ul`
+ 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;
+ }
+`;
diff --git a/packages/website/ts/globals.d.ts b/packages/website/ts/globals.d.ts
index 341f8b8a59..80d69e7de1 100644
--- a/packages/website/ts/globals.d.ts
+++ b/packages/website/ts/globals.d.ts
@@ -20,6 +20,11 @@ declare module '*.json' {
/* tslint:enable */
}
+declare module '*.mdx' {
+ let MDXComponent: (props) => JSX.Element;
+ export default MDXComponent;
+}
+
declare module '*.svg' {
import { PureComponent, SVGProps } from 'react';
export default class extends PureComponent> {}
diff --git a/packages/website/ts/icons/illustrations/0x-coreConcepts.svg b/packages/website/ts/icons/illustrations/0x-coreConcepts.svg
new file mode 100644
index 0000000000..a06cc1cfc7
--- /dev/null
+++ b/packages/website/ts/icons/illustrations/0x-coreConcepts.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/website/ts/icons/illustrations/apiExplorer.svg b/packages/website/ts/icons/illustrations/apiExplorer.svg
new file mode 100644
index 0000000000..252637d98a
--- /dev/null
+++ b/packages/website/ts/icons/illustrations/apiExplorer.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/website/ts/icons/illustrations/tools.svg b/packages/website/ts/icons/illustrations/tools.svg
new file mode 100644
index 0000000000..040aad717a
--- /dev/null
+++ b/packages/website/ts/icons/illustrations/tools.svg
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx
index cc3f062aaa..1fc8027924 100644
--- a/packages/website/ts/index.tsx
+++ b/packages/website/ts/index.tsx
@@ -10,6 +10,7 @@ import { Wiki } from 'ts/containers/wiki';
import { createLazyComponent } from 'ts/lazy_component';
import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
+import { DocsPageTemplate } from 'ts/pages/docs/page_template';
import { store } from 'ts/redux/store';
import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
import { muiTheme } from 'ts/utils/mui_theme';
@@ -217,6 +218,7 @@ render(
path={`${WebsitePaths.AssetSwapperDocs}/:version?`}
component={LazyAssetSwapperDocumentation}
/>
+
{/* Legacy endpoints */}
{
+ public state = {
+ };
+ public componentDidMount(): void {
+ }
+ public render(): React.ReactNode {
+ return (
+
+
+
+
+
+ {shortcuts.map((shortcut, index) => )}
+
+
+
+
+ Get Started
+
+
+ Useful Links
+
+
+
+
+
+ {communityShortcuts.map((shortcut, index) => )}
+
+
+
+ );
+ }
+}
+
+const ShortcutsWrapper = styled.div`
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-column-gap: 30px;
+ grid-row-gap: 30px;
+`;
+
+const CommunityWrapper = styled.div`
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ grid-column-gap: 30px;
+ grid-row-gap: 30px;
+`;
+
+const Columns = styled.div<{ count?: number }>`
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-column-gap: 70px;
+ grid-row-gap: 30px;
+`;
+
+Columns.defaultProps = {
+ count: 2,
+};
+
+const Separator = styled.hr`
+ border-width: 0 0 1px;
+ border-color: #E4E4E4;
+ height: 0;
+ margin-top: 60px;
+ margin-bottom: 60px;
+`;
diff --git a/packages/website/ts/pages/docs/page_template.tsx b/packages/website/ts/pages/docs/page_template.tsx
new file mode 100644
index 0000000000..65b1e49cc2
--- /dev/null
+++ b/packages/website/ts/pages/docs/page_template.tsx
@@ -0,0 +1,134 @@
+import { utils as sharedUtils } from '@0x/react-shared';
+import * as _ from 'lodash';
+import * as React from 'react';
+import styled, { keyframes } from 'styled-components';
+
+import { Callout } from 'ts/components/docs/callout';
+import { CommunityLink, CommunityLinkProps } from 'ts/components/docs/community_link';
+import { Hero } from 'ts/components/docs/hero';
+import { SearchInput } from 'ts/components/docs/search_input';
+import { LinkProps, ShortcutLink } from 'ts/components/docs/shortcut_link';
+import { SiteWrap } from 'ts/components/docs/siteWrap';
+import { StepLinkConfig } from 'ts/components/docs/step_link';
+import { StepLinks } from 'ts/components/docs/step_links';
+import { TutorialSteps } from 'ts/components/docs/tutorial_steps';
+import { DocumentTitle } from 'ts/components/document_title';
+import { Section, SectionProps } from 'ts/components/newLayout';
+import { Heading, Paragraph } from 'ts/components/text';
+import { colors } from 'ts/style/colors';
+import { WebsitePaths } from 'ts/types';
+import { documentConstants } from 'ts/utils/document_meta_constants';
+
+interface Props {
+ location: Location;
+ theme: {
+ bgColor: string;
+ textColor: string;
+ linkColor: string;
+ };
+}
+
+const usefulLinks: StepLinkConfig[] = [
+ {
+ title: 'Core Concepts',
+ url: '/docs/core-concepts',
+ },
+ {
+ title: 'API Explorer',
+ url: '/docs/core-concepts',
+ },
+ {
+ title: 'Guides',
+ url: '/docs/get-started',
+ },
+ {
+ title: 'Tools',
+ url: '/docs/core-concepts',
+ },
+];
+
+export class DocsPageTemplate extends React.Component {
+ public render(): React.ReactNode {
+ return (
+
+
+
+
+
+
+
+ Large Heading
+ Large Heading
+ Notifications
+
+
+
+ Tutorial Steps
+
+ Step 1
+ Step 2
+ Step 3
+
+ Standard Heading
+
+ This would be paragraph text.
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat velit in nisl varius malesuada. Morbi at porttitor enim. Donec vel tristique dolor, quis convallis sapien. Nam et massa tempus, dignissim leo vitae, ultricies libero. Vivamus eu enim tellus. Phasellus eu mattis elit. Proin ut eleifend urna, sed tincidunt nunc. Sed eu dapibus metus, in congue ipsum. Duis volutpat sem et sem faucibus blandit. Nullam ultricies ante eu elit auctor, id mattis nunc euismod. Curabitur arcu enim, cursus ac pellentesque quis, accumsan sit amet turpis. Praesent dignissim mi a maximus euismod
+
+
+ And here is a table:
+
+ Subheading
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec consequat velit in nisl varius malesuada. Morbi at porttitor enim. Donec vel tristique dolor, quis convallis sapien. Nam et massa tempus, dignissim leo vitae, ultricies libero. Vivamus eu enim tellus. Phasellus eu mattis elit. Proin ut eleifend urna, sed tincidunt nunc. Sed eu dapibus metus, in congue ipsum. Duis volutpat sem et sem faucibus blandit. Nullam ultricies ante eu elit auctor, id mattis nunc euismod. Curabitur arcu enim, cursus ac pellentesque quis, accumsan sit amet turpis. Praesent dignissim mi a maximus euismod
+
+
+ List items
+ List items
+ List items
+ List items
+
+ Tabbed Code Snippet
+ Run Code Snippet
+ Next Steps
+
+
+
+
+
+ );
+ }
+}
+
+const Columns = styled.div<{ count?: number }>`
+ display: grid;
+ grid-template-columns: 314px 1fr;
+ grid-column-gap: 40px;
+ grid-row-gap: 30px;
+`;
+
+Columns.defaultProps = {
+ count: 2,
+};
+
+const Separator = styled.hr`
+ border-width: 0 0 1px;
+ border-color: #E4E4E4;
+ height: 0;
+ margin-top: 60px;
+ margin-bottom: 60px;
+`;
+
+const LargeHeading = styled(Heading).attrs({
+ asElement: 'h1',
+})`
+ font-size: 2.125rem !important;
+`;
+
+const LargeIntro = styled(Paragraph).attrs({
+ size: 'medium',
+})`
+`;