From de20ef1a49966153f25236ee68b186cd49f8dc20 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 12 Oct 2018 15:54:44 +0200 Subject: Refactor Home so that Dev section chrome is reusable across pages --- .../react-docs/src/components/doc_reference.tsx | 331 +++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 packages/react-docs/src/components/doc_reference.tsx (limited to 'packages/react-docs/src/components/doc_reference.tsx') diff --git a/packages/react-docs/src/components/doc_reference.tsx b/packages/react-docs/src/components/doc_reference.tsx new file mode 100644 index 000000000..38ec818db --- /dev/null +++ b/packages/react-docs/src/components/doc_reference.tsx @@ -0,0 +1,331 @@ +import { + colors, + constants as sharedConstants, + EtherscanLinkSuffixes, + Link, + MarkdownSection, + Networks, + SectionHeader, + utils as sharedUtils, +} from '@0xproject/react-shared'; +import { + DocAgnosticFormat, + Event, + ExternalExportToLink, + Property, + SolidityMethod, + TypeDefinitionByName, + TypescriptFunction, + TypescriptMethod, +} from '@0xproject/types'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as semver from 'semver'; + +import { DocsInfo } from '../docs_info'; +import { AddressByContractName, SupportedDocJson } from '../types'; +import { constants } from '../utils/constants'; + +import { Badge } from './badge'; +import { Comment } from './comment'; +import { EventDefinition } from './event_definition'; +import { PropertyBlock } from './property_block'; +import { SignatureBlock } from './signature_block'; +import { TypeDefinition } from './type_definition'; + +const networkNameToColor: { [network: string]: string } = { + [Networks.Kovan]: colors.purple, + [Networks.Ropsten]: colors.red, + [Networks.Mainnet]: colors.turquois, + [Networks.Rinkeby]: colors.darkYellow, +}; + +export interface DocReferenceProps { + selectedVersion: string; + availableVersions: string[]; + docsInfo: DocsInfo; + sourceUrl: string; + docAgnosticFormat?: DocAgnosticFormat; +} + +export interface DocReferenceState { + isHoveringSidebar: boolean; +} + +export class DocReference extends React.Component { + constructor(props: DocReferenceProps) { + super(props); + this.state = { + isHoveringSidebar: false, + }; + } + public componentDidMount(): void { + window.addEventListener('hashchange', this._onHashChanged.bind(this), false); + } + public componentWillUnmount(): void { + window.removeEventListener('hashchange', this._onHashChanged.bind(this), false); + } + public componentDidUpdate(prevProps: DocReferenceProps, _prevState: DocReferenceState): void { + if (!_.isEqual(prevProps.docAgnosticFormat, this.props.docAgnosticFormat)) { + const hash = window.location.hash.slice(1); + sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); + } + } + public render(): React.ReactNode { + const subMenus = _.values(this.props.docsInfo.markdownMenu); + const orderedSectionNames = _.flatten(subMenus); + + const typeDefinitionByName = this.props.docsInfo.getTypeDefinitionsByName(this.props.docAgnosticFormat); + const renderedSections = _.map(orderedSectionNames, this._renderSection.bind(this, typeDefinitionByName)); + + return ( +
+
+ {renderedSections} +
+ ); + } + private _renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode { + const markdownVersions = _.keys(this.props.docsInfo.sectionNameToMarkdownByVersion); + const eligibleVersions = _.filter(markdownVersions, mdVersion => { + return semver.lte(mdVersion, this.props.selectedVersion); + }); + if (_.isEmpty(eligibleVersions)) { + throw new Error( + `No eligible markdown sections found for ${this.props.docsInfo.displayName} version ${ + this.props.selectedVersion + }.`, + ); + } + const sortedEligibleVersions = eligibleVersions.sort(semver.rcompare.bind(semver)); + const closestVersion = sortedEligibleVersions[0]; + const markdownFileIfExists = this.props.docsInfo.sectionNameToMarkdownByVersion[closestVersion][sectionName]; + if (!_.isUndefined(markdownFileIfExists)) { + return ( + + ); + } + + const docSection = this.props.docAgnosticFormat[sectionName]; + if (_.isUndefined(docSection)) { + return null; + } + + const isExportedFunctionSection = + docSection.functions.length === 1 && + _.isEmpty(docSection.types) && + _.isEmpty(docSection.methods) && + _.isEmpty(docSection.constructors) && + _.isEmpty(docSection.properties) && + _.isEmpty(docSection.events); + + const sortedTypes = _.sortBy(docSection.types, 'name'); + const typeDefs = _.map(sortedTypes, (customType, i) => { + return ( + + ); + }); + + const sortedProperties = _.sortBy(docSection.properties, 'name'); + const propertyDefs = _.map( + sortedProperties, + this._renderProperty.bind(this, sectionName, typeDefinitionByName), + ); + + const sortedMethods = _.sortBy(docSection.methods, 'name'); + const methodDefs = _.map(sortedMethods, method => { + return this._renderSignatureBlocks(method, sectionName, typeDefinitionByName); + }); + + const sortedFunctions = _.sortBy(docSection.functions, 'name'); + const functionDefs = _.map(sortedFunctions, func => { + return this._renderSignatureBlocks(func, sectionName, typeDefinitionByName); + }); + + const sortedEvents = _.sortBy(docSection.events, 'name'); + const eventDefs = _.map(sortedEvents, (event: Event, i: number) => { + return ( + + ); + }); + const headerStyle: React.CSSProperties = { + fontWeight: 100, + }; + return ( +
+
+
+ +
+ {this._renderNetworkBadgesIfExists(sectionName)} +
+ {docSection.comment && } + {!_.isEmpty(docSection.constructors) && ( +
+

Constructor

+ {this._renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)} +
+ )} + {!_.isEmpty(docSection.properties) && ( +
+

Properties

+
{propertyDefs}
+
+ )} + {!_.isEmpty(docSection.methods) && ( +
+

Methods

+
{methodDefs}
+
+ )} + {!_.isEmpty(docSection.functions) && ( +
+ {!isExportedFunctionSection &&

Functions

} +
{functionDefs}
+
+ )} + {!_.isUndefined(docSection.events) && + docSection.events.length > 0 && ( +
+

Events

+
{eventDefs}
+
+ )} + {!_.isUndefined(docSection.externalExportToLink) && + this._renderExternalExports(docSection.externalExportToLink)} + {!_.isUndefined(typeDefs) && + typeDefs.length > 0 && ( +
+
{typeDefs}
+
+ )} +
+ ); + } + private _renderExternalExports(externalExportToLink: ExternalExportToLink): React.ReactNode { + const externalExports = _.map(externalExportToLink, (link: string, exportName: string) => { + return ( +
+ + {`import { `} + + {exportName} + + {` } from '${this.props.docsInfo.packageName}'`} + +
+ ); + }); + return
{externalExports}
; + } + private _renderNetworkBadgesIfExists(sectionName: string): React.ReactNode { + if (this.props.docsInfo.type !== SupportedDocJson.SolDoc) { + return null; + } + + const networkToAddressByContractName = this.props.docsInfo.contractsByVersionByNetworkId[ + this.props.selectedVersion + ]; + const badges = _.map( + networkToAddressByContractName, + (addressByContractName: AddressByContractName, networkName: string) => { + const contractAddress = addressByContractName[sectionName]; + if (_.isUndefined(contractAddress)) { + return null; + } + const linkIfExists = sharedUtils.getEtherScanLinkIfExists( + contractAddress, + sharedConstants.NETWORK_ID_BY_NAME[networkName], + EtherscanLinkSuffixes.Address, + ); + return ( +
+ + + +
+ ); + }, + ); + return badges; + } + private _renderConstructors( + constructors: SolidityMethod[] | TypescriptMethod[], + sectionName: string, + typeDefinitionByName: TypeDefinitionByName, + ): React.ReactNode { + const constructorDefs = _.map(constructors, constructor => { + return this._renderSignatureBlocks(constructor, sectionName, typeDefinitionByName); + }); + return
{constructorDefs}
; + } + private _renderProperty( + sectionName: string, + typeDefinitionByName: TypeDefinitionByName, + property: Property, + ): React.ReactNode { + return ( + + ); + } + private _renderSignatureBlocks( + method: SolidityMethod | TypescriptFunction | TypescriptMethod, + sectionName: string, + typeDefinitionByName: TypeDefinitionByName, + ): React.ReactNode { + return ( + + ); + } + private _onSidebarHover(_event: React.FormEvent): void { + this.setState({ + isHoveringSidebar: true, + }); + } + private _onSidebarHoverOff(): void { + this.setState({ + isHoveringSidebar: false, + }); + } + private _onHashChanged(_event: any): void { + const hash = window.location.hash.slice(1); + sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); + } +} -- cgit v1.2.3