empty.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { cva, type VariantProps } from 'class-variance-authority';
  2. import { cn } from '@/lib/utils';
  3. function Empty({ className, ...props }: React.ComponentProps<'div'>) {
  4. return (
  5. <div
  6. data-slot="empty"
  7. className={cn(
  8. 'gap-4 rounded-xl border-dashed p-6 flex w-full min-w-0 flex-1 flex-col items-center justify-center text-center text-balance',
  9. className,
  10. )}
  11. {...props}
  12. />
  13. );
  14. }
  15. function EmptyHeader({ className, ...props }: React.ComponentProps<'div'>) {
  16. return (
  17. <div
  18. data-slot="empty-header"
  19. className={cn('gap-2 flex max-w-sm flex-col items-center', className)}
  20. {...props}
  21. />
  22. );
  23. }
  24. const emptyMediaVariants = cva(
  25. 'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
  26. {
  27. variants: {
  28. variant: {
  29. default: 'bg-transparent',
  30. icon: "bg-muted text-foreground flex size-8 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-4",
  31. },
  32. },
  33. defaultVariants: {
  34. variant: 'default',
  35. },
  36. },
  37. );
  38. function EmptyMedia({
  39. className,
  40. variant = 'default',
  41. ...props
  42. }: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) {
  43. return (
  44. <div
  45. data-slot="empty-icon"
  46. data-variant={variant}
  47. className={cn(emptyMediaVariants({ variant, className }))}
  48. {...props}
  49. />
  50. );
  51. }
  52. function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>) {
  53. return (
  54. <div
  55. data-slot="empty-title"
  56. className={cn(
  57. 'text-sm font-medium tracking-tight cn-font-heading',
  58. className,
  59. )}
  60. {...props}
  61. />
  62. );
  63. }
  64. function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
  65. return (
  66. <div
  67. data-slot="empty-description"
  68. className={cn(
  69. 'text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary',
  70. className,
  71. )}
  72. {...props}
  73. />
  74. );
  75. }
  76. function EmptyContent({ className, ...props }: React.ComponentProps<'div'>) {
  77. return (
  78. <div
  79. data-slot="empty-content"
  80. className={cn(
  81. 'gap-2.5 text-sm flex w-full max-w-sm min-w-0 flex-col items-center text-balance',
  82. className,
  83. )}
  84. {...props}
  85. />
  86. );
  87. }
  88. export {
  89. Empty,
  90. EmptyHeader,
  91. EmptyTitle,
  92. EmptyDescription,
  93. EmptyContent,
  94. EmptyMedia,
  95. };