import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Link } from 'bisheng/router'; import { Row, Col, Menu, Affix, Tooltip, Avatar } from 'antd'; import { injectIntl } from 'react-intl'; import { LeftOutlined, RightOutlined, ExportOutlined } from '@ant-design/icons'; import ContributorsList from '@qixian.cs/github-contributors-list'; import classNames from 'classnames'; import get from 'lodash/get'; import MobileMenu from 'rc-drawer'; import { DarkIcon, DefaultIcon } from './ThemeIcon'; import Article from './Article'; import PrevAndNext from './PrevAndNext'; import Footer from '../Layout/Footer'; import SiteContext from '../Layout/SiteContext'; import ComponentDoc from './ComponentDoc'; import * as utils from '../utils'; const { SubMenu } = Menu; function getModuleData(props) { const { pathname } = props.location; const moduleName = /^\/?components/.test(pathname) ? 'components' : pathname .split('/') .filter(item => item) .slice(0, 2) .join('/'); const excludedSuffix = utils.isZhCN(props.location.pathname) ? 'en-US.md' : 'zh-CN.md'; let data; switch (moduleName) { case 'docs/react': case 'changelog': case 'changelog-cn': data = [...props.picked['docs/react'], ...props.picked.changelog]; break; default: data = props.picked[moduleName]; } return data.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; }; class MainContent extends Component { static contextTypes = { theme: PropTypes.oneOf(['default', 'dark']), setTheme: PropTypes.func, setIframeTheme: PropTypes.func, }; state = { openKeys: undefined, }; componentDidMount() { this.componentDidUpdate(); window.addEventListener('load', this.handleInitialHashOnLoad); } static getDerivedStateFromProps(props, state) { if (!state.openKeys) { return { ...state, openKeys: getSideBarOpenKeys(props), }; } return null; } componentDidUpdate(prevProps) { const { location } = this.props; const { location: prevLocation = {} } = prevProps || {}; if (!prevProps || prevLocation.pathname !== location.pathname) { this.bindScroller(); } if (!window.location.hash && prevLocation.pathname !== location.pathname) { window.scrollTo(0, 0); } // when subMenu not equal if (get(this.props, 'route.path') !== get(prevProps, 'route.path')) { // reset menu OpenKeys this.handleMenuOpenChange(); } } componentWillUnmount() { this.scroller.destroy(); window.removeEventListener('load', this.handleInitialHashOnLoad); } getMenuItems(footerNavIcons = {}) { const { themeConfig, intl: { locale }, } = this.props; const moduleData = getModuleData(this.props); const menuItems = utils.getMenuItems( moduleData, locale, themeConfig.categoryOrder, themeConfig.typeOrder, ); return menuItems.map(menuItem => { if (menuItem.type === 'type') { return ( {menuItem.children .sort((a, b) => a.title.charCodeAt(0) - b.title.charCodeAt(0)) .map(leaf => this.generateMenuItem(false, leaf, footerNavIcons))} ); } if (menuItem.children) { return ( {menuItem.children.map(child => { if (child.type === 'type') { return ( {child.children.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 }; } getActiveMenuItem() { const { params: { children }, location, } = this.props; return ( (children && children.replace('-cn', '')) || location.pathname.replace(/(^\/|-cn$)/g, '') ); } handleMenuOpenChange = openKeys => { this.setState({ openKeys }); }; handleInitialHashOnLoad = () => { setTimeout(() => { if (!window.location.hash) { return; } const element = document.getElementById( decodeURIComponent(window.location.hash.replace('#', '')), ); if (element && document.documentElement.scrollTop === 0) { element.scrollIntoView(); } }, 0); }; bindScroller() { if (this.scroller) { this.scroller.destroy(); } if (!document.querySelector('.markdown > h2, .code-box')) { return; } 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.props; 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.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); } changeTheme = () => { const { theme, setTheme } = this.context; const nextTheme = theme !== 'dark' ? 'dark' : 'default'; setTheme(nextTheme); }; render() { return ( {({ isMobile }) => { const { theme, setIframeTheme } = this.context; const { openKeys } = this.state; const { localizedPageData, demos, intl: { formatMessage }, } = this.props; const { meta } = localizedPageData; const activeMenuItem = this.getActiveMenuItem(); const menuItems = this.getMenuItems(); const menuItemsForFooterNav = this.getMenuItems({ before: , after: , }); const { prev, next } = this.getFooterNav(menuItemsForFooterNav, activeMenuItem); const mainContainerClass = classNames('main-container', { 'main-container-component': !!demos, }); const menuChild = ( {menuItems} ); const componentPage = /^\/?components/.test(this.props.location.pathname); return (
{isMobile ? ( {menuChild} ) : (
{menuChild}
)}
{demos ? ( ) : (
{componentPage && (
node.parentNode} title={formatMessage({ id: `app.theme.switch.${theme}` })} overlayClassName="fixed-widgets-tooltip" > : } />
)}
); }}
); } } export default injectIntl(MainContent);