diff options
author | Fabio Berger <me@fabioberger.com> | 2017-11-28 00:05:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-28 00:05:47 +0800 |
commit | 48b3d8526560d389e74beb12bbd64b7be6e9268f (patch) | |
tree | 00ae6e24314793cd303b154ede4fe4f55c654e84 /packages/website/ts/pages/shared | |
parent | b5ce876327fe6443364837ea65cf28ec0e371949 (diff) | |
parent | ecfee00feca331ee1efa55165471d79774cb03d2 (diff) | |
download | dexon-0x-contracts-48b3d8526560d389e74beb12bbd64b7be6e9268f.tar.gz dexon-0x-contracts-48b3d8526560d389e74beb12bbd64b7be6e9268f.tar.zst dexon-0x-contracts-48b3d8526560d389e74beb12bbd64b7be6e9268f.zip |
Merge pull request #237 from 0xProject/addWebsite
Add Website to Mono Repo
Diffstat (limited to 'packages/website/ts/pages/shared')
6 files changed, 454 insertions, 0 deletions
diff --git a/packages/website/ts/pages/shared/anchor_title.tsx b/packages/website/ts/pages/shared/anchor_title.tsx new file mode 100644 index 000000000..dfa9401ae --- /dev/null +++ b/packages/website/ts/pages/shared/anchor_title.tsx @@ -0,0 +1,98 @@ +import * as React from 'react'; +import {Styles, HeaderSizes} from 'ts/types'; +import {utils} from 'ts/utils/utils'; +import {constants} from 'ts/utils/constants'; +import {Link as ScrollLink} from 'react-scroll'; + +const headerSizeToScrollOffset: {[headerSize: string]: number} = { + h2: -20, + h3: 0, +}; + +interface AnchorTitleProps { + title: string|React.ReactNode; + id: string; + headerSize: HeaderSizes; + shouldShowAnchor: boolean; +} + +interface AnchorTitleState { + isHovering: boolean; +} + +const styles: Styles = { + anchor: { + fontSize: 20, + transform: 'rotate(45deg)', + cursor: 'pointer', + }, + headers: { + WebkitMarginStart: 0, + WebkitMarginEnd: 0, + fontWeight: 'bold', + display: 'block', + }, + h1: { + fontSize: '1.8em', + WebkitMarginBefore: '0.83em', + WebkitMarginAfter: '0.83em', + }, + h2: { + fontSize: '1.5em', + WebkitMarginBefore: '0.83em', + WebkitMarginAfter: '0.83em', + }, + h3: { + fontSize: '1.17em', + WebkitMarginBefore: '1em', + WebkitMarginAfter: '1em', + }, +}; + +export class AnchorTitle extends React.Component<AnchorTitleProps, AnchorTitleState> { + constructor(props: AnchorTitleProps) { + super(props); + this.state = { + isHovering: false, + }; + } + public render() { + let opacity = 0; + if (this.props.shouldShowAnchor) { + if (this.state.isHovering) { + opacity = 0.6; + } else { + opacity = 1; + } + } + return ( + <div className="relative flex" style={{...styles[this.props.headerSize], ...styles.headers}}> + <div + className="inline-block" + style={{paddingRight: 4}} + > + {this.props.title} + </div> + <ScrollLink + to={this.props.id} + offset={headerSizeToScrollOffset[this.props.headerSize]} + duration={constants.DOCS_SCROLL_DURATION_MS} + containerId={constants.DOCS_CONTAINER_ID} + > + <i + className="zmdi zmdi-link" + onClick={utils.setUrlHash.bind(utils, this.props.id)} + style={{...styles.anchor, opacity}} + onMouseOver={this.setHoverState.bind(this, true)} + onMouseOut={this.setHoverState.bind(this, false)} + /> + </ScrollLink> + </div> + ); + } + private setHoverState(isHovering: boolean) { + this.setState({ + isHovering, + }); + } +} diff --git a/packages/website/ts/pages/shared/markdown_code_block.tsx b/packages/website/ts/pages/shared/markdown_code_block.tsx new file mode 100644 index 000000000..621e5b606 --- /dev/null +++ b/packages/website/ts/pages/shared/markdown_code_block.tsx @@ -0,0 +1,20 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import * as HighLight from 'react-highlight'; + +interface MarkdownCodeBlockProps { + literal: string; + language: string; +} + +export function MarkdownCodeBlock(props: MarkdownCodeBlockProps) { + return ( + <span style={{fontSize: 16}}> + <HighLight + className={props.language || 'js'} + > + {props.literal} + </HighLight> + </span> + ); +} diff --git a/packages/website/ts/pages/shared/markdown_section.tsx b/packages/website/ts/pages/shared/markdown_section.tsx new file mode 100644 index 000000000..32b55abc8 --- /dev/null +++ b/packages/website/ts/pages/shared/markdown_section.tsx @@ -0,0 +1,77 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import * as ReactMarkdown from 'react-markdown'; +import {Element as ScrollElement} from 'react-scroll'; +import {AnchorTitle} from 'ts/pages/shared/anchor_title'; +import {utils} from 'ts/utils/utils'; +import {MarkdownCodeBlock} from 'ts/pages/shared/markdown_code_block'; +import RaisedButton from 'material-ui/RaisedButton'; +import {HeaderSizes} from 'ts/types'; + +interface MarkdownSectionProps { + sectionName: string; + markdownContent: string; + headerSize?: HeaderSizes; + githubLink?: string; +} + +interface MarkdownSectionState { + shouldShowAnchor: boolean; +} + +export class MarkdownSection extends React.Component<MarkdownSectionProps, MarkdownSectionState> { + public static defaultProps: Partial<MarkdownSectionProps> = { + headerSize: HeaderSizes.H3, + }; + constructor(props: MarkdownSectionProps) { + super(props); + this.state = { + shouldShowAnchor: false, + }; + } + public render() { + const sectionName = this.props.sectionName; + const id = utils.getIdFromName(sectionName); + return ( + <div + className="pt2 pr3 md-pl2 sm-pl3 overflow-hidden" + onMouseOver={this.setAnchorVisibility.bind(this, true)} + onMouseOut={this.setAnchorVisibility.bind(this, false)} + > + <ScrollElement name={id}> + <div className="clearfix"> + <div className="col lg-col-8 md-col-8 sm-col-12"> + <span style={{textTransform: 'capitalize'}}> + <AnchorTitle + headerSize={this.props.headerSize} + title={sectionName} + id={id} + shouldShowAnchor={this.state.shouldShowAnchor} + /> + </span> + </div> + <div className="col col-4 sm-hide xs-hide py2 right-align"> + {!_.isUndefined(this.props.githubLink) && + <RaisedButton + href={this.props.githubLink} + target="_blank" + label="Edit on Github" + icon={<i className="zmdi zmdi-github" style={{fontSize: 23}} />} + /> + } + </div> + </div> + <ReactMarkdown + source={this.props.markdownContent} + renderers={{CodeBlock: MarkdownCodeBlock}} + /> + </ScrollElement> + </div> + ); + } + private setAnchorVisibility(shouldShowAnchor: boolean) { + this.setState({ + shouldShowAnchor, + }); + } +} diff --git a/packages/website/ts/pages/shared/nested_sidebar_menu.tsx b/packages/website/ts/pages/shared/nested_sidebar_menu.tsx new file mode 100644 index 000000000..e69506bb8 --- /dev/null +++ b/packages/website/ts/pages/shared/nested_sidebar_menu.tsx @@ -0,0 +1,163 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import MenuItem from 'material-ui/MenuItem'; +import {colors} from 'material-ui/styles'; +import {utils} from 'ts/utils/utils'; +import {constants} from 'ts/utils/constants'; +import {VersionDropDown} from 'ts/pages/shared/version_drop_down'; +import {ZeroExJsDocSections, Styles, MenuSubsectionsBySection, Docs} from 'ts/types'; +import {typeDocUtils} from 'ts/utils/typedoc_utils'; +import {Link as ScrollLink} from 'react-scroll'; + +interface NestedSidebarMenuProps { + topLevelMenu: {[topLevel: string]: string[]}; + menuSubsectionsBySection: MenuSubsectionsBySection; + shouldDisplaySectionHeaders?: boolean; + onMenuItemClick?: () => void; + selectedVersion?: string; + versions?: string[]; + doc?: Docs; + isSectionHeaderClickable?: boolean; +} + +interface NestedSidebarMenuState {} + +const styles: Styles = { + menuItemWithHeaders: { + minHeight: 0, + }, + menuItemWithoutHeaders: { + minHeight: 48, + }, + menuItemInnerDivWithHeaders: { + lineHeight: 2, + }, +}; + +export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, NestedSidebarMenuState> { + public static defaultProps: Partial<NestedSidebarMenuProps> = { + shouldDisplaySectionHeaders: true, + onMenuItemClick: _.noop, + }; + public render() { + const navigation = _.map(this.props.topLevelMenu, (menuItems: string[], sectionName: string) => { + const finalSectionName = sectionName.replace(/-/g, ' '); + if (this.props.shouldDisplaySectionHeaders) { + const id = utils.getIdFromName(sectionName); + return ( + <div + key={`section-${sectionName}`} + className="py1" + > + <ScrollLink + to={id} + offset={-20} + duration={constants.DOCS_SCROLL_DURATION_MS} + containerId={constants.DOCS_CONTAINER_ID} + > + <div + style={{color: colors.grey500, cursor: 'pointer'}} + className="pb1" + > + {finalSectionName.toUpperCase()} + </div> + </ScrollLink> + {this.renderMenuItems(menuItems)} + </div> + ); + } else { + return ( + <div key={`section-${sectionName}`} > + {this.renderMenuItems(menuItems)} + </div> + ); + } + }); + return ( + <div> + {!_.isUndefined(this.props.versions) && + !_.isUndefined(this.props.selectedVersion) && + !_.isUndefined(this.props.doc) && + <VersionDropDown + selectedVersion={this.props.selectedVersion} + versions={this.props.versions} + doc={this.props.doc} + /> + } + {navigation} + </div> + ); + } + private renderMenuItems(menuItemNames: string[]): React.ReactNode[] { + const menuItemStyles = this.props.shouldDisplaySectionHeaders ? + styles.menuItemWithHeaders : + styles.menuItemWithoutHeaders; + const menuItemInnerDivStyles = this.props.shouldDisplaySectionHeaders ? + styles.menuItemInnerDivWithHeaders : {}; + const menuItems = _.map(menuItemNames, menuItemName => { + const id = utils.getIdFromName(menuItemName); + return ( + <div key={menuItemName}> + <ScrollLink + key={`menuItem-${menuItemName}`} + to={id} + offset={-10} + duration={constants.DOCS_SCROLL_DURATION_MS} + containerId={constants.DOCS_CONTAINER_ID} + > + <MenuItem + onTouchTap={this.onMenuItemClick.bind(this, menuItemName)} + style={menuItemStyles} + innerDivStyle={menuItemInnerDivStyles} + > + <span style={{textTransform: 'capitalize'}}> + {menuItemName} + </span> + </MenuItem> + </ScrollLink> + {this.renderMenuItemSubsections(menuItemName)} + </div> + ); + }); + return menuItems; + } + private renderMenuItemSubsections(menuItemName: string): React.ReactNode { + if (_.isUndefined(this.props.menuSubsectionsBySection[menuItemName])) { + return null; + } + return this.renderMenuSubsectionsBySection(menuItemName, this.props.menuSubsectionsBySection[menuItemName]); + } + private renderMenuSubsectionsBySection(menuItemName: string, entityNames: string[]): React.ReactNode { + return ( + <ul style={{margin: 0, listStyleType: 'none', paddingLeft: 0}} key={menuItemName}> + {_.map(entityNames, entityName => { + const id = utils.getIdFromName(entityName); + return ( + <li key={`menuItem-${entityName}`}> + <ScrollLink + to={id} + offset={0} + duration={constants.DOCS_SCROLL_DURATION_MS} + containerId={constants.DOCS_CONTAINER_ID} + onTouchTap={this.onMenuItemClick.bind(this, entityName)} + > + <MenuItem + onTouchTap={this.onMenuItemClick.bind(this, menuItemName)} + style={{minHeight: 35}} + innerDivStyle={{paddingLeft: 36, fontSize: 14, lineHeight: '35px'}} + > + {entityName} + </MenuItem> + </ScrollLink> + </li> + ); + })} + </ul> + ); + } + private onMenuItemClick(menuItemName: string): void { + const id = utils.getIdFromName(menuItemName); + utils.setUrlHash(id); + this.props.onMenuItemClick(); + } +} diff --git a/packages/website/ts/pages/shared/section_header.tsx b/packages/website/ts/pages/shared/section_header.tsx new file mode 100644 index 000000000..5937be13b --- /dev/null +++ b/packages/website/ts/pages/shared/section_header.tsx @@ -0,0 +1,50 @@ +import * as React from 'react'; +import {Element as ScrollElement} from 'react-scroll'; +import {AnchorTitle} from 'ts/pages/shared/anchor_title'; +import {utils} from 'ts/utils/utils'; +import {HeaderSizes} from 'ts/types'; + +interface SectionHeaderProps { + sectionName: string; + headerSize?: HeaderSizes; +} + +interface SectionHeaderState { + shouldShowAnchor: boolean; +} + +export class SectionHeader extends React.Component<SectionHeaderProps, SectionHeaderState> { + public static defaultProps: Partial<SectionHeaderProps> = { + headerSize: HeaderSizes.H2, + }; + constructor(props: SectionHeaderProps) { + super(props); + this.state = { + shouldShowAnchor: false, + }; + } + public render() { + const sectionName = this.props.sectionName.replace(/-/g, ' '); + const id = utils.getIdFromName(sectionName); + return ( + <div + onMouseOver={this.setAnchorVisibility.bind(this, true)} + onMouseOut={this.setAnchorVisibility.bind(this, false)} + > + <ScrollElement name={id}> + <AnchorTitle + headerSize={this.props.headerSize} + title={<span style={{textTransform: 'capitalize'}}>{sectionName}</span>} + id={id} + shouldShowAnchor={this.state.shouldShowAnchor} + /> + </ScrollElement> + </div> + ); + } + private setAnchorVisibility(shouldShowAnchor: boolean) { + this.setState({ + shouldShowAnchor, + }); + } +} diff --git a/packages/website/ts/pages/shared/version_drop_down.tsx b/packages/website/ts/pages/shared/version_drop_down.tsx new file mode 100644 index 000000000..f29547c9c --- /dev/null +++ b/packages/website/ts/pages/shared/version_drop_down.tsx @@ -0,0 +1,46 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import MenuItem from 'material-ui/MenuItem'; +import DropDownMenu from 'material-ui/DropDownMenu'; +import {constants} from 'ts/utils/constants'; +import {Docs} from 'ts/types'; + +interface VersionDropDownProps { + selectedVersion: string; + versions: string[]; + doc: Docs; +} + +interface VersionDropDownState {} + +export class VersionDropDown extends React.Component<VersionDropDownProps, VersionDropDownState> { + public render() { + return ( + <div className="mx-auto" style={{width: 120}}> + <DropDownMenu + maxHeight={300} + value={this.props.selectedVersion} + onChange={this.updateSelectedVersion.bind(this)} + > + {this.renderDropDownItems()} + </DropDownMenu> + </div> + ); + } + private renderDropDownItems() { + const items = _.map(this.props.versions, version => { + return ( + <MenuItem + key={version} + value={version} + primaryText={`v${version}`} + /> + ); + }); + return items; + } + private updateSelectedVersion(e: any, index: number, value: string) { + const docPath = constants.docToPath[this.props.doc]; + window.location.href = `${docPath}/${value}${window.location.hash}`; + } +} |