chore(site): improve site (#39504)

* chore: merge context

* chore:  theme context

* chore(site): improve site

* chore: update components overview url

* chore: update

* chore: remove default theme button

* chore: update

* chore: update
This commit is contained in:
Wuxh 2022-12-19 11:42:41 +08:00 committed by GitHub
parent 1eaf125528
commit 36abb3df4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 182 additions and 190 deletions

View File

@ -3,10 +3,10 @@ import { Button, Space, Typography } from 'antd';
import { Link, useLocation } from 'dumi';
import { css } from '@emotion/react';
import useLocale from '../../../hooks/useLocale';
import SiteContext from '../../../theme/slots/SiteContext';
import useSiteToken from '../../../hooks/useSiteToken';
import { GroupMask } from './Group';
import * as utils from '../../../theme/utils';
import SiteContext from './SiteContext';
const locales = {
cn: {

View File

@ -4,7 +4,7 @@ import type { SerializedStyles } from '@emotion/react';
import { css } from '@emotion/react';
import type { Extra, Icon } from './util';
import useSiteToken from '../../../hooks/useSiteToken';
import SiteContext from './SiteContext';
import SiteContext from '../../../theme/slots/SiteContext';
import { useCarouselStyle } from './util';
const useStyle = () => {
@ -65,14 +65,20 @@ const RecommendItem = ({ extra, index, icons, itemCss }: RecommendItemProps) =>
const icon = icons.find((i) => i.name === extra.source);
return (
<a key={extra?.title} href={extra.href} target="_blank" css={[style.itemBase, itemCss]} rel="noreferrer">
<a
key={extra?.title}
href={extra.href}
target="_blank"
css={[style.itemBase, itemCss]}
rel="noreferrer"
>
<Typography.Title level={5}>{extra?.title}</Typography.Title>
<Typography.Paragraph type="secondary" style={{ flex: 'auto' }}>
{extra.description}
</Typography.Paragraph>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Typography.Text>{extra.date}</Typography.Text>
{icon && <img src={icon.href} style={{ height: token.fontSize }} alt="banner"/>}
{icon && <img src={icon.href} style={{ height: token.fontSize }} alt="banner" />}
</div>
</a>
);
@ -119,4 +125,3 @@ export default function BannerRecommends({ extras = [], icons = [] }: BannerReco
</div>
);
}

View File

@ -17,7 +17,7 @@ import { CustomerServiceOutlined, QuestionCircleOutlined, SyncOutlined } from '@
import { css } from '@emotion/react';
import useSiteToken from '../../../hooks/useSiteToken';
import useLocale from '../../../hooks/useLocale';
import SiteContext from './SiteContext';
import SiteContext from '../../../theme/slots/SiteContext';
import { useCarouselStyle } from './util';
const SAMPLE_CONTENT_EN =

View File

@ -5,7 +5,7 @@ import { Link, useLocation } from 'dumi';
import useLocale from '../../../hooks/useLocale';
import useSiteToken from '../../../hooks/useSiteToken';
import * as utils from '../../../theme/utils';
import SiteContext from './SiteContext';
import SiteContext from '../../../theme/slots/SiteContext';
const SECONDARY_LIST = [
{

View File

@ -2,7 +2,7 @@ import * as React from 'react';
import { useContext } from 'react';
import { Typography } from 'antd';
import useSiteToken from '../../../hooks/useSiteToken';
import SiteContext from './SiteContext';
import SiteContext from '../../../theme/slots/SiteContext';
export interface GroupMaskProps {
style?: React.CSSProperties;

View File

@ -1,11 +0,0 @@
import * as React from 'react';
export interface SiteContextProps {
isMobile: boolean;
}
const SiteContext = React.createContext<SiteContextProps>({
isMobile: false,
});
export default SiteContext;

View File

@ -30,7 +30,7 @@ import RadiusPicker from './RadiusPicker';
import Group from '../Group';
import BackgroundImage from './BackgroundImage';
import { DEFAULT_COLOR, getAvatarURL, getClosetColor, PINK_COLOR } from './colorUtil';
import SiteContext from '../SiteContext';
import SiteContext from '../../../../theme/slots/SiteContext';
import { useCarouselStyle } from '../util';
import MobileCarousel from './MobileCarousel';

View File

@ -1,4 +1,4 @@
import React, { useEffect, useMemo } from 'react';
import React from 'react';
import { useLocale as useDumiLocale } from 'dumi';
import { ConfigProvider } from 'antd';
import useLocale from '../../hooks/useLocale';
@ -9,7 +9,6 @@ import Theme from './components/Theme';
import BannerRecommends from './components/BannerRecommends';
import ComponentsList from './components/ComponentsList';
import DesignFramework from './components/DesignFramework';
import SiteContext from './components/SiteContext';
const locales = {
cn: {
@ -34,61 +33,44 @@ const Homepage: React.FC = () => {
const localeStr = localeId === 'zh-CN' ? 'cn' : 'en';
const [siteData] = useSiteData();
const [isMobile, setIsMobile] = React.useState<boolean>(false);
const updateMobileMode = () => {
setIsMobile(window.innerWidth < 768);
};
useEffect(() => {
updateMobileMode();
window.addEventListener('resize', updateMobileMode);
return () => {
window.removeEventListener('resize', updateMobileMode);
};
}, []);
const siteValue = useMemo(() => ({ isMobile }), [isMobile]);
return (
<ConfigProvider theme={{ algorithm: undefined }}>
<SiteContext.Provider value={siteValue}>
<section>
<Banner>
<BannerRecommends extras={siteData?.extras?.[localeStr]} icons={siteData?.icons} />
</Banner>
<section>
<Banner>
<BannerRecommends extras={siteData?.extras?.[localeStr]} icons={siteData?.icons} />
</Banner>
<div>
<Theme />
<Group
background="#fff"
collapse
title={locale.assetsTitle}
description={locale.assetsDesc}
id="design"
>
<ComponentsList />
</Group>
<Group
title={locale.designTitle}
description={locale.designDesc}
background="#F5F8FF"
decoration={
<>
{/* Image Left Top */}
<img
style={{ position: 'absolute', left: 0, top: -50, height: 160 }}
src="https://gw.alipayobjects.com/zos/bmw-prod/ba37a413-28e6-4be4-b1c5-01be1a0ebb1c.svg"
alt=""
/>
</>
}
>
<DesignFramework />
</Group>
</div>
</section>
</SiteContext.Provider>
<div>
<Theme />
<Group
background="#fff"
collapse
title={locale.assetsTitle}
description={locale.assetsDesc}
id="design"
>
<ComponentsList />
</Group>
<Group
title={locale.designTitle}
description={locale.designDesc}
background="#F5F8FF"
decoration={
<>
{/* Image Left Top */}
<img
style={{ position: 'absolute', left: 0, top: -50, height: 160 }}
src="https://gw.alipayobjects.com/zos/bmw-prod/ba37a413-28e6-4be4-b1c5-01be1a0ebb1c.svg"
alt=""
/>
</>
}
>
<DesignFramework />
</Group>
</div>
</section>
</ConfigProvider>
);
};

View File

@ -1,5 +1,5 @@
import React, { memo, useMemo, useState } from 'react';
import { Link, useIntl, useSidebarData } from 'dumi';
import { Link, useIntl, useSidebarData, useLocation } from 'dumi';
import { css } from '@emotion/react';
import debounce from 'lodash/debounce';
import { Card, Col, Divider, Input, Row, Space, Tag, Typography } from 'antd';
@ -16,7 +16,6 @@ const useStyle = () => {
padding: 0;
`,
componentsOverviewGroupTitle: css`
font-size: 24px;
margin-bottom: 24px !important;
`,
componentsOverviewTitle: css`
@ -38,22 +37,7 @@ const useStyle = () => {
}
`,
componentsOverviewSearch: css`
&${token.antCls}-input-affix-wrapper {
width: 100%;
padding: 0;
font-size: 20px;
border: 0;
box-shadow: none;
input {
color: rgba(0, 0, 0, 0.85);
font-size: 20px;
}
.anticon {
color: #bbb;
}
}
font-size: ${token.fontSizeXL}px;
`,
};
};
@ -81,7 +65,7 @@ const { Title } = Typography;
const Overview: React.FC = () => {
const style = useStyle();
const data = useSidebarData();
const { search: urlSearch } = useLocation();
const { locale, formatMessage } = useIntl();
const [search, setSearch] = useState<string>('');
@ -131,7 +115,8 @@ const Overview: React.FC = () => {
reportSearch(e.target.value);
}}
onKeyDown={onKeyDown}
autoFocus // eslint-disable-line jsx-a11y/no-autofocus
bordered={false}
autoFocus
suffix={<SearchOutlined />}
/>
<Divider />
@ -154,10 +139,16 @@ const Overview: React.FC = () => {
</Title>
<Row gutter={[24, 24]}>
{components.map((component) => {
const url = `${component.link}/`;
/** 是否是外链 */
const isExternalLink = component.link.startsWith('http');
let url = `${component.link}`;
if (!isExternalLink) {
url += urlSearch;
}
/** Link 不能跳转到外链 */
const ComponentLink = !url.startsWith('http') ? Link : 'a';
const ComponentLink = isExternalLink ? 'a' : Link;
return (
<Col xs={24} sm={12} lg={8} xl={6} key={component?.title}>

View File

@ -3,7 +3,7 @@ import JsonML from 'jsonml.js/lib/utils';
import toReactComponent from 'jsonml-to-react-element';
import Prism from 'prismjs';
import 'prismjs/components/prism-typescript';
import { useLocation, useSearchParams, useIntl, type IPreviewerProps } from 'dumi';
import { useLocation, useIntl, type IPreviewerProps } from 'dumi';
import { ping } from '../../utils';
let pingDeferrer: PromiseLike<boolean>;
@ -36,7 +36,6 @@ export default function fromDumiProps<P extends object>(
const hoc = function DumiPropsAntdPreviewer(props: IPreviewerProps) {
const showRiddleButton = useShowRiddleButton();
const location = useLocation();
const [searchParams] = useSearchParams();
const { asset, children, demoUrl, expand, description = '', ...meta } = props;
const intl = useIntl();
const entryCode = asset.dependencies['index.tsx'].value;
@ -89,7 +88,6 @@ export default function fromDumiProps<P extends object>(
expand,
// FIXME: confirm is there has any case?
highlightedStyle: '',
theme: searchParams.get('theme'),
} as P;
return <WrappedComponent {...transformedProps} />;

View File

@ -17,6 +17,8 @@ import CodeSandboxIcon from '../../common/CodeSandboxIcon';
import RiddleIcon from '../../common/RiddleIcon';
import ExternalLinkIcon from '../../common/ExternalLinkIcon';
import fromDumiProps from './fromDumiProps';
import type { SiteContextProps } from '../../slots/SiteContext';
import SiteContext from '../../slots/SiteContext';
import { version } from '../../../../package.json';
const { ErrorBoundary } = Alert;
@ -38,7 +40,6 @@ interface DemoProps {
highlightedStyle: string;
expand: boolean;
intl: any;
theme: string;
sourceCodes: Record<'jsx' | 'tsx', string>;
location: Location;
showRiddleButton: boolean;
@ -53,6 +54,8 @@ interface DemoState {
}
class Demo extends React.Component<DemoProps, DemoState> {
static contextType = SiteContext;
liveDemo: any;
iframeRef = React.createRef<HTMLIFrameElement>();
@ -81,13 +84,12 @@ class Demo extends React.Component<DemoProps, DemoState> {
shouldComponentUpdate(nextProps: DemoProps, nextState: DemoState) {
const { codeExpand, copied, copyTooltipOpen, codeType } = this.state;
const { expand, theme, showRiddleButton } = this.props;
const { expand, showRiddleButton } = this.props;
return (
(codeExpand || expand) !== (nextState.codeExpand || nextProps.expand) ||
copied !== nextState.copied ||
copyTooltipOpen !== nextState.copyTooltipOpen ||
codeType !== nextState.copyTooltipOpen ||
nextProps.theme !== theme ||
nextProps.showRiddleButton !== showRiddleButton
);
}
@ -129,6 +131,7 @@ class Demo extends React.Component<DemoProps, DemoState> {
render() {
const { state } = this;
const { props } = this;
const site: SiteContextProps = this.context;
const {
meta,
src,
@ -139,7 +142,6 @@ class Demo extends React.Component<DemoProps, DemoState> {
highlightedStyle,
expand,
intl: { locale },
theme,
showRiddleButton,
} = props;
const { copied, copyTooltipOpen, codeType } = state;
@ -465,7 +467,7 @@ createRoot(document.getElementById('container')).render(<Demo />);
<img
alt="expand code"
src={
theme === 'dark'
site.theme.includes('dark')
? 'https://gw.alipayobjects.com/zos/antfincdn/btT3qDZn1U/wSAkBuJFbdxsosKKpqyq.svg'
: 'https://gw.alipayobjects.com/zos/antfincdn/Z5c7kzvi30/expand.svg'
}
@ -475,7 +477,7 @@ createRoot(document.getElementById('container')).render(<Demo />);
<img
alt="expand code"
src={
theme === 'dark'
site.theme.includes('dark')
? 'https://gw.alipayobjects.com/zos/antfincdn/CjZPwcKUG3/OpROPHYqWmrMDBFMZtKF.svg'
: 'https://gw.alipayobjects.com/zos/antfincdn/4zAaozCvUH/unexpand.svg'
}

View File

@ -14,7 +14,8 @@ export type ThemeSwitchProps = {
onChange: (value: ThemeName[]) => void;
};
const ThemeSwitch: React.FC<ThemeSwitchProps> = ({ value, onChange }) => {
const ThemeSwitch: React.FC<ThemeSwitchProps> = (props: ThemeSwitchProps) => {
const { value = ['light'], onChange } = props;
const { token } = useSiteToken();
const { pathname, search } = useLocation();
return (

View File

@ -1,16 +1,15 @@
import React, { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
import React, { useContext, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
import 'dayjs/locale/zh-cn';
import dayjs from 'dayjs';
import { Helmet, useOutlet, useSearchParams } from 'dumi';
import { Helmet, useOutlet } from 'dumi';
import '../../static/style';
import type { DirectionType } from 'antd/es/config-provider';
import ConfigProvider from 'antd/es/config-provider';
import classNames from 'classnames';
import zhCN from 'antd/es/locale/zh_CN';
import SiteContext from '../../slots/SiteContext';
import Header from '../../slots/Header';
import Footer from '../../slots/Footer';
import useLocale from '../../../hooks/useLocale';
import SiteContext from '../../slots/SiteContext';
import useLocation from '../../../hooks/useLocation';
import ResourceLayout from '../ResourceLayout';
import GlobalStyles from '../../common/GlobalStyles';
@ -28,26 +27,13 @@ const locales = {
},
};
const RESPONSIVE_MOBILE = 768;
const DocLayout: React.FC = () => {
const outlet = useOutlet();
const location = useLocation();
const { pathname, search } = location;
const [searchParams, setSearchParams] = useSearchParams();
const [locale, lang] = useLocale(locales);
// TODO: place doc layout here, apply for all docs route paths
// migrate from: https://github.com/ant-design/ant-design/blob/eb9179464b9c4a93c856e1e70ddbdbaaf3f3371f/site/theme/template/Layout/index.tsx
const [isMobile, setIsMobile] = React.useState<boolean>(false);
const [direction, setDirection] = React.useState<DirectionType>('ltr');
const timerRef = useRef<NodeJS.Timeout | null>(null);
const updateMobileMode = () => {
setIsMobile(window.innerWidth < RESPONSIVE_MOBILE);
};
const { direction } = useContext(SiteContext);
useLayoutEffect(() => {
if (lang === 'cn') {
@ -64,20 +50,6 @@ const DocLayout: React.FC = () => {
nprogressHiddenStyle.parentNode?.removeChild(nprogressHiddenStyle);
}, 0);
}
// Handle direction
const queryDirection = searchParams.get('direction');
setDirection(queryDirection === 'rtl' ? 'rtl' : 'ltr');
// Handle mobile mode
updateMobileMode();
window.addEventListener('resize', updateMobileMode);
return () => {
window.removeEventListener('resize', updateMobileMode);
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, []);
React.useEffect(() => {
@ -89,16 +61,6 @@ const DocLayout: React.FC = () => {
}
}, [location]);
const changeDirection = (dir: DirectionType): void => {
setDirection(dir);
if (dir === 'ltr') {
searchParams.delete('direction');
} else {
searchParams.set('direction', 'rtl');
}
setSearchParams(searchParams);
};
const content = useMemo(() => {
if (
['', '/'].some((path) => path === pathname) ||
@ -120,16 +82,8 @@ const DocLayout: React.FC = () => {
return <SidebarLayout>{outlet}</SidebarLayout>;
}, [pathname, outlet]);
const siteContextValue = useMemo(
() => ({
isMobile,
direction,
}),
[isMobile, direction],
);
return (
<SiteContext.Provider value={siteContextValue}>
<>
<Helmet encodeSpecialCharacters={false}>
<html
lang={lang}
@ -149,12 +103,12 @@ const DocLayout: React.FC = () => {
content="https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png"
/>
</Helmet>
<ConfigProvider locale={lang === 'cn' ? zhCN : undefined} direction={direction}>
<ConfigProvider locale={lang === 'cn' ? zhCN : undefined}>
<GlobalStyles />
<Header changeDirection={changeDirection} />
<Header />
{content}
</ConfigProvider>
</SiteContext.Provider>
</>
);
};

View File

@ -1,18 +1,26 @@
import React from 'react';
import { useOutlet, useSearchParams } from 'dumi';
import React, { useCallback, useEffect, useMemo } from 'react';
import { createSearchParams, useOutlet, useSearchParams } from 'dumi';
import { ConfigProvider, theme as antdTheme } from 'antd';
import { createCache, StyleProvider } from '@ant-design/cssinjs';
import type { DirectionType } from 'antd/es/config-provider';
import ThemeSwitch from '../common/ThemeSwitch';
import type { ThemeName } from '../common/ThemeSwitch';
import useLocation from '../../hooks/useLocation';
import type { SiteContextProps } from '../slots/SiteContext';
import SiteContext from '../slots/SiteContext';
type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
type SiteState = Partial<Omit<SiteContextProps, 'updateSiteContext'>>;
const RESPONSIVE_MOBILE = 768;
const styleCache = createCache();
if (typeof global !== 'undefined') {
(global as any).styleCache = styleCache;
}
const getAlgorithm = (themes: ThemeName[]) =>
(themes || []).map((theme) => {
const getAlgorithm = (themes: ThemeName[] = []) =>
themes.map((theme) => {
if (theme === 'dark') {
return antdTheme.darkAlgorithm;
}
@ -26,26 +34,87 @@ const GlobalLayout: React.FC = () => {
const outlet = useOutlet();
const { pathname } = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
const theme = searchParams.getAll('theme') as unknown as ThemeName[];
const handleThemeChange = (value: ThemeName[]) => {
setSearchParams({
...searchParams,
theme: value,
});
const [{ theme, direction, isMobile }, setSiteState] = React.useState<SiteState>({
isMobile: false,
direction: 'ltr',
theme: ['light'],
});
const updateSiteConfig = useCallback(
(props: SiteState) => {
setSiteState((prev) => ({ ...prev, ...props }));
// updating `searchParams` will clear the hash
const oldSearchStr = searchParams.toString();
let nextSearchParams: URLSearchParams = searchParams;
(Object.entries(props) as Entries<SiteContextProps>).forEach(([key, value]) => {
if (key === 'direction') {
if (value === 'rtl') {
nextSearchParams.set('direction', 'rtl');
} else {
nextSearchParams.delete('direction');
}
}
if (key === 'theme') {
nextSearchParams = createSearchParams({
...nextSearchParams,
theme: value.filter((t) => t !== 'light'),
});
}
});
if (nextSearchParams.toString() !== oldSearchStr) {
setSearchParams(nextSearchParams);
}
},
[searchParams, setSearchParams],
);
const updateMobileMode = () => {
updateSiteConfig({ isMobile: window.innerWidth < RESPONSIVE_MOBILE });
};
useEffect(() => {
const _theme = searchParams.getAll('theme') as ThemeName[];
const _direction = searchParams.get('direction') as DirectionType;
setSiteState({ theme: _theme, direction: _direction === 'rtl' ? 'rtl' : 'ltr' });
// Handle isMobile
updateMobileMode();
window.addEventListener('resize', updateMobileMode);
return () => {
window.removeEventListener('resize', updateMobileMode);
};
}, []);
const siteContextValue = useMemo(
() => ({
direction,
updateSiteConfig,
theme: theme!,
isMobile: isMobile!,
}),
[isMobile, direction, updateSiteConfig, theme],
);
return (
<StyleProvider cache={styleCache}>
<ConfigProvider
theme={{
algorithm: getAlgorithm(theme),
}}
>
{outlet}
{!pathname.startsWith('/~demos') && (
<ThemeSwitch value={theme} onChange={handleThemeChange} />
)}
</ConfigProvider>
<SiteContext.Provider value={siteContextValue}>
<ConfigProvider
theme={{
algorithm: getAlgorithm(theme),
}}
>
{outlet}
{!pathname.startsWith('/~demos') && (
<ThemeSwitch
value={theme}
onChange={(nextTheme) => updateSiteConfig({ theme: nextTheme })}
/>
)}
</ConfigProvider>
</SiteContext.Provider>
</StyleProvider>
);
};

View File

@ -83,7 +83,7 @@ export default function LangBtn({
top: 0,
zIndex: 1,
background: token.colorText,
color: token.colorTextLightSolid,
color: token.colorBgContainer,
transformOrigin: '0 0',
transform: `scale(0.7)`,
};

View File

@ -4,7 +4,6 @@ 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 type { DirectionType } from 'antd/es/config-provider';
import { ClassNames, css } from '@emotion/react';
import * as utils from '../../utils';
import { getThemeConfig, ping } from '../../utils';
@ -129,10 +128,6 @@ const useStyle = () => {
};
};
export interface HeaderProps {
changeDirection: (direction: DirectionType) => void;
}
const V5_NOTIFICATION = 'antd@4.0.0-notification-sent';
const SHOULD_OPEN_ANT_DESIGN_MIRROR_MODAL = 'ANT_DESIGN_DO_NOT_OPEN_MIRROR_MODAL';
@ -151,8 +146,7 @@ interface HeaderState {
}
// ================================= Header =================================
const Header: React.FC<HeaderProps> = (props) => {
const { changeDirection } = props;
const Header: React.FC = () => {
const [isClient, setIsClient] = React.useState(false);
const [locale, lang] = useLocale(locales);
const { token } = useSiteToken();
@ -188,7 +182,7 @@ const Header: React.FC<HeaderProps> = (props) => {
windowWidth: 1400,
searching: false,
});
const { direction, isMobile } = useContext<SiteContextProps>(SiteContext);
const { direction, isMobile, updateSiteConfig } = useContext<SiteContextProps>(SiteContext);
const pingTimer = useRef<NodeJS.Timeout | null>(null);
const location = useLocation();
const { pathname, search } = location;
@ -208,7 +202,7 @@ const Header: React.FC<HeaderProps> = (props) => {
setHeaderState((prev) => ({ ...prev, menuVisible: visible }));
}, []);
const onDirectionChange = () => {
changeDirection?.(direction !== 'rtl' ? 'rtl' : 'ltr');
updateSiteConfig({ direction: direction !== 'rtl' ? 'rtl' : 'ltr' });
};
useEffect(() => {

View File

@ -126,10 +126,11 @@ const useStyle = () => {
const Sidebar: React.FC = () => {
const sidebarData = useSidebarData();
const { isMobile } = useContext(SiteContext);
const { isMobile, theme } = useContext(SiteContext);
const styles = useStyle();
const [menuItems, selectedKey] = useMenu();
const isDark = theme.includes('dark');
const menuChild = (
<Menu
@ -137,6 +138,7 @@ const Sidebar: React.FC = () => {
inlineIndent={30}
css={styles.asideContainer}
mode="inline"
theme={isDark ? 'dark' : 'light'}
selectedKeys={[selectedKey]}
defaultOpenKeys={sidebarData?.map(({ title }) => title).filter((item) => item) as string[]}
/>

View File

@ -1,14 +1,19 @@
import * as React from 'react';
import type { DirectionType } from 'antd/es/config-provider';
import type { ThemeName } from '../common/ThemeSwitch';
export interface SiteContextProps {
isMobile: boolean;
direction: DirectionType;
theme: ThemeName[];
updateSiteConfig: (props: Partial<SiteContextProps>) => void;
}
const SiteContext = React.createContext<SiteContextProps>({
isMobile: false,
direction: 'ltr',
theme: ['light'],
updateSiteConfig: () => {},
});
export default SiteContext;