diff --git a/src/app/(page-detail)/[slug]/page.tsx b/src/app/(page-detail)/[slug]/page.tsx index a2af77c932..b7f92d3258 100644 --- a/src/app/(page-detail)/[slug]/page.tsx +++ b/src/app/(page-detail)/[slug]/page.tsx @@ -1,103 +1,52 @@ -'use client' - -import { useEffect } from 'react' -import { Balancer } from 'react-wrap-balancer' -import type { Image } from '@mx-space/api-client' -import type { PropsWithChildren } from 'react' - -import { useSetHeaderMetaInfo } from '~/components/layout/header/hooks' -import { Markdown } from '~/components/ui/markdown' import { BottomToUpSoftScaleTransitionView } from '~/components/ui/transition/BottomToUpSoftScaleTransitionView' import { BottomToUpTransitionView } from '~/components/ui/transition/BottomToUpTransitionView' import { TocAside } from '~/components/widgets/toc' -import { noopArr } from '~/lib/noop' -import { MarkdownImageRecordProvider } from '~/providers/article/MarkdownImageRecordProvider' -import { useCurrentPageDataSelector } from '~/providers/page/CurrentPageDataProvider' import { LayoutRightSidePortal } from '~/providers/shared/LayoutRightSideProvider' import { WrappedElementProvider } from '~/providers/shared/WrappedElementProvider' -import Loading from './loading' +import { + HeaderMetaInfoSetting, + MarkdownImageRecordProviderInternal, + PageLoading, + PagePaginator, + PageSubTitle, + PageTitle, + PostMarkdown, +} from './pageExtra' const PageDetail = () => { - const id = useCurrentPageDataSelector((p) => p?.id) - const title = useCurrentPageDataSelector((p) => p?.title) - const subtitle = useCurrentPageDataSelector((p) => p?.subtitle) - if (!id) { - return - } - return ( -
- -
-
- -

- {title} -

-
- - -

- {subtitle} -

-
-
- - - - - - - - - - - -
-
+ +
+ +
+
+ + + + + + + +
+ + + + + + + + + + + +
+ +
+
) } - -const PostMarkdown = () => { - const text = useCurrentPageDataSelector((data) => data?.text) - if (!text) return null - - return -} -const MarkdownImageRecordProviderInternal = (props: PropsWithChildren) => { - const images = useCurrentPageDataSelector( - (data) => data?.images || (noopArr as Image[]), - ) - if (!images) return null - - return ( - - {props.children} - - ) -} - -const HeaderMetaInfoSetting = () => { - const setHeaderMetaInfo = useSetHeaderMetaInfo() - const meta = useCurrentPageDataSelector((data) => { - if (!data) return null - - return { - title: data.title, - description: data.subtitle || '', - slug: `/${data.slug}`, - } - }) - - useEffect(() => { - if (meta) setHeaderMetaInfo(meta) - }, [meta]) - - return null -} - export default PageDetail diff --git a/src/app/(page-detail)/[slug]/pageExtra.tsx b/src/app/(page-detail)/[slug]/pageExtra.tsx new file mode 100644 index 0000000000..ef5cb01879 --- /dev/null +++ b/src/app/(page-detail)/[slug]/pageExtra.tsx @@ -0,0 +1,122 @@ +'use client' + +import { Fragment, useEffect, useMemo } from 'react' +import { Balancer } from 'react-wrap-balancer' +import Link from 'next/link' +import type { Image } from '@mx-space/api-client' +import type { PropsWithChildren } from 'react' + +import { useSetHeaderMetaInfo } from '~/components/layout/header/hooks' +import { Markdown } from '~/components/ui/markdown' +import { noopArr } from '~/lib/noop' +import { MarkdownImageRecordProvider } from '~/providers/article/MarkdownImageRecordProvider' +import { useCurrentPageDataSelector } from '~/providers/page/CurrentPageDataProvider' +import { useAggregationSelector } from '~/providers/root/aggregation-data-provider' + +import Loading from './loading' + +export const PageLoading: Component = ({ children }) => { + const id = useCurrentPageDataSelector((p) => p?.id) + + if (!id) { + return + } + + return children +} + +export const PostMarkdown = () => { + const text = useCurrentPageDataSelector((data) => data?.text) + if (!text) return null + + return +} +export const MarkdownImageRecordProviderInternal = ( + props: PropsWithChildren, +) => { + const images = useCurrentPageDataSelector( + (data) => data?.images || (noopArr as Image[]), + ) + if (!images) return null + + return ( + + {props.children} + + ) +} + +export const PageSubTitle = () => { + const subtitle = useCurrentPageDataSelector((data) => data?.subtitle) + return ( +

+ {subtitle} +

+ ) +} +export const PageTitle = () => { + const title = useCurrentPageDataSelector((data) => data?.title) + return ( +

+ {title} +

+ ) +} +export const HeaderMetaInfoSetting = () => { + const setHeaderMetaInfo = useSetHeaderMetaInfo() + const meta = useCurrentPageDataSelector((data) => { + if (!data) return null + + return { + title: data.title, + description: data.subtitle || '', + slug: `/${data.slug}`, + } + }) + + useEffect(() => { + if (meta) setHeaderMetaInfo(meta) + }, [meta]) + + return null +} + +export const PagePaginator = () => { + const currentPageTitle = useCurrentPageDataSelector((d) => d?.title) + const pageMeta = useAggregationSelector((d) => d.pageMeta) + const pages = useMemo(() => pageMeta || [], [pageMeta]) + const indexInPages = pages.findIndex((i) => i.title == currentPageTitle) + const n = pages.length + const hasNext = indexInPages + 1 < n + const hasPrev = indexInPages - 1 >= 0 + return ( +
+
+ {hasPrev && ( + + + 回顾一下: + {pages[indexInPages - 1].title} + + + )} +
+
+ {hasNext && ( + + + 继续了解: + {pages[indexInPages + 1].title} + + + )} +
+
+ ) +} diff --git a/src/components/widgets/toc/TocItem.tsx b/src/components/widgets/toc/TocItem.tsx index 28983c6984..c542dcd263 100644 --- a/src/components/widgets/toc/TocItem.tsx +++ b/src/components/widgets/toc/TocItem.tsx @@ -1,3 +1,5 @@ +'use client' + import { memo, useCallback, useEffect, useMemo, useRef } from 'react' import { tv } from 'tailwind-variants' import type { FC, MouseEvent } from 'react' diff --git a/src/providers/shared/WrappedElementProvider.tsx b/src/providers/shared/WrappedElementProvider.tsx index 843d82343b..dc139fc029 100644 --- a/src/providers/shared/WrappedElementProvider.tsx +++ b/src/providers/shared/WrappedElementProvider.tsx @@ -1,3 +1,5 @@ +'use client' + import { memo, useEffect, useRef } from 'react' import { createContextState } from 'foxact/create-context-state' import { useIsomorphicLayoutEffect } from 'foxact/use-isomorphic-layout-effect'