Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions app/docs/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { PageFeedback } from "@/app/components/PageFeedback";
import { DocHistoryPanel } from "@/app/components/DocHistoryPanel";
import { DocShareButton } from "@/app/components/DocShareButton";
import { cookies } from "next/headers";
import { type PageData } from "@/app/types/doc";
// Extract clean text content from MDX - no longer used on client/page side
// content fetching moved to API route for performance

Expand Down Expand Up @@ -51,7 +52,7 @@ function getPageWithLocale(
return { page: originalPage, isFallback: false };

const originalLang =
(originalPage?.data as { lang?: string } | undefined)?.lang ?? null;
(originalPage?.data as PageData | undefined)?.lang ?? null;

// 已经是目标语言,直接返回
if (originalLang === locale) return { page: originalPage, isFallback: false };
Expand Down Expand Up @@ -83,11 +84,8 @@ export default async function DocPage({ params }: Param) {

// 统一通过工具函数生成 Edit 链接,内部已处理中文目录编码
const editUrl = buildDocsEditUrl(page.path);
const docIdFromPage =
(page.data as { docId?: string; frontmatter?: { docId?: string } })
?.docId ??
(page.data as { docId?: string; frontmatter?: { docId?: string } })
?.frontmatter?.docId;
const data = page.data as PageData;
const docIdFromPage = data.docId ?? data.frontmatter?.docId;

const contributorsEntry =
getDocContributorsByPath(page.file.path) ||
Expand Down
26 changes: 1 addition & 25 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,12 @@ import leaderboard from "@/generated/site-leaderboard.json";
// SITE_URL 由 lib/site-url.ts 统一提供(从 NEXT_PUBLIC_SITE_URL 读 + 归一化),
// 这里和 app/robots.ts 共用一份,避免两边 drift。
import { SITE_URL } from "@/lib/site-url";
import { type PageData, type DateLike } from "@/app/types/doc";

/** * 定义 `source.getPages()` 返回的单个页面对象的类型别名
*/
type SourcePage = ReturnType<typeof source.getPages>[number];

/** * 定义可以被解析为日期的宽松类型
*/
type DateLike = string | number | Date | undefined | null;

/**
* (FIX) 定义一个用于 page.data 的基础类型,
* 以避免在 isDraftOrHidden 和 extractDateFromPage 中使用 'any'。
*/
type PageData = {
date?: DateLike;
updated?: DateLike;
updatedAt?: DateLike;
lastUpdated?: DateLike;
draft?: boolean;
hidden?: boolean;
frontmatter?: {
date?: DateLike;
updated?: DateLike;
updatedAt?: DateLike;
lastUpdated?: DateLike;
draft?: boolean;
hidden?: boolean;
};
};

/**
* Next.js 会调用的默认导出函数,用于生成整个站点的 Sitemap。
* * @returns {MetadataRoute.Sitemap} 一个包含所有站点地图条目的数组。
Expand Down
46 changes: 46 additions & 0 deletions app/types/doc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { StructuredData } from "fumadocs-core/mdx-plugins";

/**
* 定义可以被解析为日期的宽松类型
*/
export type DateLike = string | number | Date | undefined | null;

/**
* 定义用于 page.data 的基础类型,
* 包含 Fumadocs 自动生成的字段以及常见的前置元数据 (frontmatter)。
*/
export interface PageData {
title?: string;
description?: string;
date?: DateLike;
updated?: DateLike;
updatedAt?: DateLike;
lastUpdated?: DateLike;
draft?: boolean;
hidden?: boolean;
docId?: string;
lang?: string;
structuredData?: StructuredData;
load?: () => Promise<{ structuredData: StructuredData }>;
/**
* 允许访问 frontmatter 原始对象(Fumadocs 默认会将字段打平到 data 根部,
* 但部分逻辑可能仍显式访问 .frontmatter)。
*/
frontmatter?: {
title?: string;
description?: string;
date?: DateLike;
updated?: DateLike;
updatedAt?: DateLike;
lastUpdated?: DateLike;
draft?: boolean;
hidden?: boolean;
docId?: string;
lang?: string;
[key: string]: unknown;
};
// 故意不挂顶层 [key: string]: unknown 索引签名 —— Fumadocs 的 page.data 由
// zod DocOut 推出,没有 index signature;如果在 PageData 上挂一个,as PageData
// 会触发 TS2352 "neither type sufficiently overlaps"。所有需要的字段都已
// 在上面显式声明;真要拓展加新字段,往这里加显式 ? 字段,别走 escape hatch。
}
16 changes: 3 additions & 13 deletions lib/search-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,16 @@ import type { AdvancedIndex } from "fumadocs-core/search/server";
import type { StructuredData } from "fumadocs-core/mdx-plugins";
import { source } from "@/lib/source";
import { basename, extname } from "path";
import { type PageData } from "@/app/types/doc";

type Page = ReturnType<typeof source.getPages>[number];

/**
* fumadocs page.data 在构建产物里的 runtime shape。
* 老路径:structuredData 直接 inline;新路径:通过 load() 异步拉。
*/
interface PageDataShape {
structuredData?: StructuredData;
load?: () => Promise<{ structuredData: StructuredData }>;
title?: string;
description?: string;
}

/**
* 把一个 fumadocs 页面转成 Orama 索引项(复用 fumadocs-core 默认实现逻辑),
* 单独抽出来是因为我们需要分片(zh / en),用 createSearchAPI 手动传 indexes。
*/
export async function pageToIndex(page: Page): Promise<AdvancedIndex> {
const data = page.data as PageDataShape;
const data = page.data as PageData;

let structuredData: StructuredData | undefined;
if (data.structuredData) {
Expand Down Expand Up @@ -52,6 +42,6 @@ export async function pageToIndex(page: Page): Promise<AdvancedIndex> {
* 翻译版 frontmatter 会声明 `lang: "en"` 且通常 `translatedFrom: "zh"`。
*/
export function isEnglishPage(page: Page): boolean {
const lang = (page.data as { lang?: string }).lang;
const lang = (page.data as PageData).lang;
return lang === "en";
}
Loading