Pipeline/frontend/src/components/ui/table-state.tsx

67 lines
1.7 KiB
TypeScript

import type { ReactNode } from "react";
import Link from "next/link";
import { Loader2 } from "lucide-react";
import { buttonVariants } from "@/components/ui/button";
type TableLoadingRowProps = {
colSpan: number;
label?: string;
};
export function TableLoadingRow({
colSpan,
label = "Loading…",
}: TableLoadingRowProps) {
return (
<tr>
<td colSpan={colSpan} className="px-6 py-8">
<div className="flex items-center gap-2 text-sm text-muted">
<Loader2 className="h-4 w-4 animate-spin text-[color:var(--accent)]" />
<span>{label}</span>
</div>
</td>
</tr>
);
}
type TableEmptyStateRowProps = {
colSpan: number;
icon: ReactNode;
title: string;
description: string;
actionHref?: string;
actionLabel?: string;
};
export function TableEmptyStateRow({
colSpan,
icon,
title,
description,
actionHref,
actionLabel,
}: TableEmptyStateRowProps) {
return (
<tr>
<td colSpan={colSpan} className="px-6 py-16">
<div className="flex flex-col items-center justify-center text-center">
<div className="mb-4 rounded-2xl border border-[color:var(--border)] bg-[color:var(--surface-muted)] p-4 text-[color:var(--text-muted)]">
{icon}
</div>
<h3 className="mb-2 text-lg font-semibold text-strong">{title}</h3>
<p className="mb-6 max-w-md text-sm text-muted">{description}</p>
{actionHref && actionLabel ? (
<Link
href={actionHref}
className={buttonVariants({ size: "md", variant: "primary" })}
>
{actionLabel}
</Link>
) : null}
</div>
</td>
</tr>
);
}