feat(home): role-aware project list with inbox badges

This commit is contained in:
Dave 2026-09-16 10:02:02 +02:00
parent 2eda3e7a39
commit a876ad6118

View file

@ -1,10 +1,84 @@
export default function Home() {
import Link from "next/link";
import { redirect } from "next/navigation";
import { Inbox } from "lucide-react";
import { AppShell } from "@/components/shell/app-shell";
import { TopBar } from "@/components/shell/top-bar";
import { Pill } from "@/components/ui/pill";
import { getSession } from "@/lib/auth/session";
import { loadProjectSummaries } from "@/lib/data/board";
export default async function HomePage() {
const session = await getSession();
if (!session) redirect("/login");
const summaries = await loadProjectSummaries();
return (
<main className="p-8">
<h1 className="text-2xl font-semibold">Client Board</h1>
<p className="mt-2 text-neutral-400">
The board UI arrives in Plan 1b. Sign in at <code>/login</code>.
</p>
</main>
<AppShell role={session.role} currentPath="/">
<TopBar
title="Projects"
subtitle={
session.role === "owner"
? "Everything you are building"
: "Your active projects"
}
/>
<div className="flex-1 overflow-y-auto p-6">
{summaries.length === 0 ? (
<div className="mx-auto mt-16 max-w-sm text-center">
<h2 className="text-base font-medium">No projects yet</h2>
<p className="mt-1.5 text-sm text-text-muted">
{session.role === "owner"
? "Create one from Manage, or run npm run seed for demo data."
: "Nothing has been shared with you yet."}
</p>
</div>
) : (
<ul className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
{summaries.map(({ project, client, openCards, inboxCards }) => (
<li key={project.id}>
<Link
href={`/p/${client.slug}/${project.slug}`}
className="group block rounded-[var(--radius-tile)] border border-border-subtle bg-surface p-4 transition-colors hover:border-border-strong"
>
<div className="flex items-start gap-3">
<span
aria-hidden
className="mt-1 h-2.5 w-2.5 shrink-0 rounded-full"
style={{ background: client.brand_color || "var(--brand)" }}
/>
<div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium">
{project.name}
</p>
<p className="truncate text-xs text-text-muted">
{client.name}
</p>
</div>
{inboxCards > 0 && (
<Pill tone="accent">
<Inbox size={11} strokeWidth={2} />
<span className="tabular">{inboxCards}</span>
</Pill>
)}
</div>
<div className="mt-4 flex items-center gap-2">
<span className="tabular text-2xl font-semibold tracking-tight">
{openCards}
</span>
<span className="text-xs text-text-muted">
open {openCards === 1 ? "card" : "cards"}
</span>
</div>
</Link>
</li>
))}
</ul>
)}
</div>
</AppShell>
);
}