"use client"; import { useMemo, useState, type CSSProperties } from "react"; import Link from "next/link"; import { FileDown, PenLine, Search, X } from "lucide-react"; import type { LibraryDocListItem } from "@/lib/api"; import { coverHue } from "@/lib/coverColor"; import { libraryDocPath, type UrlStyle } from "@/lib/urlStyle"; import { variantURL, widthSrcSet } from "@/lib/responsiveImage"; import { formatRelative } from "@/lib/format"; import Avatar from "@/components/Avatar"; 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`; } /** 简介 markdown → 纯文本摘要(去标记、压平空白,卡片两行截断用) */ function plainExcerpt(md: string): string { return md .replace(/!\[[^\]]*\]\([^)]*\)/g, "") // 图片 .replace(/\[([^\]]*)\]\([^)]*\)/g, "$1") // 链接保留文字 .replace(/[*_~`#>]+/g, "") // 行内/块级标记 .replace(/\s+/g, " ") .trim(); } /** 文字封面:无图时用完整书名 + 书名派生稳定色相洗底(lib/coverColor.ts) */ function TextCover({ title }: { title: string }) { const name = title.trim() || "书"; return (
{name}
); } function ExtChip({ ext, className = "" }: { ext: string; className?: string }) { return ( {ext} ); } function DocCard({ doc, href }: { doc: LibraryDocListItem; href: string }) { const exts = Array.from(new Set(doc.files.map((f) => f.ext))).slice(0, 4); const totalSize = doc.files.reduce((acc, f) => acc + f.size, 0); const creatorName = doc.creator ? doc.creator.nickname || doc.creator.username : ""; const excerpt = plainExcerpt(doc.description ?? ""); return ( {/* 横版封面框(宽大于高):模糊底衬完整显示任意比例图 + 悬停浮出简介 */}
{doc.cover_url ? ( <> {/* 底层:同图放大模糊填充,竖版/非 3:2 封面不露黑边 */} {/* eslint-disable-next-line @next/next/no-img-element */} {/* 上层:完整封面居中显示 */} {/* eslint-disable-next-line @next/next/no-img-element */} {doc.title} ) : ( )} {/* 边缘内阴影,营造卡片体积感 */}
{excerpt ? (

{excerpt}

) : null}
{/* 封面下方书目信息:衬线书名 + 作者 + 文件概要 */}

{doc.title}

{doc.author ? (

{doc.author}

) : null}
{exts.map((ext) => ( ))} {doc.file_count > 0 ? `${doc.file_count} 个文件 · ${formatSize(totalSize)}` : "暂无文件"}
{doc.creator ? ( {creatorName} ) : null} {doc.creator ? "· " : ""} {formatRelative(doc.created_at)}
); } /** * 书库目录:横版封面卡片网格(手机端单列全宽)+ 书名/作者即时过滤(目录接口一次返回全部已发布 * 条目,纯客户端过滤;上限与后端 ListPublished 的 100 条一致)。 */ export default function LibrarySearchGrid({ docs, urlStyle, }: { docs: LibraryDocListItem[]; urlStyle: UrlStyle; }) { const [query, setQuery] = useState(""); const q = query.trim().toLowerCase(); const filtered = useMemo(() => { if (!q) return docs; return docs.filter( (d) => d.title.toLowerCase().includes(q) || d.author.toLowerCase().includes(q) ); }, [docs, q]); if (docs.length === 0) { return (

书库还没有内容

管理员可在后台「书库管理」发布条目

); } return (
{/* 搜索:居中宽框,与大气 Hero 呼应 */}
setQuery(e.target.value)} placeholder="搜索书名或作者" aria-label="搜索书名或作者" className="j13-search-field w-full rounded-full pl-11 pr-10 py-3 text-[14px] shadow-[var(--shadow-sm)]" style={{ background: "var(--panel)", border: "1px solid var(--line)" }} /> {query ? ( ) : null}
{filtered.length === 0 ? (

没有找到与「{query.trim()}」相关的书籍

换个书名或作者关键词试试

) : (
{filtered.map((d) => ( ))}
)}
); }