import { colors, constants as sharedConstants, HeaderSizes, MarkdownSection, NestedSidebarMenu, Styles, utils as sharedUtils, } from '@0xproject/react-shared'; import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; import RaisedButton from 'material-ui/RaisedButton'; import * as React from 'react'; import DocumentTitle = require('react-document-title'); import { SidebarHeader } from 'ts/components/sidebar_header'; import { TopBar } from 'ts/components/top_bar/top_bar'; import { Dispatcher } from 'ts/redux/dispatcher'; import { Article, ArticlesBySection } from 'ts/types'; import { backendClient } from 'ts/utils/backend_client'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; import { utils } from 'ts/utils/utils'; const TOP_BAR_HEIGHT = 60; const WIKI_NOT_READY_BACKOUT_TIMEOUT_MS = 5000; export interface WikiProps { source: string; location: Location; dispatcher: Dispatcher; translate: Translate; } interface WikiState { articlesBySection: ArticlesBySection; isHoveringSidebar: boolean; } const styles: Styles = { mainContainers: { position: 'absolute', top: 1, left: 0, bottom: 0, right: 0, overflow: 'hidden', height: `calc(100vh - ${TOP_BAR_HEIGHT}px)`, WebkitOverflowScrolling: 'touch', }, menuContainer: { borderColor: colors.grey300, maxWidth: 330, backgroundColor: colors.gray40, }, }; export class Wiki extends React.Component { private _wikiBackoffTimeoutId: number; private _isUnmounted: boolean; constructor(props: WikiProps) { super(props); this._isUnmounted = false; this.state = { articlesBySection: undefined, isHoveringSidebar: false, }; } public componentDidMount(): void { window.addEventListener('hashchange', this._onHashChanged.bind(this), false); } public componentWillMount(): void { // tslint:disable-next-line:no-floating-promises this._fetchArticlesBySectionAsync(); } public componentWillUnmount(): void { this._isUnmounted = true; clearTimeout(this._wikiBackoffTimeoutId); window.removeEventListener('hashchange', this._onHashChanged.bind(this), false); } public render(): React.ReactNode { const menuSubsectionsBySection = _.isUndefined(this.state.articlesBySection) ? {} : this._getMenuSubsectionsBySection(this.state.articlesBySection); const mainContainersStyle: React.CSSProperties = { ...styles.mainContainers, overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden', }; const sidebarHeader = ; return (
{_.isUndefined(this.state.articlesBySection) ? (
Loading wiki...
) : (
{this._renderWikiArticles()}
)}
); } private _renderWikiArticles(): React.ReactNode { const sectionNames = _.keys(this.state.articlesBySection); const sections = _.map(sectionNames, sectionName => this._renderSection(sectionName)); return sections; } private _renderSection(sectionName: string): React.ReactNode { const articles = this.state.articlesBySection[sectionName]; const renderedArticles = _.map(articles, (article: Article) => { const githubLink = `${constants.URL_GITHUB_WIKI}/edit/master/${sectionName}/${article.fileName}`; return (
See a way to improve this article?
); }); return (
{renderedArticles}
); } private async _fetchArticlesBySectionAsync(): Promise { try { const articlesBySection = await backendClient.getWikiArticlesBySectionAsync(); if (!this._isUnmounted) { this.setState( { articlesBySection, }, async () => { await utils.onPageLoadAsync(); const hash = this.props.location.hash.slice(1); sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); }, ); } } catch (err) { const errMsg = `${err}`; if (_.includes(errMsg, `${constants.HTTP_NO_CONTENT_STATUS_CODE}`)) { // We need to backoff and try fetching again later this._wikiBackoffTimeoutId = window.setTimeout(() => { // tslint:disable-next-line:no-floating-promises this._fetchArticlesBySectionAsync(); }, WIKI_NOT_READY_BACKOUT_TIMEOUT_MS); return; } } } private _getMenuSubsectionsBySection(articlesBySection: ArticlesBySection): { [section: string]: string[] } { const sectionNames = _.keys(articlesBySection); const menuSubsectionsBySection: { [section: string]: string[] } = {}; for (const sectionName of sectionNames) { const articles = articlesBySection[sectionName]; const articleNames = _.map(articles, article => article.title); menuSubsectionsBySection[sectionName] = articleNames; } return menuSubsectionsBySection; } 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); } }