From 48052fc3e4ac80140dcfc59c0cca944592e93859 Mon Sep 17 00:00:00 2001 From: Fred Carlsen Date: Fri, 21 Jun 2019 10:53:03 +0200 Subject: [PATCH] WIP docs --- packages/website/package.json | 4 + .../website/ts/components/docs/callout.tsx | 79 +++++++ .../ts/components/docs/community_link.tsx | 54 +++++ .../website/ts/components/docs/header.tsx | 220 ++++++++++++++++++ packages/website/ts/components/docs/hero.tsx | 51 ++++ .../ts/components/docs/search_input.tsx | 86 +++++++ .../ts/components/docs/shortcut_link.tsx | 51 ++++ .../website/ts/components/docs/siteWrap.tsx | 159 +++++++++++++ .../website/ts/components/docs/step_link.tsx | 55 +++++ .../website/ts/components/docs/step_links.tsx | 36 +++ .../ts/components/docs/tutorial_steps.tsx | 49 ++++ packages/website/ts/globals.d.ts | 5 + .../icons/illustrations/0x-coreConcepts.svg | 17 ++ .../ts/icons/illustrations/apiExplorer.svg | 17 ++ .../website/ts/icons/illustrations/tools.svg | 18 ++ packages/website/ts/index.tsx | 2 + packages/website/ts/pages/docs/home.tsx | 161 +++++++++++++ .../website/ts/pages/docs/page_template.tsx | 134 +++++++++++ 18 files changed, 1198 insertions(+) create mode 100644 packages/website/ts/components/docs/callout.tsx create mode 100644 packages/website/ts/components/docs/community_link.tsx create mode 100644 packages/website/ts/components/docs/header.tsx create mode 100644 packages/website/ts/components/docs/hero.tsx create mode 100644 packages/website/ts/components/docs/search_input.tsx create mode 100644 packages/website/ts/components/docs/shortcut_link.tsx create mode 100644 packages/website/ts/components/docs/siteWrap.tsx create mode 100644 packages/website/ts/components/docs/step_link.tsx create mode 100644 packages/website/ts/components/docs/step_links.tsx create mode 100644 packages/website/ts/components/docs/tutorial_steps.tsx create mode 100644 packages/website/ts/icons/illustrations/0x-coreConcepts.svg create mode 100644 packages/website/ts/icons/illustrations/apiExplorer.svg create mode 100644 packages/website/ts/icons/illustrations/tools.svg create mode 100644 packages/website/ts/pages/docs/home.tsx create mode 100644 packages/website/ts/pages/docs/page_template.tsx 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) => ( + <> + + + + +); + +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} +
+ +