diff options
Diffstat (limited to 'packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx')
-rw-r--r-- | packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx b/packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx new file mode 100644 index 000000000..c26fb7d0a --- /dev/null +++ b/packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx @@ -0,0 +1,340 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import * as ReactMarkdown from 'react-markdown'; +import DocumentTitle = require('react-document-title'); +import findVersions = require('find-versions'); +import semverSort = require('semver-sort'); +import {colors} from 'material-ui/styles'; +import MenuItem from 'material-ui/MenuItem'; +import CircularProgress from 'material-ui/CircularProgress'; +import Paper from 'material-ui/Paper'; +import { + Link as ScrollLink, + Element as ScrollElement, + scroller, +} from 'react-scroll'; +import {Dispatcher} from 'ts/redux/dispatcher'; +import { + KindString, + TypeDocNode, + ZeroExJsDocSections, + Styles, + ScreenWidths, + TypeDefinitionByName, + DocAgnosticFormat, + TypescriptMethod, + Property, + CustomType, + Docs, +} from 'ts/types'; +import {TopBar} from 'ts/components/top_bar'; +import {utils} from 'ts/utils/utils'; +import {docUtils} from 'ts/utils/doc_utils'; +import {constants} from 'ts/utils/constants'; +import {Loading} from 'ts/components/ui/loading'; +import {MethodBlock} from 'ts/pages/documentation/method_block'; +import {SourceLink} from 'ts/pages/documentation/source_link'; +import {Type} from 'ts/pages/documentation/type'; +import {TypeDefinition} from 'ts/pages/documentation/type_definition'; +import {MarkdownSection} from 'ts/pages/shared/markdown_section'; +import {Comment} from 'ts/pages/documentation/comment'; +import {AnchorTitle} from 'ts/pages/shared/anchor_title'; +import {SectionHeader} from 'ts/pages/shared/section_header'; +import {NestedSidebarMenu} from 'ts/pages/shared/nested_sidebar_menu'; +import {typeDocUtils} from 'ts/utils/typedoc_utils'; +/* tslint:disable:no-var-requires */ +const IntroMarkdown = require('md/docs/0xjs/introduction'); +const InstallationMarkdown = require('md/docs/0xjs/installation'); +const AsyncMarkdown = require('md/docs/0xjs/async'); +const ErrorsMarkdown = require('md/docs/0xjs/errors'); +const versioningMarkdown = require('md/docs/0xjs/versioning'); +/* tslint:enable:no-var-requires */ + +const SCROLL_TO_TIMEOUT = 500; +const DOC_JSON_ROOT = constants.S3_0XJS_DOCUMENTATION_JSON_ROOT; + +const sectionNameToMarkdown = { + [ZeroExJsDocSections.introduction]: IntroMarkdown, + [ZeroExJsDocSections.installation]: InstallationMarkdown, + [ZeroExJsDocSections.async]: AsyncMarkdown, + [ZeroExJsDocSections.errors]: ErrorsMarkdown, + [ZeroExJsDocSections.versioning]: versioningMarkdown, +}; + +export interface ZeroExJSDocumentationPassedProps { + source: string; + location: Location; +} + +export interface ZeroExJSDocumentationAllProps { + source: string; + location: Location; + dispatcher: Dispatcher; + docsVersion: string; + availableDocVersions: string[]; +} + +interface ZeroExJSDocumentationState { + docAgnosticFormat?: DocAgnosticFormat; +} + +const styles: Styles = { + mainContainers: { + position: 'absolute', + top: 60, + left: 0, + bottom: 0, + right: 0, + overflowZ: 'hidden', + overflowY: 'scroll', + minHeight: 'calc(100vh - 60px)', + WebkitOverflowScrolling: 'touch', + }, + menuContainer: { + borderColor: colors.grey300, + maxWidth: 330, + marginLeft: 20, + }, +}; + +export class ZeroExJSDocumentation extends React.Component<ZeroExJSDocumentationAllProps, ZeroExJSDocumentationState> { + constructor(props: ZeroExJSDocumentationAllProps) { + super(props); + this.state = { + docAgnosticFormat: undefined, + }; + } + public componentWillMount() { + const pathName = this.props.location.pathname; + const lastSegment = pathName.substr(pathName.lastIndexOf('/') + 1); + const versions = findVersions(lastSegment); + const preferredVersionIfExists = versions.length > 0 ? versions[0] : undefined; + this.fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists); + } + public render() { + const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat) + ? {} + : typeDocUtils.getMenuSubsectionsBySection(this.state.docAgnosticFormat); + return ( + <div> + <DocumentTitle title="0x.js Documentation"/> + <TopBar + blockchainIsLoaded={false} + location={this.props.location} + docsVersion={this.props.docsVersion} + availableDocVersions={this.props.availableDocVersions} + menuSubsectionsBySection={menuSubsectionsBySection} + shouldFullWidth={true} + doc={Docs.ZeroExJs} + /> + {_.isUndefined(this.state.docAgnosticFormat) ? + <div + className="col col-12" + style={styles.mainContainers} + > + <div + className="relative sm-px2 sm-pt2 sm-m1" + style={{height: 122, top: '50%', transform: 'translateY(-50%)'}} + > + <div className="center pb2"> + <CircularProgress size={40} thickness={5} /> + </div> + <div className="center pt2" style={{paddingBottom: 11}}>Loading documentation...</div> + </div> + </div> : + <div + className="mx-auto flex" + style={{color: colors.grey800, height: 43}} + > + <div className="relative col md-col-3 lg-col-3 lg-pl0 md-pl1 sm-hide xs-hide"> + <div + className="border-right absolute" + style={{...styles.menuContainer, ...styles.mainContainers}} + > + <NestedSidebarMenu + selectedVersion={this.props.docsVersion} + versions={this.props.availableDocVersions} + topLevelMenu={typeDocUtils.getFinal0xjsMenu(this.props.docsVersion)} + menuSubsectionsBySection={menuSubsectionsBySection} + doc={Docs.ZeroExJs} + /> + </div> + </div> + <div className="relative col lg-col-9 md-col-9 sm-col-12 col-12"> + <div + id="documentation" + style={styles.mainContainers} + className="absolute" + > + <div id="zeroExJSDocs" /> + <h1 className="md-pl2 sm-pl3"> + <a href={constants.GITHUB_0X_JS_URL} target="_blank"> + 0x.js + </a> + </h1> + {this.renderDocumentation()} + </div> + </div> + </div> + } + </div> + ); + } + private renderDocumentation(): React.ReactNode { + const typeDocSection = this.state.docAgnosticFormat[ZeroExJsDocSections.types]; + const typeDefinitionByName = _.keyBy(typeDocSection.types, 'name'); + + const subMenus = _.values(constants.menu0xjs); + const orderedSectionNames = _.flatten(subMenus); + const sections = _.map(orderedSectionNames, this.renderSection.bind(this, typeDefinitionByName)); + + return sections; + } + private renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode { + const docSection = this.state.docAgnosticFormat[sectionName]; + + const markdownFileIfExists = sectionNameToMarkdown[sectionName]; + if (!_.isUndefined(markdownFileIfExists)) { + return ( + <MarkdownSection + key={`markdown-section-${sectionName}`} + sectionName={sectionName} + markdownContent={markdownFileIfExists} + /> + ); + } + + if (_.isUndefined(docSection)) { + return null; + } + + const typeDefs = _.map(docSection.types, customType => { + return ( + <TypeDefinition + key={`type-${customType.name}`} + customType={customType} + /> + ); + }); + const propertyDefs = _.map(docSection.properties, this.renderProperty.bind(this)); + const methodDefs = _.map(docSection.methods, method => { + const isConstructor = false; + return this.renderMethodBlocks(method, sectionName, isConstructor, typeDefinitionByName); + }); + return ( + <div + key={`section-${sectionName}`} + className="py2 pr3 md-pl2 sm-pl3" + > + <SectionHeader sectionName={sectionName} /> + <Comment + comment={docSection.comment} + /> + {sectionName === ZeroExJsDocSections.zeroEx && docSection.constructors.length > 0 && + <div> + <h2 className="thin">Constructor</h2> + {this.renderZeroExConstructors(docSection.constructors, typeDefinitionByName)} + </div> + } + {docSection.properties.length > 0 && + <div> + <h2 className="thin">Properties</h2> + <div>{propertyDefs}</div> + </div> + } + {docSection.methods.length > 0 && + <div> + <h2 className="thin">Methods</h2> + <div>{methodDefs}</div> + </div> + } + {typeDefs.length > 0 && + <div> + <div>{typeDefs}</div> + </div> + } + </div> + ); + } + private renderZeroExConstructors(constructors: TypescriptMethod[], + typeDefinitionByName: TypeDefinitionByName): React.ReactNode { + const constructorDefs = _.map(constructors, constructor => { + return this.renderMethodBlocks( + constructor, ZeroExJsDocSections.zeroEx, constructor.isConstructor, typeDefinitionByName, + ); + }); + return ( + <div> + {constructorDefs} + </div> + ); + } + private renderProperty(property: Property): React.ReactNode { + return ( + <div + key={`property-${property.name}-${property.type.name}`} + className="pb3" + > + <code className="hljs"> + {property.name}: <Type type={property.type} /> + </code> + <SourceLink + version={this.props.docsVersion} + source={property.source} + /> + {property.comment && + <Comment + comment={property.comment} + className="py2" + /> + } + </div> + ); + } + private renderMethodBlocks(method: TypescriptMethod, sectionName: string, isConstructor: boolean, + typeDefinitionByName: TypeDefinitionByName): React.ReactNode { + return ( + <MethodBlock + key={`method-${method.name}-${!_.isUndefined(method.source) ? method.source.line : ''}`} + method={method} + typeDefinitionByName={typeDefinitionByName} + libraryVersion={this.props.docsVersion} + /> + ); + } + private scrollToHash(): void { + const hashWithPrefix = this.props.location.hash; + let hash = hashWithPrefix.slice(1); + if (_.isEmpty(hash)) { + hash = 'zeroExJSDocs'; // scroll to the top + } + + scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'}); + } + private async fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise<void> { + const versionToFileName = await docUtils.getVersionToFileNameAsync(DOC_JSON_ROOT); + const versions = _.keys(versionToFileName); + this.props.dispatcher.updateAvailableDocVersions(versions); + const sortedVersions = semverSort.desc(versions); + const latestVersion = sortedVersions[0]; + + let versionToFetch = latestVersion; + if (!_.isUndefined(preferredVersionIfExists)) { + const preferredVersionFileNameIfExists = versionToFileName[preferredVersionIfExists]; + if (!_.isUndefined(preferredVersionFileNameIfExists)) { + versionToFetch = preferredVersionIfExists; + } + } + this.props.dispatcher.updateCurrentDocsVersion(versionToFetch); + + const versionFileNameToFetch = versionToFileName[versionToFetch]; + const versionDocObj = await docUtils.getJSONDocFileAsync(versionFileNameToFetch, DOC_JSON_ROOT); + const docAgnosticFormat = typeDocUtils.convertToDocAgnosticFormat((versionDocObj as TypeDocNode)); + + this.setState({ + docAgnosticFormat, + }, () => { + this.scrollToHash(); + }); + } +} |