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 = (
);
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}
);
})}
))}
);
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 ? (
) : (
{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
}
}
}
}
}
}
`;