mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 02:49:18 +08:00
chore(site): In order to better debug the online demo (#56072)
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import React, { Suspense, useRef } from 'react';
|
||||
import { LinkOutlined, ThunderboltOutlined } from '@ant-design/icons';
|
||||
import { BugOutlined, ThunderboltOutlined } from '@ant-design/icons';
|
||||
import stackblitzSdk from '@stackblitz/sdk';
|
||||
import { Flex, Tooltip } from 'antd';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Button, Dropdown, Flex, Tooltip } from 'antd';
|
||||
import { FormattedMessage, useSiteData } from 'dumi';
|
||||
import LZString from 'lz-string';
|
||||
|
||||
@@ -28,8 +29,6 @@ function compress(string: string): string {
|
||||
}
|
||||
|
||||
interface ActionsProps {
|
||||
showOnlineUrl: boolean;
|
||||
docsOnlineUrl?: string;
|
||||
assetId: string;
|
||||
title?: string;
|
||||
pkgDependencyList: Record<PropertyKey, string>;
|
||||
@@ -39,11 +38,10 @@ interface ActionsProps {
|
||||
onCodeExpand: () => void;
|
||||
entryCode: string;
|
||||
styleCode: string;
|
||||
debugOptions?: MenuProps['items'];
|
||||
}
|
||||
|
||||
const Actions: React.FC<ActionsProps> = ({
|
||||
showOnlineUrl,
|
||||
docsOnlineUrl,
|
||||
assetId,
|
||||
title,
|
||||
jsx,
|
||||
@@ -53,6 +51,7 @@ const Actions: React.FC<ActionsProps> = ({
|
||||
pkgDependencyList,
|
||||
entryCode,
|
||||
styleCode,
|
||||
debugOptions,
|
||||
}) => {
|
||||
const [, lang] = useLocale();
|
||||
const isZhCN = lang === 'cn';
|
||||
@@ -213,21 +212,15 @@ createRoot(document.getElementById('container')).render(<Demo />);
|
||||
});
|
||||
|
||||
return (
|
||||
<Flex wrap gap="middle" className="code-box-actions">
|
||||
{/* 在线文档按钮 */}
|
||||
{showOnlineUrl && (
|
||||
<Tooltip title={<FormattedMessage id="app.demo.online" />}>
|
||||
<a
|
||||
className="code-box-code-action"
|
||||
aria-label="open in new tab"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={docsOnlineUrl || ''}
|
||||
>
|
||||
<LinkOutlined className="code-box-online" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Flex wrap gap="middle" className="code-box-actions" align="center">
|
||||
{
|
||||
// 调试选项
|
||||
debugOptions?.length ? (
|
||||
<Dropdown menu={{ items: debugOptions }} arrow={{ pointAtCenter: true }}>
|
||||
<Button icon={<BugOutlined />} color="purple" variant="filled" size="small" />
|
||||
</Dropdown>
|
||||
) : null
|
||||
}
|
||||
{/* CodeSandbox 按钮 */}
|
||||
<form
|
||||
className="code-box-code-action"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { UpOutlined } from '@ant-design/icons';
|
||||
import { Badge, Tooltip } from 'antd';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Badge, Tag, Tooltip } from 'antd';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { clsx } from 'clsx';
|
||||
import { FormattedMessage, useLiveDemo } from 'dumi';
|
||||
|
||||
import { FormattedMessage, useLiveDemo, useSiteData } from 'dumi';
|
||||
import { major, minVersion } from 'semver';
|
||||
import type { AntdPreviewerProps } from '.';
|
||||
import useLocation from '../../../hooks/useLocation';
|
||||
import BrowserFrame from '../../common/BrowserFrame';
|
||||
@@ -12,6 +13,8 @@ import ClientOnly from '../../common/ClientOnly';
|
||||
import CodePreview from '../../common/CodePreview';
|
||||
import EditButton from '../../common/EditButton';
|
||||
import SiteContext from '../../slots/SiteContext';
|
||||
import DemoContext from '../../slots/DemoContext';
|
||||
import { isOfficialHost } from '../../utils';
|
||||
import Actions from './Actions';
|
||||
|
||||
const useStyle = createStyles(({ cssVar }) => {
|
||||
@@ -61,6 +64,9 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
clientOnly,
|
||||
pkgDependencyList,
|
||||
} = props;
|
||||
const { showDebug } = React.use(DemoContext);
|
||||
const { pkg } = useSiteData();
|
||||
|
||||
const location = useLocation();
|
||||
const { styles } = useStyle();
|
||||
|
||||
@@ -79,17 +85,15 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
const anchorRef = useRef<HTMLAnchorElement>(null);
|
||||
const [codeExpand, setCodeExpand] = useState<boolean>(false);
|
||||
const { isDark } = React.use(SiteContext);
|
||||
|
||||
const { hash, pathname, search } = location;
|
||||
const docsOnlineUrl = `https://ant.design${pathname ?? ''}${search ?? ''}#${asset.id}`;
|
||||
|
||||
const [showOnlineUrl, setShowOnlineUrl] = useState<boolean>(false);
|
||||
|
||||
/**
|
||||
* Record whether it is deployed on the official domain name.
|
||||
* Note that window.location.hostname is not available on the server side due to hydration issues
|
||||
*/
|
||||
const [deployedOnOfficialHost, setDeployedOnOfficialHost] = useState<boolean>(true);
|
||||
useEffect(() => {
|
||||
const regexp = /preview-(\d+)-ant-design/; // matching PR preview addresses
|
||||
setShowOnlineUrl(
|
||||
process.env.NODE_ENV === 'development' || regexp.test(window.location.hostname),
|
||||
);
|
||||
setDeployedOnOfficialHost(isOfficialHost(window.location.hostname));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -102,6 +106,33 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
setCodeExpand(expand);
|
||||
}, [expand]);
|
||||
|
||||
const generateDocUrl = (domain = 'https://ant.design') =>
|
||||
`${domain}${pathname ?? ''}${search ?? ''}#${asset.id}`;
|
||||
|
||||
// Enable "Go Online Docs" only when deployed on non-official domains
|
||||
const enableDocsOnlineUrl = process.env.NODE_ENV === 'development' || !deployedOnOfficialHost;
|
||||
|
||||
// Previous version demos are only available during the maintenance window
|
||||
const [supportsPreviousVersionDemo, previousVersionDomain, previousVersion] = useMemo(() => {
|
||||
const maintenanceDeadline = new Date('2026/12/31');
|
||||
|
||||
if (new Date() > maintenanceDeadline) {
|
||||
return [false, undefined, -1] as const;
|
||||
}
|
||||
|
||||
const currentMajor = major(pkg.version);
|
||||
const previousMajor = Math.min(currentMajor - 1, 5);
|
||||
|
||||
let enabled = true;
|
||||
// If the demo specifies a version, perform an additional check;
|
||||
if (version) {
|
||||
const minVer = minVersion(version);
|
||||
enabled = minVer?.major ? minVer.major < currentMajor : true;
|
||||
}
|
||||
|
||||
return [enabled, `https://${previousMajor}x.ant.design`, previousMajor];
|
||||
}, [version, pkg.version]);
|
||||
|
||||
const mergedChildren = !iframe && clientOnly ? <ClientOnly>{children}</ClientOnly> : children;
|
||||
const demoUrlWithTheme = useMemo(() => {
|
||||
return `${demoUrl}${isDark ? '?theme=dark' : ''}`;
|
||||
@@ -143,6 +174,47 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
backgroundColor: background === 'grey' ? backgroundGrey : undefined,
|
||||
};
|
||||
|
||||
const debugOptions: MenuProps['items'] = [
|
||||
{
|
||||
key: 'online',
|
||||
label: (
|
||||
<a
|
||||
aria-label="Go to online documentation"
|
||||
href={generateDocUrl()}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<FormattedMessage id="app.demo.online" />
|
||||
</a>
|
||||
),
|
||||
icon: (
|
||||
<Tag variant="filled" color="blue">
|
||||
ant.design
|
||||
</Tag>
|
||||
),
|
||||
enabled: enableDocsOnlineUrl,
|
||||
},
|
||||
{
|
||||
key: 'previousVersion',
|
||||
label: (
|
||||
<a
|
||||
aria-label="Go to previous version documentation"
|
||||
href={generateDocUrl(previousVersionDomain)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<FormattedMessage id="app.demo.previousVersion" values={{ version: previousVersion }} />
|
||||
</a>
|
||||
),
|
||||
icon: (
|
||||
<Tag variant="filled" color="purple">
|
||||
v{previousVersion}
|
||||
</Tag>
|
||||
),
|
||||
enabled: supportsPreviousVersionDemo,
|
||||
},
|
||||
].filter(({ enabled }) => showDebug && enabled);
|
||||
|
||||
const codeBox: React.ReactNode = (
|
||||
<section className={codeBoxClass} id={asset.id}>
|
||||
<section
|
||||
@@ -174,8 +246,7 @@ const CodePreviewer: React.FC<AntdPreviewerProps> = (props) => {
|
||||
/>
|
||||
)}
|
||||
<Actions
|
||||
showOnlineUrl={showOnlineUrl}
|
||||
docsOnlineUrl={docsOnlineUrl}
|
||||
debugOptions={debugOptions}
|
||||
entryCode={entryCode}
|
||||
styleCode={style}
|
||||
pkgDependencyList={pkgDependencyList}
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
"app.demo.stackblitz": "Open in Stackblitz",
|
||||
"app.demo.codeblock": "Open in Hitu (This feature is only available in the internal network environment)",
|
||||
"app.demo.separate": "Open in a new window",
|
||||
"app.demo.online": "Online Address",
|
||||
"app.demo.online": "Official demo",
|
||||
"app.demo.previousVersion": "Previous version",
|
||||
"app.home.introduce": "A design system for enterprise-level products. Create an efficient and enjoyable work experience.",
|
||||
"app.home.pr-welcome": "💡 It is an alpha version and still in progress. Contribution from community is welcome!",
|
||||
"app.home.recommend": "Recommended",
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
"app.demo.stackblitz": "在 Stackblitz 中打开",
|
||||
"app.demo.codeblock": "在海兔中打开(此功能仅在内网环境可用)",
|
||||
"app.demo.separate": "在新窗口打开",
|
||||
"app.demo.online": "线上地址",
|
||||
"app.demo.online": "官网示例",
|
||||
"app.demo.previousVersion": "历史版本",
|
||||
"app.home.introduce": "企业级产品设计体系,创造高效愉悦的工作体验",
|
||||
"app.home.pr-welcome": "💡 当前为 alpha 版本,仍在开发中。欢迎社区一起共建,让 Ant Design 变得更好!",
|
||||
"app.home.recommend": "精彩推荐",
|
||||
|
||||
@@ -206,4 +206,14 @@ export function matchDeprecated(v: string): MatchDeprecatedResult {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a hostname is an official domain.
|
||||
* antd creates a temporary preview site for each PR for convenient preview and testing.
|
||||
* Usually on platforms like surge.sh or Cloudflare Pages.
|
||||
*/
|
||||
export function isOfficialHost(hostname: string) {
|
||||
const officialHostnames = ['ant.design', 'antgroup.com'];
|
||||
return officialHostnames.some((official) => hostname.includes(official));
|
||||
}
|
||||
|
||||
export const getThemeConfig = () => themeConfig;
|
||||
|
||||
Reference in New Issue
Block a user