Refine documentation UI with distinct collection navigation and borderless surfaces
Verify and deploy Tabularium / verify-and-deploy (pull_request) Has been cancelled

This commit is contained in:
2026-10-28 15:31:25 +08:00
parent e381deb04e
commit 627c0ee887
9 changed files with 288 additions and 96 deletions
+6 -3
View File
@@ -18,6 +18,8 @@ import { listDocs, readDoc, type Doc, type DocLink } from "@/lib/docs";
import { Shell, Navigation } from "@/components/Shell";
import { ArchitectureFigure } from "@/components/ArchitectureFigure";
import { CodeBlock } from "@/components/CodeBlock";
import { collectionEntries, collectionLabel } from "@/lib/collections";
import { Icon } from "@/components/Icon";
import { headingsFor } from "@/lib/navigation";
type Props = { doc: Doc; docs: DocLink[] };
@@ -49,6 +51,7 @@ export default function DocPage({
const [active, setActive] = useState("");
const siblings = docs.filter((d) => d.collection === doc.collection);
const collectionEntry = collectionEntries(docs).find((c) => c.name === doc.collection)!.entry;
const index = siblings.findIndex((d) => d.slug === doc.slug);
useEffect(() => {
const observer = new IntersectionObserver(
@@ -90,9 +93,9 @@ export default function DocPage({
</aside>
<main id="content" className="reading-main">
<div className="breadcrumb">
<Link href="/">文档</Link>
<span>/</span>
<span>{doc.group}</span>
<Link href={`/docs/${collectionEntry.slug}`}>{collectionLabel(doc.collection)}</Link>
<Icon name="chevron" size={12} />
<span>{doc.slug === collectionEntry.slug ? "概览" : doc.group === doc.collection ? doc.title : doc.group}</span>
{doc.draft && <span className="draft-badge">草案</span>}
</div>
<article className="prose prose-neutral max-w-none">
+9 -8
View File
@@ -5,6 +5,7 @@ import { useState } from "react";
import { listDocs, type DocLink } from "@/lib/docs";
import { Shell, Navigation } from "@/components/Shell";
import { Icon } from "@/components/Icon";
import { collectionEntries, collectionIcon, collectionLabel, collectionTone } from "@/lib/collections";
export const getStaticProps: GetStaticProps<{ docs: DocLink[] }> = async () => ({
props: { docs: await listDocs() },
@@ -17,7 +18,7 @@ export default function Home({ docs }: InferGetStaticPropsType<typeof getStaticP
const collections = [...new Set(docs.map((doc) => doc.collection))];
const filtered = docs.filter((doc) => (!collection || doc.collection === collection) &&
`${doc.title} ${doc.description}`.toLocaleLowerCase().includes(query.trim().toLocaleLowerCase()));
const featured = docs.filter((doc) => doc.featured).slice(0, 3);
const entries = collectionEntries(docs);
return <>
<Head><title>Tabularium · 资料库</title><meta name="description" content="Endor 文档、源码研究与学习资料。" /></Head>
<Shell docs={docs}>
@@ -25,16 +26,16 @@ export default function Home({ docs }: InferGetStaticPropsType<typeof getStaticP
<aside className="sidebar"><Navigation docs={docs} /></aside>
<main id="content" className="home-main">
<section className="library-intro">
<h1>资料库</h1>
<h1>文档中心</h1>
<p>系统设计、源码研究与学习笔记。</p>
</section>
<section className="featured-section" aria-labelledby="featured-title">
<h2 id="featured-title">推荐阅读</h2>
<div className="featured-grid">{featured.map((doc) => <Link className="featured-link" href={`/docs/${doc.slug}`} key={doc.slug}>
<Icon name={doc.collection === "Endor 文档" ? "book" : "code"} size={23} />
<h3>{doc.title.replace("(草案)", "")}</h3>
<p>{doc.description}</p>
<Icon name="arrow" />
<h2 id="featured-title">选择一份文档</h2>
<div className="featured-grid">{entries.map(({ name, entry, count }) => <Link className="featured-link" data-tone={collectionTone(name)} href={`/docs/${entry.slug}`} key={name}>
<span className="collection-art"><Icon name={collectionIcon(name)} size={26} /></span>
<h3>{collectionLabel(name)}</h3>
<p>{entry.description}</p>
<span className="collection-entry">{count} 篇 <Icon name="arrow" size={17} /></span>
</Link>)}</div>
</section>
<section className="library-section" id="library" aria-labelledby="library-title">