Spaces:
Running
Running
File size: 2,692 Bytes
5f3e9f5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | import { Inbox } from 'lucide-react'
import type { ReactNode } from 'react'
interface Props {
icon?: ReactNode
title: string
description?: ReactNode
action?: ReactNode
/**
* One of "default" | "muted". `muted` removes the dot-grid texture for
* cases where the empty state sits inside an already-decorated card.
*/
variant?: 'default' | 'muted'
}
/**
* Friendly empty-state card — used everywhere a list/grid would otherwise
* render as a single line of grey text. The default variant uses the same
* dot-grid surface as the dashboard so it reads as "intentionally empty"
* rather than "broken".
*/
export default function EmptyState({
icon,
title,
description,
action,
variant = 'default',
}: Props) {
return (
<div
role="status"
className={
'flex flex-col items-center justify-center gap-3 rounded-xl px-6 py-12 text-center ' +
(variant === 'default'
? 'surface dot-grid'
: 'border border-dashed border-slate-200 bg-slate-50 dark:border-white/10 dark:bg-white/[0.02]')
}
>
<EmptyIllustration>{icon}</EmptyIllustration>
<div className="text-sm font-semibold text-slate-800 dark:text-slate-100">
{title}
</div>
{description && (
<div className="max-w-sm text-xs leading-relaxed text-slate-500 dark:text-slate-400">
{description}
</div>
)}
{action && <div className="mt-2">{action}</div>}
</div>
)
}
function EmptyIllustration({ children }: { children?: ReactNode }) {
// Layered "stacked cards" SVG — feels like a deck of slides waiting to
// be filled. Uses currentColor so it adopts the brand tint where set.
return (
<div className="relative flex h-16 w-16 items-center justify-center text-brand-500/70 dark:text-brand-300/70">
<svg
aria-hidden="true"
viewBox="0 0 64 64"
fill="none"
className="absolute inset-0"
>
<rect
x="10"
y="14"
width="40"
height="28"
rx="4"
className="fill-slate-100 dark:fill-white/[0.04]"
/>
<rect
x="14"
y="20"
width="40"
height="28"
rx="4"
className="fill-slate-200/70 dark:fill-white/[0.06]"
/>
<rect
x="18"
y="26"
width="40"
height="28"
rx="4"
className="fill-white stroke-slate-200 dark:fill-white/[0.08] dark:stroke-white/10"
strokeWidth="1"
/>
</svg>
<div className="relative">
{children ?? <Inbox size={20} strokeWidth={1.75} />}
</div>
</div>
)
}
|