import React, { useMemo } from 'react' import type { ThemeProps } from 'vite-plugin-react-pages/clientTypes' import { useStaticData } from 'vite-plugin-react-pages/client' import { useLocation } from 'react-router-dom' import AppLayout, { MDX } from './Layout' import { themeConfigCtx, themePropsCtx, themeCtx } from './ctx' import './style.less' import { Demo } from './Layout/Demo' import AnchorLink from './components/AnchorLink' import type { ThemeConfig, ThemeContextValue } from './ThemeConfig.doc' import { normalizeI18nConfig, useIsomorphicLayoutEffect } from './utils' import { getPageGroups, matchPagePathLocalePrefix } from './analyzeStaticData' export function createTheme( originalThemeConfig: ThemeConfig ): React.FC> { // normalize themeConfig const themeConfig = { ...originalThemeConfig, search: originalThemeConfig.search ?? true, i18n: normalizeI18nConfig(originalThemeConfig.i18n), } const ThemeComp = (props: ThemeProps) => { const { loadState, loadedData } = props const staticData = useStaticData() const location = useLocation() useIsomorphicLayoutEffect(() => { // scroll to anchor link after page component loaded if (loadState.type === 'loaded') { if (location.hash) { AnchorLink.scrollToAnchor(decodeURIComponent(location.hash.slice(1))) return } } window.scrollTo(0, 0) }, [loadState, location.hash]) if (loadState.type === 'loading') { const ComponentLoading = themeConfig.ComponentLoading return ( {ComponentLoading ? : null} ) } if (loadState.type === 'load-error') { const errMsg = loadState.error?.message console.error(loadState.error) return (

Load Error

{errMsg &&

{errMsg}

}
) } const pageData = loadedData[loadState.routePath] if (loadState.type === '404' || !pageData) { const Comp404 = themeConfig.Component404 return ( {Comp404 ? :

Page not found.

}
) } const pageStaticData = staticData[loadState.routePath] const body = Object.entries(pageData) // the dataPiece with key 'outlineInfo' is not for render .filter(([key]) => key !== 'outlineInfo') .map(([key, dataPart], idx) => { const ContentComp = (dataPart as any).default const pageStaticDataPart = pageStaticData?.[key] const content = (() => { if (pageStaticDataPart?.sourceType === 'md') return ( ) if (dataPart?.isDemo) return return })() const result = {content} let order = Number(pageStaticDataPart?.order || 1) if (Number.isNaN(order)) order = 1 return { key, result, order } }) .sort((a, b) => { // sort by (order, key) if (a.order !== b.order) return a.order - b.order // keep dataPiece with key 'main' at the front (before demos) if (a.key === 'main') return -1 if (b.key === 'main') return 1 return a.key.localeCompare(b.key) }) .map(({ result }) => result) return {body} } return withThemeRootWrapper(ThemeComp) function withThemeRootWrapper( Component: React.FC> ) { const HOC: React.FC> = (props) => { const { loadState, loadedData } = props const staticData = useStaticData() const themeCtxValue: ThemeContextValue = useMemo(() => { const pageGroups = getPageGroups(staticData, themeConfig.i18n) const result: ThemeContextValue = { ...props, themeConfig, staticData, resolvedLocale: {}, pageGroups, } if (!result.themeConfig.i18n?.locales) return result const { locale, localeKey, pagePathWithoutLocalePrefix } = matchPagePathLocalePrefix( loadState.routePath, result.themeConfig.i18n ) Object.assign(result.resolvedLocale, { locale, localeKey, pagePathWithoutLocalePrefix, }) return result }, [loadState, loadedData, staticData]) let children = if (themeConfig.AppWrapper) { children = {children} } // TODO: improve context usage // use less context and make it more efficient return ( {children} ) } return HOC } } export { defaultSideNavs } from './Layout/Sider' export type { DefaultSideNavsOpts } from './Layout/Sider' export { Demo } from './Layout/Demo' export { TsInfo } from './Layout/TsInfo' export { FileText } from './Layout/FileText' export type { ThemeConfig, LocalConfig, I18nConfig, ThemeContextValue, MenuConfig, FooterConfig, FooterColumn, FooterLink, } from './ThemeConfig.doc' export { useThemeCtx } from './ctx' import { registerSSRPlugin } from 'vite-plugin-react-pages/client' registerSSRPlugin(() => import('./ssrPlugin').then((mod) => mod.default))