veza/apps/web/src/components/ui/empty-state.tsx

175 lines
3.8 KiB
TypeScript
Raw Normal View History

import { ReactNode } from 'react';
import { Button } from './button';
import { Card, CardContent } from './card';
import { cn } from '@/lib/utils';
// FE-COMP-003: Add empty states to all list views
/**
* EmptyStateProps - Propriétés du composant EmptyState
*
* @interface EmptyStateProps
*/
export interface EmptyStateProps {
/**
* Icône à afficher au-dessus du titre
*
* @example
* ```tsx
* <EmptyState icon={<Inbox />} title="Aucun élément" />
* ```
*/
icon?: ReactNode;
/**
* Titre de l'état vide (requis)
*
* @example
* ```tsx
* <EmptyState title="Aucun résultat trouvé" />
* ```
*/
title: string;
/**
* Description optionnelle sous le titre
*
* @example
* ```tsx
* <EmptyState
* title="Aucun résultat"
* description="Essayez de modifier vos critères de recherche"
* />
* ```
*/
description?: string;
/**
* Action optionnelle (bouton) à afficher sous la description
*
* @example
* ```tsx
* <EmptyState
* title="Aucun élément"
* action={{
* label: "Créer un élément",
* onClick: () => handleCreate(),
* variant: "primary"
* }}
* />
* ```
*/
action?: {
/** Texte du bouton */
label: string;
/** Fonction appelée lors du clic */
onClick: () => void;
/** Variant du bouton */
variant?: 'default' | 'outline' | 'ghost';
};
/**
* Classes CSS personnalisées
*/
className?: string;
/**
* Taille de l'état vide
*
* - `sm`: Petit (py-6, icône h-8 w-8)
* - `md`: Moyen (py-12, icône h-12 w-12) - par défaut
* - `lg`: Grand (py-16, icône h-16 w-16)
*
* @default 'md'
*/
size?: 'sm' | 'md' | 'lg';
}
/**
* EmptyState - Composant réutilisable pour afficher des états vides dans les listes
*
* Composant pour afficher un état vide lorsqu'une liste ou une section est vide.
* Design Kodo intégré avec support pour icône, titre, description et action.
*
* FE-COMP-003: Add empty states to all list views
*
* @example
* ```tsx
* // État vide simple
* <EmptyState
* title="Aucun élément trouvé"
* description="Il n'y a pas encore d'éléments à afficher"
* />
* ```
*
* @example
* ```tsx
* // État vide avec icône et action
* <EmptyState
* icon={<Inbox />}
* title="Aucun message"
* description="Vous n'avez pas encore de messages"
* action={{
* label: "Créer un message",
* onClick: () => handleCreate(),
* variant: "primary"
* }}
* />
* ```
*
* @component
* @param {EmptyStateProps} props - Propriétés du composant
* @returns {JSX.Element} Card contenant l'état vide stylisé
*/
export function EmptyState({
icon,
title,
description,
action,
className,
size = 'md',
}: EmptyStateProps) {
const sizeClasses = {
sm: 'py-6',
md: 'py-12',
lg: 'py-16',
};
const iconSizeClasses = {
sm: 'h-8 w-8',
md: 'h-12 w-12',
lg: 'h-16 w-16',
};
return (
<Card className={cn(className)}>
<CardContent className={cn('text-center', sizeClasses[size])}>
{icon && (
<div className="flex justify-center mb-4">
<div className={cn('text-muted-foreground', iconSizeClasses[size])}>
{icon}
</div>
</div>
)}
<h3 className="text-lg font-semibold mb-2 text-foreground font-display">
{title}
</h3>
{description && (
<p className="text-sm text-muted-foreground mb-4 max-w-md mx-auto">
{description}
</p>
)}
{action && (
<Button
onClick={action.onClick}
variant={action.variant || 'default'}
size={size === 'sm' ? 'sm' : 'default'}
>
{action.label}
</Button>
)}
</CardContent>
</Card>
);
}