import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'bisheng/router'; import { Row, Col, Menu, Icon } from 'antd'; import classNames from 'classnames'; import MobileMenu from 'rc-drawer'; import Article from './Article'; import ComponentDoc from './ComponentDoc'; import * as utils from '../utils'; const { SubMenu } = Menu; function getActiveMenuItem(props) { const { children } = props.params; return ( (children && children.replace('-cn', '')) || props.location.pathname.replace(/(^\/|-cn$)/g, '') ); } function getModuleData(props) { const { pathname } = props.location; const moduleName = /^\/?components/.test(pathname) ? 'components' : pathname .split('/') .filter(item => item) .slice(0, 2) .join('/'); const moduleData = moduleName === 'components' || moduleName === 'docs/react' || moduleName === 'changelog' || moduleName === 'changelog-cn' ? [...props.picked.components, ...props.picked['docs/react'], ...props.picked.changelog] : props.picked[moduleName]; const excludedSuffix = utils.isZhCN(props.location.pathname) ? 'en-US.md' : 'zh-CN.md'; return moduleData.filter(({ meta }) => !meta.filename.endsWith(excludedSuffix)); } function fileNameToPath(filename) { const snippets = filename.replace(/(\/index)?((\.zh-CN)|(\.en-US))?\.md$/i, '').split('/'); return snippets[snippets.length - 1]; } const getSideBarOpenKeys = nextProps => { const { themeConfig } = nextProps; const { pathname } = nextProps.location; const locale = utils.isZhCN(pathname) ? 'zh-CN' : 'en-US'; const moduleData = getModuleData(nextProps); const shouldOpenKeys = utils .getMenuItems(moduleData, locale, themeConfig.categoryOrder, themeConfig.typeOrder) .map(m => (m.title && m.title[locale]) || m.title); return shouldOpenKeys; }; export default class MainContent extends React.PureComponent { static contextTypes = { intl: PropTypes.object.isRequired, isMobile: PropTypes.bool.isRequired, }; state = { openKeys: undefined, }; componentDidMount() { this.componentDidUpdate(); } static getDerivedStateFromProps(props, state) { return { ...state, openKeys: getSideBarOpenKeys(props), }; } componentDidUpdate(prevProps) { const { location } = this.props; if (!prevProps || prevProps.location.pathname !== location.pathname) { this.bindScroller(); } if (!window.location.hash && prevProps && prevProps.location.pathname !== location.pathname) { document.documentElement.scrollTop = 0; } setTimeout(() => { if ( window.location.hash && document.querySelector(decodeURIComponent(window.location.hash)) && document.documentElement.scrollTop === 0 ) { document.querySelector(decodeURIComponent(window.location.hash)).scrollIntoView(); } }, 0); } componentWillUnmount() { this.scroller.disable(); } getMenuItems(footerNavIcons = {}) { const { themeConfig } = this.props; const { intl: { locale }, } = this.context; const moduleData = getModuleData(this.props); const menuItems = utils.getMenuItems( moduleData, locale, themeConfig.categoryOrder, themeConfig.typeOrder, ); return menuItems.map(menuItem => { if (menuItem.children) { return ( {menuItem.title}} key={menuItem.title}> {menuItem.children.map(child => { if (child.type === 'type') { return ( {child.children .sort((a, b) => a.title.charCodeAt(0) - b.title.charCodeAt(0)) .map(leaf => this.generateMenuItem(false, leaf, footerNavIcons))} ); } return this.generateMenuItem(false, child, footerNavIcons); })} ); } return this.generateMenuItem(true, menuItem, footerNavIcons); }); } getFooterNav(menuItems, activeMenuItem) { const menuItemsList = this.flattenMenu(menuItems); let activeMenuItemIndex = -1; menuItemsList.forEach((menuItem, i) => { if (menuItem && menuItem.key === activeMenuItem) { activeMenuItemIndex = i; } }); const prev = menuItemsList[activeMenuItemIndex - 1]; const next = menuItemsList[activeMenuItemIndex + 1]; return { prev, next }; } handleMenuOpenChange = openKeys => { this.setState({ openKeys }); }; bindScroller() { if (this.scroller) { this.scroller.disable(); } require('intersection-observer'); // eslint-disable-line const scrollama = require('scrollama'); // eslint-disable-line this.scroller = scrollama(); this.scroller .setup({ step: '.markdown > h2, .code-box', // required offset: 0, }) .onStepEnter(({ element }) => { [].forEach.call(document.querySelectorAll('.toc-affix li a'), node => { node.className = ''; // eslint-disable-line }); const currentNode = document.querySelectorAll(`.toc-affix li a[href="#${element.id}"]`)[0]; if (currentNode) { currentNode.className = 'current'; } }); } generateMenuItem(isTop, item, { before = null, after = null }) { const { intl: { locale }, } = this.context; const key = fileNameToPath(item.filename); if (!item.title) { return null; } const title = item.title[locale] || item.title; const text = isTop ? title : [ {title}, {item.subtitle} , ]; const { disabled } = item; const url = item.filename.replace(/(\/index)?((\.zh-CN)|(\.en-US))?\.md$/i, '').toLowerCase(); const child = !item.link ? ( {before} {text} {after} ) : ( {before} {text} {after} ); return ( {child} ); } flattenMenu(menu) { if (!menu) { return null; } if (menu && menu.type && menu.type.isMenuItem) { return menu; } if (Array.isArray(menu)) { return menu.reduce((acc, item) => acc.concat(this.flattenMenu(item)), []); } return this.flattenMenu((menu.props && menu.props.children) || menu.children); } render() { const { props } = this; const { isMobile } = this.context; const { openKeys } = this.state; const activeMenuItem = getActiveMenuItem(props); const menuItems = this.getMenuItems(); const menuItemsForFooterNav = this.getMenuItems({ before: , after: , }); const { prev, next } = this.getFooterNav(menuItemsForFooterNav, activeMenuItem); const { localizedPageData } = props; const mainContainerClass = classNames('main-container', { 'main-container-component': !!props.demos, }); const menuChild = ( {menuItems} ); return (
{isMobile ? ( , ]} key="Mobile-menu" wrapperClassName="drawer-wrapper" > {menuChild} ) : ( {menuChild} )} {props.demos ? ( ) : (
)}
{prev ? React.cloneElement(prev.props.children || prev.children[0], { className: 'prev-page', }) : null} {next ? React.cloneElement(next.props.children || next.children[0], { className: 'next-page', }) : null}
); } }