mirror of
https://github.com/ant-design/ant-design.git
synced 2025-07-24 15:38:45 +08:00
refactor: import other components async in component doc (#46491)
* refactor: ContributorAvatar component * refactor: import other components async in component doc * chore: fix lint * docs: add suspense fallback * docs: add suspense fallback * docs: add suspense fallback
This commit is contained in:
parent
f6d43add73
commit
acbbbfebc2
38
.dumi/theme/slots/Content/ContributorAvatar.tsx
Normal file
38
.dumi/theme/slots/Content/ContributorAvatar.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import { Avatar, Skeleton, Tooltip } from 'antd';
|
||||
|
||||
const AvatarPlaceholder: React.FC<{ num?: number }> = ({ num = 3 }) => (
|
||||
<li>
|
||||
{Array.from({ length: num }).map((_, i) => (
|
||||
<Skeleton.Avatar size="small" active key={i} style={{ marginLeft: i === 0 ? 0 : -8 }} />
|
||||
))}
|
||||
</li>
|
||||
);
|
||||
|
||||
interface ContributorAvatarProps {
|
||||
username?: string;
|
||||
url?: string;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const ContributorAvatar: React.FC<ContributorAvatarProps> = ({ username, url, loading }) => {
|
||||
if (loading) {
|
||||
return <AvatarPlaceholder />;
|
||||
}
|
||||
if (username?.includes('github-actions')) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Tooltip title={username}>
|
||||
<li>
|
||||
<a href={`https://github.com/${username}`} target="_blank" rel="noopener noreferrer">
|
||||
<Avatar size="small" src={url} alt={username}>
|
||||
{username}
|
||||
</Avatar>
|
||||
</a>
|
||||
</li>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContributorAvatar;
|
82
.dumi/theme/slots/Content/Contributors.tsx
Normal file
82
.dumi/theme/slots/Content/Contributors.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
import React, { useContext } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useIntl } from 'dumi';
|
||||
import { createStyles } from 'antd-style';
|
||||
import ContributorsList from '@qixian.cs/github-contributors-list';
|
||||
import ContributorAvatar from './ContributorAvatar';
|
||||
import SiteContext from '../SiteContext';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => {
|
||||
const { antCls } = token;
|
||||
|
||||
return {
|
||||
contributorsList: css`
|
||||
margin-top: 120px !important;
|
||||
`,
|
||||
listMobile: css`
|
||||
margin: 1em 0 !important;
|
||||
`,
|
||||
title: css`
|
||||
font-size: 12px;
|
||||
opacity: 0.45;
|
||||
`,
|
||||
list: css`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
clear: both;
|
||||
|
||||
li {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
li,
|
||||
${antCls}-avatar + ${antCls}-avatar {
|
||||
transition: all ${token.motionDurationSlow};
|
||||
margin-inline-end: -8px;
|
||||
}
|
||||
&:hover {
|
||||
li,
|
||||
${antCls}-avatar {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
interface ContributorsProps {
|
||||
filename?: string;
|
||||
}
|
||||
|
||||
const Contributors: React.FC<ContributorsProps> = ({ filename }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { styles } = useStyle();
|
||||
const { isMobile } = useContext(SiteContext);
|
||||
|
||||
if (!filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.contributorsList, { [styles.listMobile]: isMobile })}>
|
||||
<div className={styles.title}>{formatMessage({ id: 'app.content.contributors' })}</div>
|
||||
<ContributorsList
|
||||
cache
|
||||
repo="ant-design"
|
||||
owner="ant-design"
|
||||
fileName={filename}
|
||||
className={styles.list}
|
||||
renderItem={(item, loading) => (
|
||||
<ContributorAvatar
|
||||
key={item?.username}
|
||||
username={item?.username}
|
||||
url={item?.url}
|
||||
loading={loading}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Contributors;
|
137
.dumi/theme/slots/Content/DocAnchor.tsx
Normal file
137
.dumi/theme/slots/Content/DocAnchor.tsx
Normal file
@ -0,0 +1,137 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Anchor } from 'antd';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import { useRouteMeta, useTabMeta } from 'dumi';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => {
|
||||
const { antCls } = token;
|
||||
|
||||
return {
|
||||
toc: css`
|
||||
${antCls}-anchor {
|
||||
${antCls}-anchor-link-title {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
`,
|
||||
tocWrapper: css`
|
||||
position: fixed;
|
||||
top: ${token.headerHeight + token.contentMarginTop}px;
|
||||
inset-inline-end: 0;
|
||||
width: 160px;
|
||||
margin: 0 0 12px 0;
|
||||
padding: 8px 0;
|
||||
padding-inline: 4px 8px;
|
||||
backdrop-filter: blur(8px);
|
||||
border-radius: ${token.borderRadius}px;
|
||||
box-sizing: border-box;
|
||||
z-index: 1000;
|
||||
|
||||
.toc-debug {
|
||||
color: ${token.purple6};
|
||||
|
||||
&:hover {
|
||||
color: ${token.purple5};
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 40px) !important;
|
||||
margin: 0 auto;
|
||||
overflow: auto;
|
||||
padding-inline: 4px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${token.screenLG}px) {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
articleWrapper: css`
|
||||
padding: 0 170px 32px 64px;
|
||||
|
||||
&.rtl {
|
||||
padding: 0 64px 144px 170px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${token.screenLG}px) {
|
||||
&,
|
||||
&.rtl {
|
||||
padding: 0 48px;
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
interface DocAnchorProps {
|
||||
showDebug?: boolean;
|
||||
debugDemos?: string[];
|
||||
}
|
||||
|
||||
type AnchorItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
children?: AnchorItem[];
|
||||
};
|
||||
|
||||
const DocAnchor: React.FC<DocAnchorProps> = ({ showDebug, debugDemos = [] }) => {
|
||||
const { styles } = useStyle();
|
||||
const token = useTheme();
|
||||
const meta = useRouteMeta();
|
||||
const tab = useTabMeta();
|
||||
|
||||
const renderAnchorItem = (item: AnchorItem) => ({
|
||||
href: `#${item.id}`,
|
||||
title: item.title,
|
||||
key: item.id,
|
||||
children: item.children
|
||||
?.filter((child) => showDebug || !debugDemos.includes(child.id))
|
||||
.map((child) => ({
|
||||
key: child.id,
|
||||
href: `#${child.id}`,
|
||||
title: (
|
||||
<span className={classNames(debugDemos.includes(child.id) && 'toc-debug')}>
|
||||
{child?.title}
|
||||
</span>
|
||||
),
|
||||
})),
|
||||
});
|
||||
|
||||
const anchorItems = useMemo(
|
||||
() =>
|
||||
(tab?.toc || meta.toc).reduce<AnchorItem[]>((result, item) => {
|
||||
if (item.depth === 2) {
|
||||
result.push({ ...item });
|
||||
} else if (item.depth === 3) {
|
||||
const parent = result[result.length - 1];
|
||||
if (parent) {
|
||||
parent.children = parent.children || [];
|
||||
parent.children.push({ ...item });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}, []),
|
||||
[tab?.toc, meta.toc],
|
||||
);
|
||||
|
||||
if (!meta.frontmatter.toc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={styles.tocWrapper}>
|
||||
<Anchor
|
||||
className={styles.toc}
|
||||
affix={false}
|
||||
targetOffset={token.anchorTop}
|
||||
showInkInFixed
|
||||
items={anchorItems.map(renderAnchorItem)}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocAnchor;
|
79
.dumi/theme/slots/Content/DocMeta.tsx
Normal file
79
.dumi/theme/slots/Content/DocMeta.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React, { useState, useLayoutEffect, useMemo } from 'react';
|
||||
import { Typography, Space, Skeleton, Avatar } from 'antd';
|
||||
import { useRouteMeta } from 'dumi';
|
||||
import DayJS from 'dayjs';
|
||||
import { CalendarOutlined } from '@ant-design/icons';
|
||||
|
||||
const AuthorAvatar: React.FC<{ name: string; avatar: string }> = ({ name, avatar }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
useLayoutEffect(() => {
|
||||
const img = new Image();
|
||||
img.src = avatar;
|
||||
img.onload = () => setLoading(false);
|
||||
img.onerror = () => setError(true);
|
||||
}, []);
|
||||
if (error) {
|
||||
return null;
|
||||
}
|
||||
if (loading) {
|
||||
return <Skeleton.Avatar size="small" active />;
|
||||
}
|
||||
return (
|
||||
<Avatar size="small" src={avatar} alt={name}>
|
||||
{name}
|
||||
</Avatar>
|
||||
);
|
||||
};
|
||||
|
||||
const DocMeta: React.FC<{}> = () => {
|
||||
const meta = useRouteMeta();
|
||||
|
||||
const mergedAuthorInfos = useMemo(() => {
|
||||
const { author } = meta.frontmatter;
|
||||
if (!author) {
|
||||
return [];
|
||||
}
|
||||
if (typeof author === 'string') {
|
||||
return author.split(',').map((item) => ({
|
||||
name: item,
|
||||
avatar: `https://github.com/${item}.png`,
|
||||
}));
|
||||
}
|
||||
if (Array.isArray(author)) {
|
||||
return author;
|
||||
}
|
||||
return [];
|
||||
}, [meta.frontmatter.author]);
|
||||
|
||||
if (!meta.frontmatter.date && !meta.frontmatter.author) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography.Paragraph>
|
||||
<Space>
|
||||
{meta.frontmatter.date && (
|
||||
<span style={{ opacity: 0.65 }}>
|
||||
<CalendarOutlined /> {DayJS(meta.frontmatter.date).format('YYYY-MM-DD')}
|
||||
</span>
|
||||
)}
|
||||
{mergedAuthorInfos.map((info) => (
|
||||
<a
|
||||
href={`https://github.com/${info.name}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key={info.name}
|
||||
>
|
||||
<Space size={3}>
|
||||
<AuthorAvatar name={info.name} avatar={info.avatar} />
|
||||
<span style={{ opacity: 0.65 }}>@{info.name}</span>
|
||||
</Space>
|
||||
</a>
|
||||
))}
|
||||
</Space>
|
||||
</Typography.Paragraph>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocMeta;
|
@ -1,94 +1,26 @@
|
||||
import { CalendarOutlined } from '@ant-design/icons';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import ContributorsList from '@qixian.cs/github-contributors-list';
|
||||
import classNames from 'classnames';
|
||||
import DayJS from 'dayjs';
|
||||
import { FormattedMessage, useIntl, useRouteMeta, useTabMeta } from 'dumi';
|
||||
import { FormattedMessage, useRouteMeta } from 'dumi';
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { Anchor, Avatar, Col, Skeleton, Space, Tooltip, Typography } from 'antd';
|
||||
import React, { Suspense, useContext, useLayoutEffect, useMemo } from 'react';
|
||||
import { Col, Space, Typography, Skeleton } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import useLayoutState from '../../../hooks/useLayoutState';
|
||||
import useLocation from '../../../hooks/useLocation';
|
||||
import EditButton from '../../common/EditButton';
|
||||
import PrevAndNext from '../../common/PrevAndNext';
|
||||
import ComponentChangelog from '../../common/ComponentChangelog';
|
||||
import type { DemoContextProps } from '../DemoContext';
|
||||
import DemoContext from '../DemoContext';
|
||||
import Footer from '../Footer';
|
||||
import SiteContext from '../SiteContext';
|
||||
import ColumnCard from './ColumnCard';
|
||||
|
||||
const useStyle = createStyles(({ token, css }) => {
|
||||
const { antCls } = token;
|
||||
const Contributors = React.lazy(() => import('./Contributors'));
|
||||
const ColumnCard = React.lazy(() => import('./ColumnCard'));
|
||||
const DocAnchor = React.lazy(() => import('./DocAnchor'));
|
||||
const DocMeta = React.lazy(() => import('./DocMeta'));
|
||||
const Footer = React.lazy(() => import('../Footer'));
|
||||
const PrevAndNext = React.lazy(() => import('../../common/PrevAndNext'));
|
||||
const ComponentChangelog = React.lazy(() => import('../../common/ComponentChangelog'));
|
||||
const EditButton = React.lazy(() => import('../../common/EditButton'));
|
||||
|
||||
return {
|
||||
contributorsList: css`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 120px !important;
|
||||
clear: both;
|
||||
|
||||
li {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
li,
|
||||
${antCls}-avatar + ${antCls}-avatar {
|
||||
transition: all ${token.motionDurationSlow};
|
||||
margin-inline-end: -8px;
|
||||
}
|
||||
&:hover {
|
||||
li,
|
||||
${antCls}-avatar {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
}
|
||||
`,
|
||||
listMobile: css`
|
||||
margin: 1em 0 !important;
|
||||
`,
|
||||
toc: css`
|
||||
${antCls}-anchor {
|
||||
${antCls}-anchor-link-title {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
`,
|
||||
tocWrapper: css`
|
||||
position: fixed;
|
||||
top: ${token.headerHeight + token.contentMarginTop}px;
|
||||
inset-inline-end: 0;
|
||||
width: 160px;
|
||||
margin: 0 0 12px 0;
|
||||
padding: 8px 0;
|
||||
padding-inline: 4px 8px;
|
||||
backdrop-filter: blur(8px);
|
||||
border-radius: ${token.borderRadius}px;
|
||||
box-sizing: border-box;
|
||||
z-index: 1000;
|
||||
|
||||
.toc-debug {
|
||||
color: ${token.purple6};
|
||||
|
||||
&:hover {
|
||||
color: ${token.purple5};
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 40px) !important;
|
||||
margin: 0 auto;
|
||||
overflow: auto;
|
||||
padding-inline: 4px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${token.screenLG}px) {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
articleWrapper: css`
|
||||
const useStyle = createStyles(({ token, css }) => ({
|
||||
articleWrapper: css`
|
||||
padding: 0 170px 32px 64px;
|
||||
|
||||
&.rtl {
|
||||
@ -102,53 +34,13 @@ const useStyle = createStyles(({ token, css }) => {
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
type AnchorItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
children?: AnchorItem[];
|
||||
};
|
||||
|
||||
const AvatarPlaceholder: React.FC<{ num?: number }> = ({ num = 3 }) => (
|
||||
<li>
|
||||
{Array.from({ length: num }).map((_, i) => (
|
||||
<Skeleton.Avatar size="small" active key={i} style={{ marginLeft: i === 0 ? 0 : -8 }} />
|
||||
))}
|
||||
</li>
|
||||
);
|
||||
|
||||
const AuthorAvatar: React.FC<{ name: string; avatar: string }> = ({ name, avatar }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
useLayoutEffect(() => {
|
||||
const img = new Image();
|
||||
img.src = avatar;
|
||||
img.onload = () => setLoading(false);
|
||||
img.onerror = () => setError(true);
|
||||
}, []);
|
||||
if (error) {
|
||||
return null;
|
||||
}
|
||||
if (loading) {
|
||||
return <Skeleton.Avatar size="small" active />;
|
||||
}
|
||||
return (
|
||||
<Avatar size="small" src={avatar} alt={name}>
|
||||
{name}
|
||||
</Avatar>
|
||||
);
|
||||
};
|
||||
}));
|
||||
|
||||
const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const meta = useRouteMeta();
|
||||
const tab = useTabMeta();
|
||||
const { pathname, hash } = useLocation();
|
||||
const { formatMessage } = useIntl();
|
||||
const { direction } = useContext(SiteContext);
|
||||
const { styles } = useStyle();
|
||||
const token = useTheme();
|
||||
const { direction, isMobile } = useContext(SiteContext);
|
||||
|
||||
const [showDebug, setShowDebug] = useLayoutState(false);
|
||||
const debugDemos = useMemo(
|
||||
@ -167,71 +59,14 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
[showDebug, debugDemos],
|
||||
);
|
||||
|
||||
const anchorItems = useMemo(
|
||||
() =>
|
||||
(tab?.toc || meta.toc).reduce<AnchorItem[]>((result, item) => {
|
||||
if (item.depth === 2) {
|
||||
result.push({ ...item });
|
||||
} else if (item.depth === 3) {
|
||||
const parent = result[result.length - 1];
|
||||
if (parent) {
|
||||
parent.children = parent.children || [];
|
||||
parent.children.push({ ...item });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}, []),
|
||||
[tab?.toc, meta.toc],
|
||||
);
|
||||
|
||||
const isRTL = direction === 'rtl';
|
||||
|
||||
const mergedAuthorInfos = useMemo(() => {
|
||||
const { author } = meta.frontmatter;
|
||||
if (!author) {
|
||||
return [];
|
||||
}
|
||||
if (typeof author === 'string') {
|
||||
return author.split(',').map((item) => ({
|
||||
name: item,
|
||||
avatar: `https://github.com/${item}.png`,
|
||||
}));
|
||||
}
|
||||
if (Array.isArray(author)) {
|
||||
return author;
|
||||
}
|
||||
return [];
|
||||
}, [meta.frontmatter.author]);
|
||||
|
||||
return (
|
||||
<DemoContext.Provider value={contextValue}>
|
||||
<Col xxl={20} xl={19} lg={18} md={18} sm={24} xs={24}>
|
||||
{!!meta.frontmatter.toc && (
|
||||
<section className={styles.tocWrapper}>
|
||||
<Anchor
|
||||
className={styles.toc}
|
||||
affix={false}
|
||||
targetOffset={token.anchorTop}
|
||||
showInkInFixed
|
||||
items={anchorItems.map((item) => ({
|
||||
href: `#${item.id}`,
|
||||
title: item.title,
|
||||
key: item.id,
|
||||
children: item.children
|
||||
?.filter((child) => showDebug || !debugDemos.includes(child.id))
|
||||
.map((child) => ({
|
||||
key: child.id,
|
||||
href: `#${child.id}`,
|
||||
title: (
|
||||
<span className={classNames(debugDemos.includes(child.id) && 'toc-debug')}>
|
||||
{child?.title}
|
||||
</span>
|
||||
),
|
||||
})),
|
||||
}))}
|
||||
/>
|
||||
</section>
|
||||
)}
|
||||
<Suspense fallback={<Skeleton.Input active size="small" />}>
|
||||
<DocAnchor showDebug={showDebug} debugDemos={debugDemos} />
|
||||
</Suspense>
|
||||
<article className={classNames(styles.articleWrapper, { rtl: isRTL })}>
|
||||
{meta.frontmatter?.title ? (
|
||||
<Typography.Title style={{ fontSize: 30, position: 'relative' }}>
|
||||
@ -240,90 +75,43 @@ const Content: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
{meta.frontmatter?.subtitle}
|
||||
|
||||
{!pathname.startsWith('/components/overview') && (
|
||||
<EditButton
|
||||
title={<FormattedMessage id="app.content.edit-page" />}
|
||||
filename={meta.frontmatter.filename}
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<EditButton
|
||||
title={<FormattedMessage id="app.content.edit-page" />}
|
||||
filename={meta.frontmatter.filename}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
</Space>
|
||||
{pathname.startsWith('/components/') && <ComponentChangelog pathname={pathname} />}
|
||||
{pathname.startsWith('/components/') && (
|
||||
<Suspense fallback={null}>
|
||||
<ComponentChangelog pathname={pathname} />
|
||||
</Suspense>
|
||||
)}
|
||||
</Typography.Title>
|
||||
) : null}
|
||||
{/* 添加作者、时间等信息 */}
|
||||
{meta.frontmatter.date || meta.frontmatter.author ? (
|
||||
<Typography.Paragraph>
|
||||
<Space>
|
||||
{meta.frontmatter.date && (
|
||||
<span style={{ opacity: 0.65 }}>
|
||||
<CalendarOutlined /> {DayJS(meta.frontmatter.date).format('YYYY-MM-DD')}
|
||||
</span>
|
||||
)}
|
||||
{mergedAuthorInfos.map((info) => (
|
||||
<a
|
||||
href={`https://github.com/${info.name}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
key={info.name}
|
||||
>
|
||||
<Space size={3}>
|
||||
<AuthorAvatar name={info.name} avatar={info.avatar} />
|
||||
<span style={{ opacity: 0.65 }}>@{info.name}</span>
|
||||
</Space>
|
||||
</a>
|
||||
))}
|
||||
</Space>
|
||||
</Typography.Paragraph>
|
||||
) : null}
|
||||
<Suspense fallback={<Skeleton.Input active size="small" />}>
|
||||
<DocMeta />
|
||||
</Suspense>
|
||||
{!meta.frontmatter.__autoDescription && meta.frontmatter.description}
|
||||
<div style={{ minHeight: 'calc(100vh - 64px)' }}>{children}</div>
|
||||
{(meta.frontmatter?.zhihu_url ||
|
||||
meta.frontmatter?.yuque_url ||
|
||||
meta.frontmatter?.juejin_url) && (
|
||||
<Suspense fallback={<Skeleton.Input active size="small" />}>
|
||||
<ColumnCard
|
||||
zhihuLink={meta.frontmatter.zhihu_url}
|
||||
yuqueLink={meta.frontmatter.yuque_url}
|
||||
juejinLink={meta.frontmatter.juejin_url}
|
||||
/>
|
||||
)}
|
||||
{meta.frontmatter.filename && (
|
||||
<ContributorsList
|
||||
cache
|
||||
repo="ant-design"
|
||||
owner="ant-design"
|
||||
className={classNames(styles.contributorsList, { [styles.listMobile]: isMobile })}
|
||||
fileName={meta.frontmatter.filename}
|
||||
renderItem={(item, loading) => {
|
||||
if (!item || loading) {
|
||||
return <AvatarPlaceholder />;
|
||||
}
|
||||
if (item.username?.includes('github-actions')) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Tooltip
|
||||
mouseEnterDelay={0.3}
|
||||
title={`${formatMessage({ id: 'app.content.contributors' })}: ${item.username}`}
|
||||
key={item.username}
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href={`https://github.com/${item.username}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Avatar size="small" src={item.url} alt={item.username}>
|
||||
{item.username}
|
||||
</Avatar>
|
||||
</a>
|
||||
</li>
|
||||
</Tooltip>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Suspense>
|
||||
<Suspense fallback={<Skeleton.Input active size="small" />}>
|
||||
<Contributors filename={meta.frontmatter.filename} />
|
||||
</Suspense>
|
||||
</article>
|
||||
<PrevAndNext rtl={isRTL} />
|
||||
<Footer />
|
||||
<Suspense fallback={<Skeleton.Input active size="small" />}>
|
||||
<PrevAndNext rtl={isRTL} />
|
||||
</Suspense>
|
||||
<Suspense fallback={null}>
|
||||
<Footer />
|
||||
</Suspense>
|
||||
</Col>
|
||||
</DemoContext.Provider>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user