91 lines
3.6 KiB
TypeScript
91 lines
3.6 KiB
TypeScript
import Link from "next/link";
|
|
import { listAllStudios } from "@/lib/db/queries";
|
|
import { createStudioAction } from "@/app/actions/entities";
|
|
import { Building2, Plus, ArrowDownAZ, Hash } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function StudiosPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<Record<string, string | string[] | undefined>>;
|
|
}) {
|
|
const sp = await searchParams;
|
|
const sort: "az" | "count" = sp.sort === "count" ? "count" : "az";
|
|
const raw = listAllStudios();
|
|
const items = sort === "count"
|
|
? [...raw].sort((a, b) => b.count - a.count || a.name.localeCompare(b.name))
|
|
: [...raw].sort((a, b) => a.name.localeCompare(b.name));
|
|
return (
|
|
<div className="max-w-[1600px] mx-auto px-6 py-6 fade-in">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h1 className="text-3xl font-semibold tracking-tight">Studios</h1>
|
|
<p className="text-[var(--color-fg-dim)] mt-1">{items.length} total</p>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex items-center rounded-lg glass overflow-hidden text-xs">
|
|
<Link
|
|
href="/studios"
|
|
className={cn(
|
|
"flex items-center gap-1 px-2.5 py-1.5",
|
|
sort === "az"
|
|
? "bg-[var(--color-cyan)] text-black font-medium"
|
|
: "text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]",
|
|
)}
|
|
title="Sort A → Z"
|
|
>
|
|
<ArrowDownAZ className="w-3.5 h-3.5" /> A-Z
|
|
</Link>
|
|
<Link
|
|
href="/studios?sort=count"
|
|
className={cn(
|
|
"flex items-center gap-1 px-2.5 py-1.5",
|
|
sort === "count"
|
|
? "bg-[var(--color-cyan)] text-black font-medium"
|
|
: "text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]",
|
|
)}
|
|
title="Sort by cover count"
|
|
>
|
|
<Hash className="w-3.5 h-3.5" /> Count
|
|
</Link>
|
|
</div>
|
|
<form action={createStudioAction} className="flex items-center gap-2">
|
|
<input
|
|
name="name"
|
|
placeholder="New studio"
|
|
required
|
|
maxLength={80}
|
|
className="glass rounded-lg px-3 py-1.5 text-sm outline-none focus:border-[var(--color-cyan)] w-56"
|
|
/>
|
|
<button className="flex items-center gap-1 text-sm px-3 py-1.5 rounded-lg bg-[var(--color-cyan)] text-black font-medium">
|
|
<Plus className="w-4 h-4" /> Create
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
{items.length === 0 ? (
|
|
<div className="glass rounded-2xl p-card text-center">
|
|
<Building2 className="w-8 h-8 mx-auto text-[var(--color-fg-dim)] mb-label" />
|
|
<p className="text-[var(--color-fg-dim)]">No studios yet. Create one above or add from any cover.</p>
|
|
</div>
|
|
) : (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
|
|
{items.map((s) => (
|
|
<Link
|
|
key={s.id}
|
|
href={`/studios/${s.slug}`}
|
|
className="glass glass-hover rounded-xl p-4 flex items-center justify-between gap-3"
|
|
>
|
|
<span className="font-medium truncate">{s.name}</span>
|
|
<span className="text-xs font-mono text-[var(--color-fg-muted)] tabular-nums">{s.count}</span>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|