146 lines
3.8 KiB
TypeScript
146 lines
3.8 KiB
TypeScript
import React, { useContext, useState } from 'react';
|
|
import { IRouteComponentProps } from '@umijs/types';
|
|
import { context, Link } from 'dumi/theme';
|
|
import Navbar from '../components/Navbar';
|
|
import SideMenu from '../components/SideMenu';
|
|
import SlugList from '../components/SlugList';
|
|
import NavRight from '../components/NavRight';
|
|
import './layout.less';
|
|
|
|
const Hero = (hero) => (
|
|
<>
|
|
<div className="__dumi-default-layout-hero">
|
|
{hero.image && <img src={hero.image} />}
|
|
<h1>{hero.title}</h1>
|
|
<div dangerouslySetInnerHTML={{ __html: hero.desc }} />
|
|
{hero.actions &&
|
|
hero.actions.map((action) => (
|
|
<Link to={action.link} key={action.text}>
|
|
<button type="button">{action.text}</button>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</>
|
|
);
|
|
|
|
const Features = (features) => (
|
|
<div className="__dumi-default-layout-features">
|
|
{features.map((feat) => (
|
|
<dl
|
|
key={feat.title}
|
|
style={{
|
|
backgroundImage: feat.icon
|
|
? `url(${feat.icon})`
|
|
: undefined,
|
|
}}
|
|
>
|
|
{feat.link ? (
|
|
<Link to={feat.link}>
|
|
<dt>{feat.title}</dt>
|
|
</Link>
|
|
) : (
|
|
<dt>{feat.title}</dt>
|
|
)}
|
|
<dd dangerouslySetInnerHTML={{ __html: feat.desc }} />
|
|
</dl>
|
|
))}
|
|
</div>
|
|
);
|
|
|
|
const Layout: React.FC<IRouteComponentProps> = ({ children, location }) => {
|
|
const {
|
|
config: { mode, repository },
|
|
meta,
|
|
locale,
|
|
} = useContext(context);
|
|
const { url: repoUrl, branch, platform } = repository;
|
|
const [menuCollapsed, setMenuCollapsed] = useState<boolean>(true);
|
|
const isSiteMode = mode === 'site';
|
|
const showHero = isSiteMode && meta.hero;
|
|
const showFeatures = isSiteMode && meta.features;
|
|
const showSideMenu =
|
|
meta.sidemenu !== false && !showHero && !showFeatures && !meta.gapless;
|
|
const showSlugs =
|
|
!showHero &&
|
|
!showFeatures &&
|
|
Boolean(meta.slugs?.length) &&
|
|
(meta.toc === 'content' || meta.toc === undefined) &&
|
|
!meta.gapless;
|
|
const isCN = /^zh|cn$/i.test(locale);
|
|
const updatedTimeIns = new Date(meta.updatedTime);
|
|
const updatedTime: any = `${updatedTimeIns.toLocaleDateString([], {
|
|
hour12: false,
|
|
})} ${updatedTimeIns.toLocaleTimeString([], { hour12: false })}`;
|
|
const repoPlatform =
|
|
{ github: 'GitHub', gitlab: 'GitLab' }[
|
|
(repoUrl || '').match(/(github|gitlab)/)?.[1] || 'nothing'
|
|
] || platform;
|
|
return (
|
|
<div
|
|
className="__dumi-default-layout"
|
|
data-route={location.pathname}
|
|
data-show-sidemenu={String(showSideMenu)}
|
|
data-show-slugs={String(showSlugs)}
|
|
data-site-mode={isSiteMode}
|
|
data-gapless={String(!!meta.gapless)}
|
|
onClick={() => {
|
|
if (menuCollapsed) return;
|
|
setMenuCollapsed(true);
|
|
}}
|
|
>
|
|
<Navbar
|
|
location={location}
|
|
navLast={<NavRight />}
|
|
onMobileMenuClick={(ev) => {
|
|
setMenuCollapsed((val) => !val);
|
|
ev.stopPropagation();
|
|
}}
|
|
/>
|
|
<SideMenu mobileMenuCollapsed={menuCollapsed} location={location} />
|
|
{showSlugs && (
|
|
<SlugList
|
|
slugs={meta.slugs}
|
|
className="__dumi-default-layout-toc"
|
|
/>
|
|
)}
|
|
{showHero && Hero(meta.hero)}
|
|
{showFeatures && Features(meta.features)}
|
|
<div className="__dumi-default-layout-content">
|
|
{children}
|
|
{!showHero &&
|
|
!showFeatures &&
|
|
meta.filePath &&
|
|
meta.showFooter !== false &&
|
|
!meta.gapless && (
|
|
<div className="__dumi-default-layout-footer-meta">
|
|
{repoPlatform && (
|
|
<Link
|
|
to={`${repoUrl}/edit/${branch}/${meta.filePath}`}
|
|
>
|
|
{isCN
|
|
? `在 ${repoPlatform} 上编辑此页`
|
|
: `Edit this doc on ${repoPlatform}`}
|
|
</Link>
|
|
)}
|
|
<span
|
|
data-updated-text={
|
|
isCN ? '最后更新时间:' : 'Last update: '
|
|
}
|
|
>
|
|
{updatedTime}
|
|
</span>
|
|
</div>
|
|
)}
|
|
{(showHero || showFeatures) && meta.footer && (
|
|
<div
|
|
className="__dumi-default-layout-footer"
|
|
dangerouslySetInnerHTML={{ __html: meta.footer }}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Layout;
|