import type { Metadata } from "next"; import type { CSSProperties } from "react"; import { notFound } from "next/navigation"; import Link from "next/link"; import { BookOpen, Download, Paperclip } from "lucide-react"; import { fetchLibraryDocBySlug, type LibraryFileItem } from "@/lib/api"; import { coverHue } from "@/lib/coverColor"; import { getPublicSettingsCached } from "@/lib/serverData"; import MarkdownBody from "@/components/MarkdownBody"; import { SiteDocMasthead } from "@/components/site-doc"; import { requestCanonical } from "@/lib/canonicalMeta"; import { libraryDocPath, libraryDocReadPath } from "@/lib/urlStyle"; import { webPageJsonLd } from "@/lib/jsonLd"; import JsonLd from "@/components/JsonLd"; import { estimateReadingMinutes } from "@/lib/toc"; import { groupSections } from "@/lib/librarySections"; import LightboxImage from "@/components/LightboxImage"; import AdaptiveCoverSlot from "@/components/AdaptiveCoverSlot"; interface PageProps { params: Promise<{ slug: string }>; } function formatSize(n: number): string { if (!Number.isFinite(n) || n <= 0) return "0 B"; if (n < 1024) return `${n} B`; if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`; return `${(n / (1024 * 1024)).toFixed(1)} MB`; } /** 无封面时:完整书名 + 书名派生稳定色相渐变块(有图封面走 AdaptiveCoverSlot 按横竖版自适应摆放) */ function CoverFallback({ title }: { title: string }) { const name = title.trim() || "书"; return (
{name}
); } // 附件仅下载分发(书籍正文走阅读页逐章阅读) function ExtChip({ ext }: { ext: string }) { return ( {ext} ); } function FileRow({ f }: { f: LibraryFileItem }) { return (
{f.name} {formatSize(f.size)} · {f.download_count} 次下载 下载
); } export async function generateMetadata({ params }: PageProps): Promise { const { slug } = await params; const data = await fetchLibraryDocBySlug(slug).catch(() => null); if (!data) return { title: "条目不存在" }; const d = data.doc; return { title: d.title, description: d.description ? d.description.slice(0, 150) : d.title, openGraph: { title: d.title, description: d.description ? d.description.slice(0, 150) : d.title, type: "article", publishedTime: d.created_at, }, ...(await requestCanonical(libraryDocPath((await getPublicSettingsCached()).url_style, d.slug))), }; } export default async function LibraryDocPage({ params }: PageProps) { const { slug } = await params; const [data, settings] = await Promise.all([ fetchLibraryDocBySlug(slug).catch(() => null), getPublicSettingsCached(), ]); if (!data) notFound(); const d = data.doc; const urlStyle = settings.url_style; const chapterCount = groupSections(d.sections ?? []).length; const readingMinutes = estimateReadingMinutes( [d.description, ...(d.sections ?? []).map((s) => s.content)].filter(Boolean).join("\n\n") ); const jsonLd = webPageJsonLd({ name: d.title, description: d.description ? d.description.slice(0, 150) : undefined, path: libraryDocPath(urlStyle, d.slug), datePublished: d.created_at, dateModified: d.updated_at, }); return ( <>
{/* 手机端水平内边距收窄(px-3),介绍内容近全宽;sm 起恢复常规面板内距 */}
0 ? ( {chapterCount} 章 ) : undefined } /> {/* 横版封面(宽>高且足够大):全宽置于内容上方;竖版或过小的横版图时此槽位不渲染。 小图不强行放大占满全宽:max-w-full 下保持自然尺寸,容器随内容收缩并水平居中 */} {d.cover_url ? (
) : null}
{/* 左栏:封面 + 元信息 + 开始阅读 */} {/* 右栏:介绍 + 附件 */}

介绍

{d.description ? ( ) : (

这本书还没有介绍。

)}

附件下载({d.files.length})

{d.files.length === 0 ? (

暂无附件

) : (
{d.files.map((f) => ( ))}
)}
来自站点书库
); }