Skip to content

Commit bb45c31

Browse files
author
marcus
committed
fix some UI
1 parent d0e9680 commit bb45c31

12 files changed

Lines changed: 431 additions & 105 deletions

package-lock.json

Lines changed: 61 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
},
1818
"dependencies": {
1919
"@prisma/client": "6.5.0",
20+
"@radix-ui/react-popover": "^1.1.15",
2021
"@radix-ui/react-select": "^2.2.6",
2122
"@radix-ui/react-slot": "^1.2.4",
2223
"@supabase/ssr": "0.5.2",
@@ -26,6 +27,7 @@
2627
"bullmq": "5.44.0",
2728
"class-variance-authority": "^0.7.1",
2829
"clsx": "^2.1.1",
30+
"date-fns": "^4.1.0",
2931
"dotenv": "^16.4.7",
3032
"ioredis": "5.5.0",
3133
"lucide-react": "^0.542.0",
@@ -34,8 +36,10 @@
3436
"pdf-lib": "1.17.1",
3537
"radix-ui": "^1.4.3",
3638
"react": "18.3.1",
39+
"react-day-picker": "^9.14.0",
3740
"react-dom": "18.3.1",
3841
"recharts": "2.15.1",
42+
"sonner": "^2.0.7",
3943
"tailwind-merge": "^3.5.0",
4044
"tw-animate-css": "^1.4.0",
4145
"zod": "3.24.2",

src/app/globals.css

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,52 @@ body {
161161
color: var(--foreground);
162162
min-height: 100vh;
163163
}
164+
165+
/* Sonner hard theme overrides */
166+
[data-sonner-toaster] [data-sonner-toast] {
167+
background: color-mix(in oklch, var(--background) 50%, transparent) !important;
168+
color: var(--foreground) !important;
169+
border: 1px solid color-mix(in oklch, var(--border) 82%, transparent) !important;
170+
box-shadow: var(--shadow-xl) !important;
171+
backdrop-filter: blur(6px) !important;
172+
-webkit-backdrop-filter: blur(6px) !important;
173+
}
174+
175+
[data-sonner-toaster] [data-sonner-toast] [data-title] {
176+
color: var(--foreground) !important;
177+
font-weight: 600 !important;
178+
}
179+
180+
[data-sonner-toaster] [data-sonner-toast] [data-description] {
181+
color: color-mix(in oklch, var(--foreground) 84%, var(--background) 16%) !important;
182+
}
183+
184+
[data-sonner-toaster] [data-sonner-toast] [data-close-button] {
185+
background: color-mix(in oklch, var(--background) 45%, transparent) !important;
186+
color: var(--foreground) !important;
187+
border: 1px solid color-mix(in oklch, var(--border) 88%, transparent) !important;
188+
}
189+
190+
[data-sonner-toaster] [data-sonner-toast] [data-close-button]:hover {
191+
background: color-mix(in oklch, var(--accent) 36%, transparent) !important;
192+
color: var(--foreground) !important;
193+
}
194+
195+
[data-sonner-toaster] [data-sonner-toast] [data-close-button] svg {
196+
stroke: currentColor !important;
197+
}
198+
199+
[data-sonner-toaster] [data-sonner-toast][data-type="success"] {
200+
border-color: color-mix(in oklch, #10b981 58%, var(--border) 42%) !important;
201+
background: color-mix(in oklch, #10b981 8%, transparent) !important;
202+
}
203+
204+
[data-sonner-toaster] [data-sonner-toast][data-type="error"] {
205+
border-color: color-mix(in oklch, #ef4444 58%, var(--border) 42%) !important;
206+
background: color-mix(in oklch, #ef4444 8%, transparent) !important;
207+
}
208+
209+
[data-sonner-toaster] [data-sonner-toast][data-type="default"] {
210+
border-color: color-mix(in oklch, var(--primary) 56%, var(--border) 44%) !important;
211+
background: color-mix(in oklch, var(--primary) 8%, transparent) !important;
212+
}

src/app/public-report/[token]/page.tsx

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
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";
23
import { prisma } from "@/server/db/prisma";
34
import { BadgeCheck, CalendarClock, GitCommitHorizontal, GitMerge, GitPullRequest, Workflow } from "lucide-react";
45
import { notFound } from "next/navigation";
@@ -94,48 +95,61 @@ export default async function PublicReportPage({ params }: { params: Promise<{ t
9495
const chartData = Array.from(byDay.entries()).map(([date, counts]) => ({ date, ...counts }));
9596

9697
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>
109112

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">
111114
<Metric label="Commits (90d)" value={totals.commits} icon={<GitCommitHorizontal className="size-4" />} />
112115
<Metric label="Merge requests (90d)" value={totals.merges} icon={<GitMerge className="size-4" />} />
113116
<Metric label="Pull requests (90d)" value={totals.prs} icon={<GitPullRequest className="size-4" />} />
114117
<Metric label="Pipelines (90d)" value={totals.pipelines} icon={<Workflow className="size-4" />} />
115118
</section>
116119

117-
<PublicReportVisuals data={chartData} />
120+
<section className="animate-in fade-in slide-in-from-bottom-2 duration-500">
121+
<DashboardChart data={chartData} />
122+
</section>
118123

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>
131145
</section>
132146
</div>
133147
);
134148
}
135149

136150
function Metric({ label, value, icon }: { label: string; value: number; icon: ReactNode }) {
137151
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">
139153
<p className="inline-flex items-center gap-1.5 text-sm text-muted-foreground">
140154
{icon}
141155
{label}

src/components/account-controls.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"use client";
22

3+
import { useAppToast } from "@/components/providers";
34
import { Button } from "@/components/ui/button";
4-
import { createClientSupabase } from "@/lib/supabase/client";
55
import { useDeleteAccountMutation, useDisconnectIntegrationMutation } from "@/lib/api/hooks";
6-
import { useAppToast } from "@/components/providers";
6+
import { createClientSupabase } from "@/lib/supabase/client";
77
import { GitBranch, Github, LogOut, Trash2, Unplug } from "lucide-react";
88

99
export function AccountControls() {
@@ -16,6 +16,7 @@ export function AccountControls() {
1616
await supabase.auth.signOut();
1717
window.location.href = "/";
1818
}
19+
pushToast({ title: "Provider disconnected", subtitle: "test" }, "success");
1920

2021
async function disconnect(provider: "GITLAB" | "AZURE_DEVOPS" | "GITHUB") {
2122
try {

src/components/backfill-jobs-panel.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"use client";
22

3-
import { useRouter } from "next/navigation";
4-
import { useState } from "react";
5-
import { AlertCircle, CheckCircle2, Clock3, RefreshCw, XCircle } from "lucide-react";
3+
import { useAppToast } from "@/components/providers";
64
import { Button } from "@/components/ui/button";
75
import { useBackfillActionMutation } from "@/lib/api/hooks";
8-
import { useAppToast } from "@/components/providers";
96
import { startSyncWatch } from "@/lib/sync-watch";
7+
import { AlertCircle, CheckCircle2, Clock3, Loader2, RefreshCw, Trash2, XCircle } from "lucide-react";
8+
import { useRouter } from "next/navigation";
9+
import { useState } from "react";
1010

1111
export type BackfillJobRow = {
1212
id: string;
@@ -59,12 +59,12 @@ export function BackfillJobsPanel({ jobs }: Props) {
5959
<div className="mb-2 flex justify-end">
6060
<Button
6161
size="sm"
62-
variant="outline"
62+
variant="destructive"
6363
type="button"
6464
disabled={busyAction === "cleanup:all"}
6565
onClick={() => postForm("cleanup")}
6666
>
67-
{busyAction === "cleanup:all" ? "Cleaning..." : "Clear completed"}
67+
{busyAction === "cleanup:all" ? <span className="flex gap-1"><Loader2 className="size-4 animate-spin" /> Cleaning...</span> : <span className="flex gap-1"><Trash2 /> Clean completed</span>}
6868
</Button>
6969
</div>
7070
) : null}
@@ -98,14 +98,22 @@ export function BackfillJobsPanel({ jobs }: Props) {
9898
</Button>
9999
) : null}
100100
<Button
101-
size="sm"
102-
variant="ghost"
103-
className="text-muted-foreground hover:text-foreground"
101+
size="icon"
102+
variant="destructive"
103+
className="gap-1"
104104
type="button"
105105
disabled={busyAction === `delete:${job.id}`}
106106
onClick={() => postForm("delete", job.id)}
107107
>
108-
Delete
108+
{busyAction === `delete:${job.id}` ? (
109+
<>
110+
<Loader2 className="size-4 animate-spin" />
111+
</>
112+
) : (
113+
<>
114+
<Trash2 className="size-4" />
115+
</>
116+
)}
109117
</Button>
110118
</div>
111119
</div>

0 commit comments

Comments
 (0)