import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { useLocation } from 'dumi'; import DumiSearchBar from 'dumi/theme-default/slots/SearchBar'; import classNames from 'classnames'; import { Col, Modal, Popover, Row, Select, Typography } from 'antd'; import { GithubOutlined, MenuOutlined } from '@ant-design/icons'; import { ClassNames, css } from '@emotion/react'; import * as utils from '../../utils'; import { getThemeConfig, ping } from '../../utils'; import packageJson from '../../../../package.json'; import Logo from './Logo'; import More from './More'; import Navigation from './Navigation'; import type { SiteContextProps } from '../SiteContext'; import SiteContext from '../SiteContext'; import useSiteToken from '../../../hooks/useSiteToken'; import useLocale from '../../../hooks/useLocale'; import SwitchBtn from './SwitchBtn'; const RESPONSIVE_XS = 1120; const RESPONSIVE_SM = 1200; const { Option } = Select; const antdVersion: string = packageJson.version; const locales = { cn: { title: '๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰ Ant Design 5.0 ๅ‘ๅธƒ๏ผ ๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰', ok: '็Ÿฅ้“ไบ†', }, en: { title: '๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰ Ant Design 5.0 is released! ๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰', ok: 'Got it', }, }; const useStyle = () => { const { token } = useSiteToken(); const searchIconColor = '#ced4d9'; return { header: css` position: relative; z-index: 10; max-width: 100%; background: ${token.colorBgContainer}; box-shadow: ${token.boxShadow}; @media only screen and (max-width: ${token.mobileMaxWidth}px) { text-align: center; } .nav-search-wrapper { display: flex; flex: auto; } .dumi-default-search-bar { border-inline-start: 1px solid rgba(0, 0, 0, 0.06); > svg { width: 14px; fill: ${searchIconColor}; } > input { height: 22px; border: 0; &:focus { box-shadow: none; } &::placeholder { color: ${searchIconColor}; } } .dumi-default-search-shortcut { color: ${searchIconColor}; background-color: rgba(150, 150, 150, 0.06); border-color: rgba(100, 100, 100, 0.2); border-radius: 4px; } .dumi-default-search-popover { inset-inline-start: 11px; inset-inline-end: unset; &::before { inset-inline-start: 100px; inset-inline-end: unset; } } } `, menuRow: css` display: flex; align-items: center; margin: 0; > * { flex: none; margin: 0; margin-inline-end: 12px; &:last-child { margin-inline-end: 40px; } } `, popoverMenu: { width: 300, [`${token.antCls}-popover-inner-content`]: { padding: 0, }, }, }; }; const V5_NOTIFICATION = 'antd@4.0.0-notification-sent'; const SHOULD_OPEN_ANT_DESIGN_MIRROR_MODAL = 'ANT_DESIGN_DO_NOT_OPEN_MIRROR_MODAL'; function disableAntdMirrorModal() { window.localStorage.setItem(SHOULD_OPEN_ANT_DESIGN_MIRROR_MODAL, 'true'); } function shouldOpenAntdMirrorModal() { return !window.localStorage.getItem(SHOULD_OPEN_ANT_DESIGN_MIRROR_MODAL); } interface HeaderState { menuVisible: boolean; windowWidth: number; searching: boolean; } // ================================= Header ================================= const Header: React.FC = () => { const [isClient, setIsClient] = React.useState(false); const [locale, lang] = useLocale(locales); const { token } = useSiteToken(); const [notify, setNotify] = React.useState(null); // ========================= ๅ‘ๅธƒ้€š็Ÿฅ ๅผ€ๅง‹ ========================= React.useEffect(() => { if (utils.isLocalStorageNameSupported()) { // ๅคง็‰ˆๆœฌๅ‘ๅธƒๅŽๅ…จๅฑ€ๅผน็ช—ๆ็คบ // 1. ็‚นๅ‡ปใ€Ž็Ÿฅ้“ไบ†ใ€ไน‹ๅŽไธๅ†ๆ็คบ // 2. ่ถ…่ฟ‡ๆˆชๆญขๆ—ฅๆœŸๅŽไธๅ†ๆ็คบ if ( localStorage.getItem(V5_NOTIFICATION) !== 'true' && Date.now() < new Date('2022/12/31').getTime() ) { setNotify(true); return; } } setNotify(false); }, []); function onClose() { setNotify(false); localStorage.setItem(V5_NOTIFICATION, 'true'); } // ========================= ๅ‘ๅธƒ้€š็Ÿฅ ็ป“ๆŸ ========================= const themeConfig = getThemeConfig(); const [headerState, setHeaderState] = useState({ menuVisible: false, windowWidth: 1400, searching: false, }); const { direction, isMobile, updateSiteConfig } = useContext(SiteContext); const pingTimer = useRef(null); const location = useLocation(); const { pathname, search } = location; const style = useStyle(); const handleHideMenu = useCallback(() => { setHeaderState((prev) => ({ ...prev, menuVisible: false })); }, []); const onWindowResize = useCallback(() => { setHeaderState((prev) => ({ ...prev, windowWidth: window.innerWidth })); }, []); const handleShowMenu = useCallback(() => { setHeaderState((prev) => ({ ...prev, menuVisible: true })); }, []); const onMenuVisibleChange = useCallback((visible: boolean) => { setHeaderState((prev) => ({ ...prev, menuVisible: visible })); }, []); const onDirectionChange = () => { updateSiteConfig({ direction: direction !== 'rtl' ? 'rtl' : 'ltr' }); }; useEffect(() => { handleHideMenu(); }, [location]); useEffect(() => { setIsClient(typeof window !== 'undefined'); onWindowResize(); window.addEventListener('resize', onWindowResize); pingTimer.current = ping((status) => { if (status !== 'timeout' && status !== 'error') { if ( // process.env.NODE_ENV === 'production' && window.location.host !== 'ant-design.antgroup.com' && shouldOpenAntdMirrorModal() ) { Modal.confirm({ title: 'ๆ็คบ', content: 'ๅ†…็ฝ‘็”จๆˆทๆŽจ่่ฎฟ้—ฎๅ›ฝๅ†…้•œๅƒไปฅ่Žทๅพ—ๆž้€Ÿไฝ“้ชŒ๏ฝž', okText: '๐Ÿš€ ็ซ‹ๅˆปๅ‰ๅพ€', cancelText: 'ไธๅ†ๅผนๅ‡บ', closable: true, zIndex: 99999, onOk() { window.open('https://ant-design.antgroup.com', '_self'); disableAntdMirrorModal(); }, onCancel() { disableAntdMirrorModal(); }, }); } } }); return () => { window.removeEventListener('resize', onWindowResize); if (pingTimer.current) { clearTimeout(pingTimer.current); } }; }, []); // eslint-disable-next-line class-methods-use-this const handleVersionChange = useCallback((url: string) => { const currentUrl = window.location.href; const currentPathname = window.location.pathname; if (/overview/.test(currentPathname) && /0?[1-39][0-3]?x/.test(url)) { window.location.href = currentUrl .replace(window.location.origin, url) .replace(/\/components\/overview/, `/docs${/0(9|10)x/.test(url) ? '' : '/react'}/introduce`) .replace(/\/$/, ''); return; } window.location.href = currentUrl.replace(window.location.origin, url); }, []); const onLangChange = useCallback(() => { const currentProtocol = `${window.location.protocol}//`; const currentHref = window.location.href.slice(currentProtocol.length); if (utils.isLocalStorageNameSupported()) { localStorage.setItem('locale', utils.isZhCN(pathname) ? 'en-US' : 'zh-CN'); } window.location.href = currentProtocol + currentHref.replace( window.location.pathname, utils.getLocalizedPathname(pathname, !utils.isZhCN(pathname), search).pathname, ); }, [location]); const nextDirectionText = useMemo( () => (direction !== 'rtl' ? 'RTL' : 'LTR'), [direction], ); const getDropdownStyle = useMemo( () => (direction === 'rtl' ? { direction: 'ltr', textAlign: 'right' } : {}), [direction], ); const { menuVisible, windowWidth, searching } = headerState; const docVersions: Record = { [antdVersion]: antdVersion, ...themeConfig?.docVersions, }; const versionOptions = Object.keys(docVersions).map((version) => ( )); const isHome = ['', 'index', 'index-cn'].includes(pathname); const isZhCN = lang === 'cn'; const isRTL = direction === 'rtl'; let responsive: null | 'narrow' | 'crowded' = null; if (windowWidth < RESPONSIVE_XS) { responsive = 'crowded'; } else if (windowWidth < RESPONSIVE_SM) { responsive = 'narrow'; } const headerClassName = classNames({ clearfix: true, 'home-header': isHome, }); const sharedProps = { isZhCN, isRTL, isClient, }; const navigationNode = ( ); let menu: (React.ReactElement | null)[] = [ navigationNode, {lang === 'cn' ? ( <>
ๅฆ‚ๆžœไฝ ๅ‘็Žฐไปปไฝ•ๆ–ฐๅฎ˜็ฝ‘็š„้—ฎ้ข˜๏ผŒๆฌข่ฟŽๅˆฐ{' '} GitHub Issue {' '} ๅ้ฆˆใ€‚
ๅฆ‚ๆžœไฝ ้œ€่ฆๆŸฅ็œ‹ v4 ๆ–‡ๆกฃ๏ผŒ่ฏท็‚นๅ‡ปไธŠไพงๅˆ‡ๆขใ€‚
) : ( <>
If you find any official site problem. Please feel free to report on{' '} GitHub Issue .

Click above Select to switch to v4 docs.

)} } >
, , , } tooltip1="LTR" label2={ LTR } tooltip2="RTL" pure />, } tooltip1="Github" label2={null} pure /> , ]; if (windowWidth < RESPONSIVE_XS) { menu = searching ? [] : [navigationNode]; } else if (windowWidth < RESPONSIVE_SM) { menu = searching ? [] : menu; } const colProps = isHome ? [{ flex: 'none' }, { flex: 'auto' }] : [ { xxl: 4, xl: 5, lg: 6, md: 6, sm: 24, xs: 24 }, { xxl: 20, xl: 19, lg: 18, md: 18, sm: 0, xs: 0 }, ]; return (
{isMobile && ( {({ css: cssFn }) => ( )} )}
{!isMobile && menu}
); }; export default Header;