From 00e1b28acaaf3d89008b5d6380d65efeb657b7c9 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 20 Aug 2026 07:16:10 +0000 Subject: [PATCH] fix: add contextual empty-state variants for dashboards (#54) --- src/app/dashboard/contributor/page.tsx | 2 +- src/app/dashboard/maintainer/page.tsx | 1 + src/components/ui/EmptyState.tsx | 58 +++++++++++++++++++++----- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/app/dashboard/contributor/page.tsx b/src/app/dashboard/contributor/page.tsx index bfc89e9..4002aeb 100644 --- a/src/app/dashboard/contributor/page.tsx +++ b/src/app/dashboard/contributor/page.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import Link from "next/link"; -import { DollarSign, GitMerge, TrendingUp, ListChecks, GitPullRequest } from "lucide-react"; +import { DollarSign, GitMerge, TrendingUp, ListChecks, GitPullRequest, CheckCircle2 } from "lucide-react"; import { DashboardShell } from "@/components/dashboard/DashboardShell"; import { ActivityList } from "@/components/dashboard/ActivityList"; import { StatCard, type StatCardStatus } from "@/components/ui/StatCard"; diff --git a/src/app/dashboard/maintainer/page.tsx b/src/app/dashboard/maintainer/page.tsx index 3e6ca6b..1e37c5f 100644 --- a/src/app/dashboard/maintainer/page.tsx +++ b/src/app/dashboard/maintainer/page.tsx @@ -125,6 +125,7 @@ export default async function MaintainerDashboardPage() { icon={CheckCircle2} title="All caught up" description="No pull requests are waiting on your review right now." + variant="success" /> )} diff --git a/src/components/ui/EmptyState.tsx b/src/components/ui/EmptyState.tsx index 5c34031..a676711 100644 --- a/src/components/ui/EmptyState.tsx +++ b/src/components/ui/EmptyState.tsx @@ -1,22 +1,60 @@ import type { LucideIcon } from "lucide-react"; +import { cn } from "@/lib/utils"; + +export type EmptyStateVariant = "default" | "success" | "filtered" | "error"; + +interface EmptyStateProps { + icon: LucideIcon; + title: string; + description: string; + action?: React.ReactNode; + /** Visual variant for contextual empty states. */ + variant?: EmptyStateVariant; +} + +const variantStyles: Record = { + default: { + container: "border-slate-200 bg-slate-50/50 dark:border-slate-800 dark:bg-slate-900/40", + icon: "bg-slate-100 text-slate-400 dark:bg-slate-800 dark:text-slate-500", + title: "text-slate-700 dark:text-slate-200", + }, + success: { + container: "border-emerald-200 bg-emerald-50/50 dark:border-emerald-800/50 dark:bg-emerald-950/20", + icon: "bg-emerald-100 text-emerald-600 dark:bg-emerald-900/50 dark:text-emerald-400", + title: "text-emerald-900 dark:text-emerald-100", + }, + filtered: { + container: "border-amber-200 bg-amber-50/50 dark:border-amber-800/50 dark:bg-amber-950/20", + icon: "bg-amber-100 text-amber-600 dark:bg-amber-900/50 dark:text-amber-400", + title: "text-amber-900 dark:text-amber-100", + }, + error: { + container: "border-rose-200 bg-rose-50/50 dark:border-rose-800/50 dark:bg-rose-950/20", + icon: "bg-rose-100 text-rose-600 dark:bg-rose-900/50 dark:text-rose-400", + title: "text-rose-900 dark:text-rose-100", + }, +}; export function EmptyState({ icon: Icon, title, description, action, -}: { - icon: LucideIcon; - title: string; - description: string; - action?: React.ReactNode; -}) { + variant = "default", +}: EmptyStateProps) { + const styles = variantStyles[variant]; + return ( -
- - +
+ + -

{title}

+

{title}

{description}

{action &&
{action}
}