134 c3faeba1c8 Squashed 'services/pascal-editor/' content from commit 312064e6
git-subtree-dir: services/pascal-editor
git-subtree-split: 312064e6e8122f958d2961e28ea85ad8b9db40c5
2026-07-12 00:43:59 +08:00

97 lines
3.8 KiB
TypeScript

import { headers } from 'next/headers'
import Link from 'next/link'
import { CreateSceneButton } from '@/components/save-button'
import type { SceneMeta } from '@/components/scene-loader'
import { getPascalHostIdentity } from '@/lib/pascal-host-identity'
import { getSceneOperations } from '@/lib/scene-store-server'
export const dynamic = 'force-dynamic'
async function fetchScenes(): Promise<SceneMeta[]> {
const identity = getPascalHostIdentity(await headers())
if (!identity.allowed) return []
const operations = await getSceneOperations()
return operations.listScenes({ limit: 50, ownerId: identity.userId ?? undefined })
}
function formatDate(iso: string): string {
try {
return new Date(iso).toLocaleString('zh-CN', { hour12: false })
} catch {
return iso
}
}
export default async function ScenesPage() {
const scenes = await fetchScenes()
return (
<div className="min-h-screen bg-background">
<header className="sticky top-0 z-10 border-border border-b bg-background/95 backdrop-blur">
<div className="container mx-auto flex items-center justify-between gap-4 px-6 py-4">
<nav className="flex items-center gap-4 text-sm">
<Link
className="text-muted-foreground transition-colors hover:text-foreground"
href="/"
>
首页
</Link>
<span className="text-muted-foreground">/</span>
<span className="font-medium text-foreground">场景</span>
</nav>
<CreateSceneButton />
</div>
</header>
<main className="container mx-auto max-w-5xl px-6 py-12">
<h1 className="mb-2 font-bold text-3xl">我的场景</h1>
<p className="mb-8 text-muted-foreground text-sm">
{scenes.length === 0 ? '还没有场景,创建一个开始设计吧。' : `共 ${scenes.length} 个场景`}
</p>
{scenes.length === 0 ? (
<div className="rounded-xl border border-border/60 border-dashed bg-background p-12 text-center">
<p className="text-muted-foreground text-sm">尚未保存任何场景。</p>
<div className="mt-4 flex justify-center">
<CreateSceneButton />
</div>
</div>
) : (
<ul className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{scenes.map((scene) => (
<li key={scene.id}>
<Link
className="group block rounded-xl border border-border/60 bg-background p-4 transition-colors hover:border-border hover:bg-accent/30"
href={`/scene/${scene.id}`}
>
<div className="flex aspect-video items-center justify-center overflow-hidden rounded-lg bg-accent/30">
{scene.thumbnailUrl ? (
// eslint-disable-next-line @next/next/no-img-element
<img
alt={scene.name}
className="h-full w-full object-cover"
src={scene.thumbnailUrl}
/>
) : (
<span className="text-muted-foreground text-xs">暂无缩略图</span>
)}
</div>
<div className="mt-3">
<h2 className="truncate font-semibold text-sm group-hover:text-foreground">
{scene.name}
</h2>
<div className="mt-1 flex items-center justify-between text-muted-foreground text-xs">
<span>{scene.nodeCount} 个元素</span>
<time dateTime={scene.updatedAt}>{formatDate(scene.updatedAt)}</time>
</div>
</div>
</Link>
</li>
))}
</ul>
)}
</main>
</div>
)
}