diff --git a/next.config.mjs b/next.config.mjs index d0af8a226c..9ee519cef8 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -4,7 +4,7 @@ import { config } from 'dotenv' import NextBundleAnalyzer from '@next/bundle-analyzer' -import pkg from './package.json' assert { type: 'json' } +import pkg from './package.json' with { type: 'json' } process.title = 'Shiro (NextJS)' diff --git a/package.json b/package.json index 77afd5a945..8cba799789 100644 --- a/package.json +++ b/package.json @@ -192,5 +192,6 @@ "object.values": "npm:@nolyfill/object.values@latest", "string.prototype.matchall": "npm:@nolyfill/string.prototype.matchall@latest" } - } + }, + "packageManager": "pnpm@9.0.6+sha256.0624e30eff866cdeb363b15061bdb7fd9425b17bc1bb42c22f5f4efdea21f6b3" } diff --git a/src/app/(app)/notes/[id]/api.tsx b/src/app/(app)/notes/[id]/api.tsx index 0b2f19a22f..661390314d 100644 --- a/src/app/(app)/notes/[id]/api.tsx +++ b/src/app/(app)/notes/[id]/api.tsx @@ -1,30 +1,33 @@ import { cache } from 'react' -import { headers } from 'next/dist/client/components/headers' -import { REQUEST_QUERY } from '~/constants/system' import { attachServerFetch, getAuthFromCookie } from '~/lib/attach-fetch' import { getQueryClient } from '~/lib/query-client.server' import { requestErrorHandler } from '~/lib/request.server' import { queries } from '~/queries/definition' -export const getData = cache(async (params: { id: string }) => { - attachServerFetch() +export const getData = cache( + async (params: { + id: string - const header = headers() - const searchParams = new URLSearchParams(header.get(REQUEST_QUERY) || '') - const id = params.id - const token = searchParams.get('token') - const query = queries.note.byNid( - id, - searchParams.get('password') || undefined, - token ? `${token}` : undefined, - ) + token?: string + password?: string + }) => { + attachServerFetch() - const data = await getQueryClient() - .fetchQuery({ - ...query, - staleTime: getAuthFromCookie() ? 0 : undefined, - }) - .catch(requestErrorHandler) - return data -}) + const { id, password, token } = params + + const query = queries.note.byNid( + id, + password, + token ? `${token}` : undefined, + ) + + const data = await getQueryClient() + .fetchQuery({ + ...query, + staleTime: getAuthFromCookie() ? 0 : undefined, + }) + .catch(requestErrorHandler) + return data + }, +) diff --git a/src/app/(app)/notes/[id]/layout.tsx b/src/app/(app)/notes/[id]/layout.tsx deleted file mode 100644 index d35dd09c29..0000000000 --- a/src/app/(app)/notes/[id]/layout.tsx +++ /dev/null @@ -1,167 +0,0 @@ -/* eslint-disable react/display-name */ -import { Suspense } from 'react' -import type { Metadata } from 'next' - -import { buildRoomName, RoomProvider } from '~/components/modules/activity' -import { CommentAreaRootLazy } from '~/components/modules/comment' -import { NotePasswordForm } from '~/components/modules/note' -import { NoteFontSettingFab } from '~/components/modules/note/NoteFontFab' -import { NoteMainContainer } from '~/components/modules/note/NoteMainContainer' -import { TocFAB } from '~/components/modules/toc/TocFAB' -import { BottomToUpSoftScaleTransitionView } from '~/components/ui/transition' -import { OnlyMobile } from '~/components/ui/viewport/OnlyMobile' -import { getOgUrl } from '~/lib/helper.server' -import { getSummaryFromMd } from '~/lib/markdown' -import { definePrerenderPage } from '~/lib/request.server' -import { - CurrentNoteDataProvider, - SyncNoteDataAfterLoggedIn, -} from '~/providers/note/CurrentNoteDataProvider' -import { CurrentNoteNidProvider } from '~/providers/note/CurrentNoteIdProvider' - -import { Paper } from '../../../../components/layout/container/Paper' -import { getData } from './api' -import { Transition } from './Transition' - -export const dynamic = 'force-dynamic' -export const generateMetadata = async ({ - params, -}: { - params: { - id: string - } -}): Promise => { - try { - const res = await getData(params) - - const data = res.data - const { title, text } = data - const description = getSummaryFromMd(text ?? '') - - const ogUrl = getOgUrl('note', { - nid: params.id, - }) - - return { - title, - description, - openGraph: { - title, - description, - images: ogUrl, - type: 'article', - }, - twitter: { - images: ogUrl, - title, - description, - card: 'summary_large_image', - }, - } satisfies Metadata - } catch { - return {} - } -} - -export default definePrerenderPage<{ - id: string -}>()({ - fetcher: getData, - requestErrorRenderer(error, parsed, { id }) { - const { status } = parsed - - if (status === 403) { - return ( - - - - - ) - } - }, - Component({ data, params: { id: nid }, children }) { - return ( - <> - - - - - - - {children} - - - - - - - - - - - - - - ) - }, -}) - -// export default async ( -// props: NextPageParams<{ -// id: string -// }>, -// ) => { -// const { params } = props -// const { id: nid } = params -// const { data, error, status, bizMessage } = await unwrapRequest( -// getData(params), -// ) - -// if (status === 403) { -// return ( -// -// -// -// -// ) -// } - -// if (error) { -// if (bizMessage) { -// return -// } -// throw error -// } - -// const { id: noteObjectId, allowComment } = data.data - -// return ( -// <> -// -// -// -// -// -// -// {props.children} -// -// -// -// -// -// - -// - -// -// -// -// -// ) -// } diff --git a/src/app/(app)/notes/[id]/page.tsx b/src/app/(app)/notes/[id]/page.tsx index 479036d2d3..e239c3170a 100644 --- a/src/app/(app)/notes/[id]/page.tsx +++ b/src/app/(app)/notes/[id]/page.tsx @@ -1,9 +1,19 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable react/display-name */ +import { Suspense } from 'react' +import type { NoteModel } from '@mx-space/api-client' +import type { Metadata } from 'next' + import { AckRead } from '~/components/common/AckRead' import { ClientOnly } from '~/components/common/ClientOnly' -import { Presence } from '~/components/modules/activity' +import { + buildRoomName, + Presence, + RoomProvider, +} from '~/components/modules/activity' +import { CommentAreaRootLazy } from '~/components/modules/comment' import { NoteActionAside, NoteBottomBarAction, @@ -11,19 +21,34 @@ import { NoteFooterNavigationBarForMobile, NoteMetaBar, NoteMetaReadingCount, + NotePasswordForm, } from '~/components/modules/note' import { NoteBanner, NoteRootBanner, } from '~/components/modules/note/NoteBanner' +import { NoteFontSettingFab } from '~/components/modules/note/NoteFontFab' +import { NoteMainContainer } from '~/components/modules/note/NoteMainContainer' import { ArticleRightAside } from '~/components/modules/shared/ArticleRightAside' import { BanCopyWrapper } from '~/components/modules/shared/BanCopyWrapper' import { ReadIndicatorForMobile } from '~/components/modules/shared/ReadIndicator' import { SummarySwitcher } from '~/components/modules/shared/SummarySwitcher' +import { TocFAB } from '~/components/modules/toc/TocFAB' import { XLogInfoForNote } from '~/components/modules/xlog' +import { BottomToUpSoftScaleTransitionView } from '~/components/ui/transition' +import { OnlyMobile } from '~/components/ui/viewport/OnlyMobile' +import { getOgUrl } from '~/lib/helper.server' +import { getSummaryFromMd } from '~/lib/markdown' +import { definePrerenderPage } from '~/lib/request.server' +import { + CurrentNoteDataProvider, + SyncNoteDataAfterLoggedIn, +} from '~/providers/note/CurrentNoteDataProvider' +import { CurrentNoteNidProvider } from '~/providers/note/CurrentNoteIdProvider' import { LayoutRightSidePortal } from '~/providers/shared/LayoutRightSideProvider' import { WrappedElementProvider } from '~/providers/shared/WrappedElementProvider' +import { Paper } from '../../../../components/layout/container/Paper' import { NoteHeadCover } from '../../../../components/modules/note/NoteHeadCover' import { NoteHideIfSecret } from '../../../../components/modules/note/NoteHideIfSecret' import { getData } from './api' @@ -36,14 +61,9 @@ import { NoteMarkdownImageRecordProvider, NoteTitle, } from './pageExtra' +import { Transition } from './Transition' -export const dynamic = 'force-dynamic' -export default async function Page(props: { - params: { - id: string - } -}) { - const { data } = await getData(props.params) +async function PageInner({ data }: { data: NoteModel }) { return ( <> @@ -103,3 +123,94 @@ export default async function Page(props: { ) } + +export const dynamic = 'force-dynamic' + +type NoteDetailPageParams = { + id: string + + password?: string + token?: string +} +export const generateMetadata = async ({ + params, +}: { + params: NoteDetailPageParams +}): Promise => { + try { + const res = await getData(params) + + const data = res.data + const { title, text } = data + const description = getSummaryFromMd(text ?? '') + + const ogUrl = getOgUrl('note', { + nid: params.id, + }) + + return { + title, + description, + openGraph: { + title, + description, + images: ogUrl, + type: 'article', + }, + twitter: { + images: ogUrl, + title, + description, + card: 'summary_large_image', + }, + } satisfies Metadata + } catch { + return {} + } +} + +export default definePrerenderPage()({ + fetcher: getData, + requestErrorRenderer(error, parsed, { id }) { + const { status } = parsed + + if (status === 403) { + return ( + + + + + ) + } + }, + Component({ data, params: { id: nid } }) { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + ) + }, +}) diff --git a/src/app/(app)/og/route.tsx b/src/app/(app)/og/route.tsx index 070113293f..e43287dee1 100644 --- a/src/app/(app)/og/route.tsx +++ b/src/app/(app)/og/route.tsx @@ -156,7 +156,7 @@ export const GET = async (req: NextRequest) => { const { nid } = data document = await apiClient.note .getNoteById(+nid) - .then((r) => ({ title: r.data.title, subtitle: '生活记录' })) + .then((r) => ({ title: r.data.title, subtitle: '手记' })) break } case 'page': { diff --git a/src/app/(app)/timeline/layout.tsx b/src/app/(app)/timeline/layout.tsx index b2dbe85d7a..00e3110d91 100644 --- a/src/app/(app)/timeline/layout.tsx +++ b/src/app/(app)/timeline/layout.tsx @@ -1,58 +1,57 @@ +/* eslint-disable react/display-name */ import { dehydrate } from '@tanstack/react-query' -import { headers } from 'next/dist/client/components/headers' import type { PropsWithChildren } from 'react' import { TimelineType } from '@mx-space/api-client' import { QueryHydrate } from '~/components/common/QueryHydrate' import { SearchFAB } from '~/components/modules/shared/SearchFAB' -import { REQUEST_QUERY } from '~/constants/system' -import { attachServerFetch } from '~/lib/attach-fetch' import { getQueryClient } from '~/lib/query-client.server' import { apiClient } from '~/lib/request' +import { definePrerenderPage } from '~/lib/request.server' export const metadata = { title: '时间线', } export const dynamic = 'force-dynamic' -export default async (props: PropsWithChildren) => { - attachServerFetch() - const header = headers() - const query = header.get(REQUEST_QUERY) - const search = new URLSearchParams(query || '?') - const year = search.get('year') - const type = search.get('type') as 'post' | 'note' +export default definePrerenderPage<{ + type: string + year: string +}>()({ + async fetcher({ type, year }) { + const nextType = { + post: TimelineType.Post, + note: TimelineType.Note, + }[type] + const queryClient = getQueryClient() + await queryClient.fetchQuery({ + queryKey: ['timeline'], + meta: { nextType, year }, + queryFn: async () => { + return await apiClient.aggregate + .getTimeline({ + type: nextType, + year: +(year || 0) || undefined, + }) + .then((res) => res.data) + }, + }) + }, + Component: async (props: PropsWithChildren) => { + const queryClient = getQueryClient() + return ( + { + return query.queryKey[0] === 'timeline' + }, + })} + > + {props.children} - const nextType = { - post: TimelineType.Post, - note: TimelineType.Note, - }[type] - const queryClient = getQueryClient() - await queryClient.fetchQuery({ - queryKey: ['timeline'], - meta: { nextType, year }, - queryFn: async () => { - return await apiClient.aggregate - .getTimeline({ - type: nextType, - year: +(year || 0) || undefined, - }) - .then((res) => res.data) - }, - }) - - return ( - { - return query.queryKey[0] === 'timeline' - }, - })} - > - {props.children} - - - - ) -} + + + ) + }, +}) diff --git a/src/components/layout/footer/Footer.tsx b/src/components/layout/footer/Footer.tsx index 72f104adf0..4c5d90ce09 100644 --- a/src/components/layout/footer/Footer.tsx +++ b/src/components/layout/footer/Footer.tsx @@ -1,20 +1,10 @@ -import { headers } from 'next/headers' - import { ThemeSwitcher } from '~/components/ui/theme-switcher' -import { REQUEST_GEO, REQUEST_IP } from '~/constants/system' import { FooterInfo } from './FooterInfo' export const Footer = () => { - const header = headers() - const geo = header.get(REQUEST_GEO) - const ip = header.get(REQUEST_IP) return (