feat(home): role-aware project list with inbox badges
This commit is contained in:
parent
2eda3e7a39
commit
a876ad6118
1 changed files with 81 additions and 7 deletions
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue