|
1 | | -import { PublicReportVisuals } from "@/components/public-report-visuals"; |
| 1 | +import { DashboardChart } from "@/components/dashboard-chart"; |
| 2 | +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; |
2 | 3 | import { prisma } from "@/server/db/prisma"; |
3 | 4 | import { BadgeCheck, CalendarClock, GitCommitHorizontal, GitMerge, GitPullRequest, Workflow } from "lucide-react"; |
4 | 5 | import { notFound } from "next/navigation"; |
@@ -94,48 +95,61 @@ export default async function PublicReportPage({ params }: { params: Promise<{ t |
94 | 95 | const chartData = Array.from(byDay.entries()).map(([date, counts]) => ({ date, ...counts })); |
95 | 96 |
|
96 | 97 | return ( |
97 | | - <div className="mx-auto flex flex-col max-w-6xl gap-6"> |
98 | | - <section className="rounded-2xl border border-border/60 bg-card/70 p-6 shadow-sm"> |
99 | | - <p className="mb-3 inline-flex items-center gap-2 rounded-full border border-primary/25 bg-primary/10 px-3 py-1 text-xs font-medium text-primary"> |
100 | | - <BadgeCheck className="size-3.5" /> |
101 | | - Public read-only report |
102 | | - </p> |
103 | | - <h1 className="text-2xl font-semibold tracking-tight sm:text-3xl">Contribution verification report</h1> |
104 | | - <p className="mt-2 inline-flex items-start gap-2 text-sm text-muted-foreground"> |
105 | | - <CalendarClock className="mt-0.5 size-4 shrink-0 text-primary" /> |
106 | | - Verification stamp: Data pulled on {new Date().toISOString().slice(0, 10)} via official APIs; only aggregate counts stored. |
107 | | - </p> |
108 | | - </section> |
| 98 | + <div className="mx-auto flex max-w-6xl flex-col gap-6"> |
| 99 | + <div className="animate-in fade-in slide-in-from-bottom-2 flex flex-row flex-wrap items-start justify-between gap-3 duration-500"> |
| 100 | + <div> |
| 101 | + <p className="mb-2 inline-flex items-center gap-2 rounded-full border border-primary/25 bg-primary/10 px-3 py-1 text-xs font-medium text-primary"> |
| 102 | + <BadgeCheck className="size-3.5" /> |
| 103 | + Public read-only report |
| 104 | + </p> |
| 105 | + <h1 className="text-3xl font-semibold tracking-tight">Contribution verification report</h1> |
| 106 | + <p className="mt-2 inline-flex items-start gap-2 text-sm text-muted-foreground"> |
| 107 | + <CalendarClock className="mt-0.5 size-4 shrink-0 text-primary" /> |
| 108 | + Verification stamp: Data pulled on {new Date().toISOString().slice(0, 10)} via official APIs; only aggregate counts stored. |
| 109 | + </p> |
| 110 | + </div> |
| 111 | + </div> |
109 | 112 |
|
110 | | - <section className="grid gap-4 md:grid-cols-4"> |
| 113 | + <section className="animate-in fade-in slide-in-from-bottom-2 grid gap-4 duration-500 md:grid-cols-4"> |
111 | 114 | <Metric label="Commits (90d)" value={totals.commits} icon={<GitCommitHorizontal className="size-4" />} /> |
112 | 115 | <Metric label="Merge requests (90d)" value={totals.merges} icon={<GitMerge className="size-4" />} /> |
113 | 116 | <Metric label="Pull requests (90d)" value={totals.prs} icon={<GitPullRequest className="size-4" />} /> |
114 | 117 | <Metric label="Pipelines (90d)" value={totals.pipelines} icon={<Workflow className="size-4" />} /> |
115 | 118 | </section> |
116 | 119 |
|
117 | | - <PublicReportVisuals data={chartData} /> |
| 120 | + <section className="animate-in fade-in slide-in-from-bottom-2 duration-500"> |
| 121 | + <DashboardChart data={chartData} /> |
| 122 | + </section> |
118 | 123 |
|
119 | | - <section className="rounded-2xl border border-border/60 bg-card/70 p-6 shadow-sm"> |
120 | | - <h2 className="text-xl font-semibold">Manual highlights</h2> |
121 | | - <ul className="mt-3 space-y-2 text-sm"> |
122 | | - {highlights.map((highlight: any) => ( |
123 | | - <li key={highlight.id} className="rounded-lg border border-border/60 bg-background/50 p-3"> |
124 | | - <strong>{highlight.date.toISOString().slice(0, 10)}</strong>: {highlight.note} |
125 | | - </li> |
126 | | - ))} |
127 | | - {highlights.length === 0 ? ( |
128 | | - <li className="rounded-lg border border-dashed border-border/60 bg-muted/20 p-3 text-muted-foreground">No highlights shared yet.</li> |
129 | | - ) : null} |
130 | | - </ul> |
| 124 | + <section className="animate-in fade-in slide-in-from-bottom-2 duration-500"> |
| 125 | + <Card className="border-border/60 shadow-sm transition-all hover:shadow-md"> |
| 126 | + <CardHeader> |
| 127 | + <CardTitle>Manual highlights</CardTitle> |
| 128 | + </CardHeader> |
| 129 | + <CardContent> |
| 130 | + <ul className="space-y-2 text-sm"> |
| 131 | + {highlights.map((highlight: any) => ( |
| 132 | + <li key={highlight.id} className="rounded-lg border border-border/60 bg-muted/20 px-3 py-2"> |
| 133 | + <p className="font-semibold text-foreground">{highlight.date.toISOString().slice(0, 10)}</p> |
| 134 | + <p className="mt-0.5 text-muted-foreground">{highlight.note}</p> |
| 135 | + </li> |
| 136 | + ))} |
| 137 | + {highlights.length === 0 ? ( |
| 138 | + <li className="rounded-lg border border-dashed border-border/70 bg-muted/20 px-3 py-2 text-muted-foreground"> |
| 139 | + No highlights shared yet. |
| 140 | + </li> |
| 141 | + ) : null} |
| 142 | + </ul> |
| 143 | + </CardContent> |
| 144 | + </Card> |
131 | 145 | </section> |
132 | 146 | </div> |
133 | 147 | ); |
134 | 148 | } |
135 | 149 |
|
136 | 150 | function Metric({ label, value, icon }: { label: string; value: number; icon: ReactNode }) { |
137 | 151 | return ( |
138 | | - <div className="rounded-xl border border-border/60 bg-card/70 p-4 shadow-sm"> |
| 152 | + <div className="rounded-lg border border-border/60 bg-card/80 p-4 shadow-sm transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md"> |
139 | 153 | <p className="inline-flex items-center gap-1.5 text-sm text-muted-foreground"> |
140 | 154 | {icon} |
141 | 155 | {label} |
|
0 commit comments