121 lines
2.6 KiB
TypeScript
121 lines
2.6 KiB
TypeScript
import React from 'react';
|
|
import { LucideIcon } from 'lucide-react';
|
|
import { Button } from '../Button';
|
|
|
|
export interface EmptyStateProps {
|
|
/**
|
|
* Icon component to display (from lucide-react)
|
|
*/
|
|
icon: LucideIcon;
|
|
|
|
/**
|
|
* Main title text
|
|
*/
|
|
title: string;
|
|
|
|
/**
|
|
* Description text (can be a string or React node for complex content)
|
|
*/
|
|
description?: string | React.ReactNode;
|
|
|
|
/**
|
|
* Optional action button label
|
|
*/
|
|
actionLabel?: string;
|
|
|
|
/**
|
|
* Optional action button click handler
|
|
*/
|
|
onAction?: () => void;
|
|
|
|
/**
|
|
* Optional icon for the action button
|
|
*/
|
|
actionIcon?: LucideIcon;
|
|
|
|
/**
|
|
* Optional action button variant
|
|
*/
|
|
actionVariant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
|
|
/**
|
|
* Optional action button size
|
|
*/
|
|
actionSize?: 'sm' | 'md' | 'lg';
|
|
|
|
/**
|
|
* Additional CSS classes for the container
|
|
*/
|
|
className?: string;
|
|
}
|
|
|
|
/**
|
|
* EmptyState Component
|
|
*
|
|
* A reusable component for displaying empty states across the application
|
|
* with consistent styling and behavior.
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* <EmptyState
|
|
* icon={Package}
|
|
* title="No items found"
|
|
* description="Try adjusting your search or add a new item"
|
|
* actionLabel="Add Item"
|
|
* actionIcon={Plus}
|
|
* onAction={() => setShowModal(true)}
|
|
* />
|
|
* ```
|
|
*/
|
|
export const EmptyState: React.FC<EmptyStateProps> = ({
|
|
icon: Icon,
|
|
title,
|
|
description,
|
|
actionLabel,
|
|
onAction,
|
|
actionIcon: ActionIcon,
|
|
actionVariant = 'primary',
|
|
actionSize = 'md',
|
|
className = '',
|
|
}) => {
|
|
return (
|
|
<div className={`text-center py-12 ${className}`}>
|
|
{/* Icon */}
|
|
<Icon className="mx-auto h-12 w-12 text-[var(--text-tertiary)] mb-4" />
|
|
|
|
{/* Title */}
|
|
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-2">
|
|
{title}
|
|
</h3>
|
|
|
|
{/* Description */}
|
|
{description && (
|
|
<div className="text-[var(--text-secondary)] mb-4">
|
|
{typeof description === 'string' ? (
|
|
<p>{description}</p>
|
|
) : (
|
|
description
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* Action Button */}
|
|
{actionLabel && onAction && (
|
|
<Button
|
|
onClick={onAction}
|
|
variant={actionVariant}
|
|
size={actionSize}
|
|
className="font-medium px-4 sm:px-6 py-2 sm:py-3 shadow-sm hover:shadow-md transition-all duration-200"
|
|
>
|
|
{ActionIcon && (
|
|
<ActionIcon className="w-3 h-3 sm:w-4 sm:h-4 mr-1 sm:mr-2 flex-shrink-0" />
|
|
)}
|
|
<span className="text-sm sm:text-base">{actionLabel}</span>
|
|
</Button>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default EmptyState;
|