import React, { useState, useEffect } from 'react'; import { graphql, Link } from 'gatsby'; import { Layout as AntLayout, Anchor, Affix, BackTop, Menu } from 'antd'; import { createFromIconfontCN, MenuFoldOutlined, MenuUnfoldOutlined, VerticalAlignTopOutlined, } from '@ant-design/icons'; import { groupBy, debounce } from 'lodash-es'; import { useTranslation } from 'react-i18next'; import Drawer from 'rc-drawer'; import { useMedia } from 'react-use'; import Article from '../components/Article'; import SEO from '../components/Seo'; import PlayGround from '../components/PlayGround'; import NavigatorBanner from '../components/NavigatorBanner'; import { usePrevAndNext } from '../hooks'; import styles from './markdown.module.less'; const { SubMenu } = Menu; const { Link: AnchorLink } = Anchor; let gallery = false; const MenuIcon = createFromIconfontCN({ scriptUrl: '//at.alicdn.com/t/font_470089_9m0keqj54r.js', // generated by iconfont.cn }); const renderAnchorItems = (edges: any[]) => edges .filter((edge: any) => { const { node: { fields: { slug }, }, } = edge; if ( slug.endsWith('/API') || slug.endsWith('/design') || slug.endsWith('/gallery') ) { return false; } return true; }) .sort((a: any, b: any) => { const { node: { frontmatter: { order: aOrder }, }, } = a; const { node: { frontmatter: { order: bOrder }, }, } = b; return aOrder - bOrder; }) .map((edge: any) => { const { node: { frontmatter: { title, icon }, fields: { slug }, }, } = edge; return ( {icon && ( )} {title} } /> ); }); const getMenuItemLocaleKey = (slug = '') => { const slugPieces = slug.split('/'); const menuItemLocaleKey = slugPieces .slice(slugPieces.indexOf('examples') + 1) .filter((key) => key) .join('/'); return menuItemLocaleKey; }; const getExampleOrder = ({ groupedEdgeKey = '', examples = [], groupedEdges = {}, }: { groupedEdgeKey: string; examples: any[]; groupedEdges: { [key: string]: any[]; }; }): number => { const key = getMenuItemLocaleKey(groupedEdgeKey); if (examples.find((item) => item.slug === key)) { return (examples.findIndex((item) => item.slug === key) || 0) + 100; } if (!groupedEdges[groupedEdgeKey] && !groupedEdges[groupedEdgeKey].length) { return 0; } return groupedEdges[groupedEdgeKey][0].node.frontmatter.order || 0; }; export default function Template({ data, // this prop will be injected by the GraphQL query below. location, pageContext, }: { data: any; location: Location; pageContext: { exampleSections: any; allDemos?: any[]; description: string; }; }): React.ReactNode { const { allMarkdownRemark, site } = data; // data.markdownRemark holds our post data const { edges = [] } = allMarkdownRemark; const edgesInExamples = edges; const pathWithoutTrailingSlashes = location.pathname.replace(/\/$/, ''); const { node: markdownRemark } = edgesInExamples.find((edge: any) => { const { fields: { slug }, } = edge.node; if ( /\/examples\/.*\/API$/.test(pathWithoutTrailingSlashes) || /\/examples\/.*\/design$/.test(pathWithoutTrailingSlashes) ) { return pathWithoutTrailingSlashes.indexOf(slug) >= 0; } return ( pathWithoutTrailingSlashes === slug || pathWithoutTrailingSlashes.endsWith(slug) ); }) || {}; if (!markdownRemark) { return null; } const { frontmatter } = markdownRemark; const { siteMetadata: { examples = [], galleryMenuCloseAll = false }, } = site; const { i18n } = useTranslation(); const groupedEdges = groupBy( edgesInExamples, ({ node: { fields: { slug: slugString }, }, }: any) => { // API.md and deisgn.md if (slugString.endsWith('/API') || slugString.endsWith('/design')) { return slugString.split('/').slice(0, -2).join('/'); } // index.md return slugString.split('/').slice(0, -1).join('/'); }, ); const { exampleSections = {}, allDemos = [], description = '' } = pageContext; const [prev, next] = usePrevAndNext(); const allDemosInCategory = groupBy(allDemos || [], (demo) => { if (!demo.postFrontmatter || !demo.postFrontmatter[i18n.language]) { return 'OTHER'; } return demo.postFrontmatter[i18n.language].title; }); const Categories = Object.keys(allDemosInCategory).sort( (a: string, b: string) => { if (a === 'OTHER') { return -1; } if (b === 'OTHER') { return 1; } return ( allDemosInCategory[a][0].postFrontmatter[i18n.language].order - allDemosInCategory[b][0].postFrontmatter[i18n.language].order ); }, ); const [openKeys, setOpenKeys] = useState(() => // 是否默认收起所有 sub menu galleryMenuCloseAll ? [] : Object.keys(groupedEdges), ); const [selectedKeys, setSelectedKeys] = useState([]); const onAnchorLinkChange = debounce((currentActiveLink: string) => { let currentSlug = ''; edges.forEach((edge: any) => { const { node: { frontmatter: { title }, fields: { slug }, }, } = edge; if (`#category-${title.replace(/\s/g, '')}` === currentActiveLink) { currentSlug = slug; } }); setSelectedKeys([currentSlug]); if (currentActiveLink) { const link = document.querySelector(`a[href='${currentActiveLink}']`); if (link) { const anchor = link?.parentNode as Element; anchor.scrollIntoView({ block: 'center', }); } } }, 300); const menu = ( setOpenKeys(currentOpenKeys as string[]) } forceSubMenuRender > {Object.keys(groupedEdges) .filter((key) => key.startsWith(`/${i18n.language}/`)) .sort((a: string, b: string) => { const aOrder = getExampleOrder({ groupedEdgeKey: a, examples, groupedEdges, }); const bOrder = getExampleOrder({ groupedEdgeKey: b, examples, groupedEdges, }); return aOrder - bOrder; }) .map((slugString) => { const slugPieces = slugString.split('/'); if (slugPieces.length <= 3) { return renderAnchorItems(groupedEdges[slugString]); } const menuItemLocaleKey = getMenuItemLocaleKey(slugString); const doc = examples.find((item: any) => item.slug === menuItemLocaleKey) || {}; return ( {doc.icon && ( )} {doc && doc.title ? doc.title[i18n.language] : menuItemLocaleKey} } > {renderAnchorItems(groupedEdges[slugString])} ); })} ); const isWide = useMedia('(min-width: 767.99px)', true); const [drawOpen, setDrawOpen] = useState(false); const menuSider = ( {isWide ? ( {menu} ) : ( ) : ( ) } wrapperClassName={styles.menuDrawer} onChange={(open) => setDrawOpen(!!open)} width={280} > {menu} )} ); const galleryPageContent = (
{Categories.map((category: string, i) => (
{category !== 'OTHER' && (

{category}

)}
    {allDemosInCategory[category] .sort((a, b) => { return (a.order || -1) - (b.order || -1); }) .map((demo) => { let cardTitle; if (typeof demo.title === 'string') { cardTitle = demo.title; } else { cardTitle = demo.title ? demo.title[i18n.language] : demo.filename; } const demoSlug = demo.relativePath.replace( /\/demo\/(.*)\..*/, (_: string, filename: string) => { return `#${filename}`; }, ); return (
  • {cardTitle}

    {cardTitle}

  • ); })}
))}
); const exmaplePageContent = (
{exampleSections.examples && exampleSections.examples.length > 0 && ( )}
); // 判断当前所在页面 useEffect(() => { if (pathWithoutTrailingSlashes.endsWith('/examples/gallery')) { gallery = true; } else { gallery = false; } return () => { document.getElementsByTagName('body')[0].style.overflow = 'auto'; }; }, [pathWithoutTrailingSlashes]); return ( <> {gallery ? menuSider : null} {gallery ? (
{galleryPageContent}
) : (
{exmaplePageContent}
)}
); } export const pageQuery = graphql` query { site { siteMetadata { title galleryMenuCloseAll examples { slug icon title { zh en } } playground { container playgroundDidMount playgroundWillUnmount dependencies htmlCodeTemplate } } pathPrefix } allMarkdownRemark( filter: { fields: { slug: { regex: "//examples//" } } } sort: { order: ASC, fields: [frontmatter___order] } limit: 1000 ) { edges { node { fields { slug } frontmatter { title order icon } parent { ... on File { relativePath } } } } } } `;