import Link from "next/link"; import { useRouter } from "next/router"; import { useCallback, useEffect, useRef, useState, type FormEvent, } from "react"; import { ArrowRight, ArrowUpRight, Bot, ChevronRight, FileText, Plus, Search, X, } from "lucide-react"; import GuidanceShell, { useGuidanceAccount } from "@/components/GuidanceShell"; import { EmptyState, KindBadge, KindIcon, Notice, PageHeading, kindNames, Tabs, } from "@/components/GuidanceUI"; import { guides, type Guidance } from "@/content/guides/catalog"; import s from "@/styles/guidance.module.css"; type Summary = { id: string; revision: number; title: string; summary: string; kind: Guidance["kind"]; author?: string; tags?: string[]; source: "community" | "example"; }; type Source = "all" | "published" | "examples"; const kinds = ["all", "guide", "context", "evidence"] as const; const examples: Summary[] = guides.map((g) => ({ ...g, source: "example" })); export default function DocumentDirectory({ communityOnly = false, }: { communityOnly?: boolean; }) { const router = useRouter(); const mine = communityOnly && router.query.scope === "mine"; return ( ); } function DirectoryContent({ communityOnly, mine, }: { communityOnly: boolean; mine: boolean; }) { const router = useRouter(), account = useGuidanceAccount(); const [published, setPublished] = useState([]), [loading, setLoading] = useState(true), [error, setError] = useState(""); const [q, setQ] = useState(""), [kind, setKind] = useState("all"), [source, setSource] = useState(communityOnly ? "published" : "all"), [sort, setSort] = useState("default"); const controller = useRef(null); const refresh = useCallback(async () => { controller.current?.abort(); const abort = new AbortController(); controller.current = abort; setLoading(true); setError(""); try { const r = await fetch( "/api/documents" + (mine && account.user ? "?author=" + account.user.id : ""), { signal: abort.signal }, ); const b = await r.json(); if (!r.ok) throw Error(b.error || "目录暂时不可用"); if (!Array.isArray(b.documents)) throw Error("目录返回异常,请稍后重试"); setPublished( b.documents.map((d: Omit) => ({ ...d, source: "community", })), ); } catch (e) { if (!abort.signal.aborted) setError(e instanceof Error ? e.message : "目录暂时不可用"); } finally { if (!abort.signal.aborted) setLoading(false); } }, [mine, account.user?.id]); useEffect(() => { void refresh(); return () => controller.current?.abort(); }, [refresh]); useEffect(() => { if (!router.isReady) return; setQ(typeof router.query.q === "string" ? router.query.q : ""); setKind( typeof router.query.kind === "string" && kinds.some((k) => k === router.query.kind) ? router.query.kind : "all", ); setSource( communityOnly ? "published" : router.query.source === "published" || router.query.source === "examples" ? router.query.source : "all", ); setSort(router.query.sort === "title" ? "title" : "default"); }, [ router.isReady, router.query.q, router.query.kind, router.query.source, router.query.sort, communityOnly, ]); function remember( next: { q?: string; kind?: string; source?: Source; sort?: string } = {}, ) { const values = { q, kind, source, sort, ...next }, query: Record = {}; if (values.q) query.q = values.q; if (values.kind !== "all") query.kind = values.kind; if (!communityOnly && values.source !== "all") query.source = values.source; if (values.sort !== "default") query.sort = values.sort; if (mine) query.scope = "mine"; void router.push( { pathname: communityOnly ? "/documents" : "/", query }, undefined, { shallow: true, scroll: false }, ); } function search(e: FormEvent) { e.preventDefault(); remember(); } function clear() { setQ(""); setKind("all"); setSource(communityOnly ? "published" : "all"); setSort("default"); remember({ q: "", kind: "all", source: communityOnly ? "published" : "all", sort: "default", }); } const all: Summary[] = communityOnly ? published : [...published, ...examples]; const term = q.trim().toLocaleLowerCase(); const found = all.filter( (d) => (!mine || d.author === account.user?.id) && (source === "all" || (source === "published" && d.source === "community") || (source === "examples" && d.source === "example")) && `${d.title} ${d.summary} ${d.id} ${d.tags?.join(" ") || ""}` .toLocaleLowerCase() .includes(term), ); const documents = found.filter((d) => kind === "all" || d.kind === kind); if (sort === "title") documents.sort((a, b) => a.title.localeCompare(b.title, "zh-CN")); const waiting = loading || (mine && account.loading), filtered = !!q || kind !== "all" || (!communityOnly && source !== "all") || sort !== "default"; const heading = mine ? "我的文档" : communityOnly ? "社区文档" : "探索文档"; return ( <> Agent 入口 {!communityOnly && ( <> 好用的知识,从不必整套加载。 每篇文档都有适用条件和固定版本。需要更多时,再沿着有用的链接继续阅读。 一篇文档 下一页 了解工作原理 试试这些任务 {["代码审查", "规划", "验证"].map((t) => ( { setQ(t); remember({ q: t }); }} > {t} ))} > )} {mine && !account.loading && !account.user ? ( {account.error && ( {account.error}{" "} void account.refresh()}> 重新检查 )} 登录 / 创建账户 ) : ( <> ({ id: k, label: k === "all" ? "全部文档" : kindNames[k], count: found.filter((d) => k === "all" || d.kind === k).length, }))} value={kind} onChange={(value) => { setKind(value); remember({ kind: value }); }} /> setQ(e.target.value)} /> {q && ( { setQ(""); remember({ q: "" }); }} > )} {!communityOnly && ( { const value = e.target.value as Source; setSource(value); remember({ source: value }); }} > 全部来源 社区发布 协议样例 )} { setSort(e.target.value); remember({ sort: e.target.value }); }} > 默认顺序 按标题排序 {waiting ? "正在加载文档…" : error ? `当前显示 ${documents.length} 篇,社区目录加载失败` : `找到 ${documents.length} 篇文档`} {filtered ? ( 清除所有筛选 ) : ( 最多展示最近 100 篇社区文档 )} {error && ( {error}{" "} void refresh()} > 重新加载 )} 文档 类型 版本 来源 {waiting && (!documents.length || communityOnly) ? ( {[0, 1, 2].map((i) => ( ))} ) : ( documents.map((d) => ( {d.title} {d.summary} {d.id} v{d.revision} {d.source === "example" ? "协议样例" : "社区发布"} v{d.revision} {d.source === "example" ? "协议样例" : "社区发布"} )) )} {!waiting && !documents.length && !error && ( {filtered ? ( 重置筛选 ) : ( 发布一篇文档 )} )} {mine ? "只有你可以更新自己的文档,已发布的历史版本保持不变。" : "社区文档与协议样例分别标识,采用前请确认适用条件与版本。"} 了解读取规范 > )} > ); }
每篇文档都有适用条件和固定版本。需要更多时,再沿着有用的链接继续阅读。
{waiting ? "正在加载文档…" : error ? `当前显示 ${documents.length} 篇,社区目录加载失败` : `找到 ${documents.length} 篇文档`}
{d.summary}
{d.id}