ui: create Spinner component for inline loading states (Action 8.3.1.4)
- Created Spinner.tsx component for inline use in buttons and UI elements - Size variants: sm, md, lg - Color variants: default (kodo-cyan), muted, white, current - Uses Loader2 from lucide-react with Kodo design system styling - Includes accessibility attributes (sr-only label) - Different from LoadingSpinner (which is for full-page states) - Task 8.3.1.4 complete
This commit is contained in:
parent
b9cceae6b5
commit
ac65373c36
2 changed files with 118 additions and 3 deletions
|
|
@ -2942,11 +2942,18 @@ Critical path dependencies:
|
|||
- **Result**: All high and medium priority mutation buttons now have loading states. Low priority buttons (auto-triggered notifications) can be enhanced incrementally if needed.
|
||||
- **Rollback**: Remove loading states
|
||||
|
||||
- [ ] **Action 8.3.1.4**: Create Spinner component (if doesn't exist)
|
||||
- [x] **Action 8.3.1.4**: Create Spinner component (if doesn't exist)
|
||||
- **Scope**: `apps/web/src/components/ui/Spinner.tsx` (create) - Reusable spinner component
|
||||
- **Dependencies**: None
|
||||
- **Dependencies**: None ✅
|
||||
- **Risk**: LOW 🔒
|
||||
- **Validation**: Spinner component works
|
||||
- **Validation**: ✅ Spinner component created:
|
||||
- **File**: Created `apps/web/src/components/ui/Spinner.tsx`
|
||||
- **Component**: Simple, reusable inline spinner component
|
||||
- **Features**: Size variants (sm, md, lg), color variants (default, muted, white, current), accessibility (aria-label, role="status")
|
||||
- **Design**: Uses Kodo design system colors (kodo-cyan by default), wraps Loader2 from lucide-react
|
||||
- **Purpose**: Optimized for inline use in buttons and UI elements (different from LoadingSpinner which is for full-page states)
|
||||
- **Pattern**: Follows existing component patterns with TypeScript interfaces and JSDoc documentation
|
||||
- **Result**: Reusable spinner component ready for use in loading states
|
||||
- **Rollback**: Delete component
|
||||
|
||||
- [ ] **Action 8.3.1.5**: Use Spinner in loading states
|
||||
|
|
|
|||
108
apps/web/src/components/ui/Spinner.tsx
Normal file
108
apps/web/src/components/ui/Spinner.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import { Loader2 } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
/**
|
||||
* SpinnerProps - Propriétés du composant Spinner
|
||||
*
|
||||
* @interface SpinnerProps
|
||||
*/
|
||||
export interface SpinnerProps {
|
||||
/**
|
||||
* Taille du spinner
|
||||
*
|
||||
* - `sm`: Petit (h-4 w-4) - pour les boutons et éléments compacts
|
||||
* - `md`: Moyen (h-5 w-5) - par défaut
|
||||
* - `lg`: Grand (h-6 w-6) - pour les éléments plus grands
|
||||
*
|
||||
* @default 'md'
|
||||
*/
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
|
||||
/**
|
||||
* Couleur du spinner
|
||||
*
|
||||
* - `default`: Couleur par défaut (kodo-cyan pour le thème Kodo)
|
||||
* - `muted`: Couleur atténuée (text-muted-foreground)
|
||||
* - `white`: Blanc
|
||||
* - `current`: Utilise la couleur du texte parent
|
||||
*
|
||||
* @default 'default'
|
||||
*/
|
||||
variant?: 'default' | 'muted' | 'white' | 'current';
|
||||
|
||||
/**
|
||||
* Classes CSS personnalisées
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* Label d'accessibilité
|
||||
*
|
||||
* @default 'Chargement en cours'
|
||||
*/
|
||||
'aria-label'?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spinner - Composant de spinner réutilisable pour les états de chargement inline
|
||||
*
|
||||
* Composant de spinner optimisé pour l'utilisation inline dans les boutons,
|
||||
* formulaires et autres éléments UI. Utilise le design system Kodo.
|
||||
*
|
||||
* Différences avec LoadingSpinner:
|
||||
* - LoadingSpinner: Pour les états de chargement de page complète avec conteneur
|
||||
* - Spinner: Pour les spinners inline dans les boutons et éléments UI
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // Spinner simple dans un bouton
|
||||
* <Button disabled={isLoading}>
|
||||
* {isLoading && <Spinner size="sm" className="mr-2" />}
|
||||
* Enregistrer
|
||||
* </Button>
|
||||
*
|
||||
* // Spinner avec couleur personnalisée
|
||||
* <Spinner size="lg" variant="muted" />
|
||||
*
|
||||
* // Spinner avec classes personnalisées
|
||||
* <Spinner className="text-kodo-cyan" />
|
||||
* ```
|
||||
*
|
||||
* @component
|
||||
* @param {SpinnerProps} props - Propriétés du composant
|
||||
* @returns {JSX.Element} Spinner animé
|
||||
*/
|
||||
export function Spinner({
|
||||
size = 'md',
|
||||
variant = 'default',
|
||||
className,
|
||||
'aria-label': ariaLabel = 'Chargement en cours',
|
||||
}: SpinnerProps) {
|
||||
const sizeClasses = {
|
||||
sm: 'h-4 w-4',
|
||||
md: 'h-5 w-5',
|
||||
lg: 'h-6 w-6',
|
||||
};
|
||||
|
||||
const variantClasses = {
|
||||
default: 'text-kodo-cyan',
|
||||
muted: 'text-muted-foreground',
|
||||
white: 'text-white',
|
||||
current: 'text-current',
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Loader2
|
||||
className={cn(
|
||||
'animate-spin',
|
||||
sizeClasses[size],
|
||||
variantClasses[variant],
|
||||
className,
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span className="sr-only">{ariaLabel}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue