feat: improve app ui and project metadata
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user