84 lines
No EOL
3.1 KiB
TypeScript
84 lines
No EOL
3.1 KiB
TypeScript
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 (
|
|
<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>
|
|
);
|
|
} |