feat: improve app ui and project metadata

This commit is contained in:
Yaojia Wang
2026-06-28 07:31:20 +02:00
parent 3bd464d400
commit 90a66437d7
86 changed files with 4892 additions and 1108 deletions

View File

@@ -1,9 +1,13 @@
import Link from "next/link";
import { BookOpen, Plus } from "lucide-react";
import { AppShell } from "@/components/AppShell";
import { ProjectCard } from "@/components/ProjectCard";
import { ProjectLibrary } from "@/components/projects/ProjectLibrary";
import { EmptyState } from "@/components/ui/EmptyState";
import { PageHeader } from "@/components/ui/PageHeader";
import { fetchProjects } from "@/lib/api/server";
import type { ProjectResponse } from "@/lib/api/types";
import { buttonClass } from "@/lib/ui/variants";
// 作品库Dashboard 入口UX §6.1。Server Component 读取。
export default async function DashboardPage() {
@@ -18,63 +22,44 @@ export default async function DashboardPage() {
return (
<AppShell>
<div className="mx-auto max-w-5xl px-8 py-10">
<div className="mb-8 flex items-center justify-between">
<h1 className="font-serif text-3xl text-ink"></h1>
<Link
href="/projects/new"
className="rounded bg-cinnabar px-4 py-2 text-sm text-panel hover:opacity-90"
>
</Link>
</div>
<div className="mx-auto max-w-5xl px-6 py-10 sm:px-8">
<PageHeader
title="我的作品"
description="从一个灵感进入正文、设定、审稿与验收闭环。"
actions={
<Link
href="/projects/new"
className={buttonClass({ variant: "primary" })}
>
<Plus className="h-4 w-4" aria-hidden="true" />
</Link>
}
/>
{loadError ? (
<p className="rounded border border-conflict bg-panel p-6 text-conflict">
API
</p>
) : projects.length === 0 ? (
<EmptyState />
<EmptyState
icon={BookOpen}
title="还没有作品"
description="从一句灵感开始,后续的设定库、大纲、写章和审稿都会围绕这本书展开。"
action={
<Link
href="/projects/new"
className={buttonClass({ variant: "primary" })}
>
<Plus className="h-4 w-4" aria-hidden="true" />
</Link>
}
/>
) : (
<ul className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
{projects.map((p) => (
<li key={p.id}>
<ProjectCard project={p} />
</li>
))}
<li>
<NewProjectCard />
</li>
</ul>
<ProjectLibrary projects={projects} />
)}
</div>
</AppShell>
);
}
function EmptyState() {
return (
<div className="flex flex-col items-center gap-4 rounded border border-line bg-panel py-20 text-center">
<p className="font-serif text-2xl text-ink"></p>
<p className="text-ink-soft"></p>
<Link
href="/projects/new"
className="rounded bg-cinnabar px-5 py-2 text-sm text-panel hover:opacity-90"
>
</Link>
</div>
);
}
function NewProjectCard() {
return (
<Link
href="/projects/new"
className="flex h-full min-h-[160px] flex-col items-center justify-center rounded border border-dashed border-line bg-panel text-center hover:border-cinnabar"
>
<span className="font-serif text-xl text-cinnabar"> </span>
<span className="mt-2 text-sm text-ink-soft"></span>
</Link>
);
}