veza/apps/web/src/features/tracks/components/TrackListSelectionActions.tsx
senke 64fbb81ddf ui(design): Phase 3 - rounded tokens, min-w/min-h, stories, NavigationProgress
- rounded-[var(--radius-xl/md/lg/sm)] → rounded-xl, rounded-md, rounded-lg, rounded-sm
- Timeline: min-w-[200px] → min-w-50
- AddEquipmentView, MetadataForm: min-h-[100px] → min-h-25
- NavigationProgress: shadow-[...] → shadow-button-primary-glow
- Stories: ActivityGraph, StatCard, NotificationBell, LoadingState, ScrollArea, Skeleton, FileUploadZone
- Reduced arbitrary values from ~60+ to 11 (5 files, exceptions documented)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 19:24:07 +01:00

163 lines
5 KiB
TypeScript

/**
* Composant TrackListSelectionActions
* Barre d'actions pour les pistes sélectionnées
*/
import { Play, Trash2, Heart, Download, MoreVertical, X } from 'lucide-react';
import { cn } from '@/lib/utils';
export interface TrackListSelectionActionsProps {
selectedCount: number;
onPlay?: (trackIds: string[]) => void;
onDelete?: (trackIds: string[]) => void;
onLike?: (trackIds: string[]) => void;
onDownload?: (trackIds: string[]) => void;
onMore?: (trackIds: string[]) => void;
onClearSelection?: () => void;
selectedTrackIds: string[];
className?: string;
}
export function TrackListSelectionActions({
selectedCount,
onPlay,
onDelete,
onLike,
onDownload,
onMore,
onClearSelection,
selectedTrackIds,
className,
}: TrackListSelectionActionsProps) {
if (selectedCount === 0) {
return null;
}
const handlePlay = () => {
onPlay?.(selectedTrackIds);
};
const handleDelete = () => {
onDelete?.(selectedTrackIds);
};
const handleLike = () => {
onLike?.(selectedTrackIds);
};
const handleDownload = () => {
onDownload?.(selectedTrackIds);
};
const handleMore = () => {
onMore?.(selectedTrackIds);
};
const actionButtonClass = [
'p-2 rounded-md',
'transition-[background-color,transform] duration-[var(--duration-normal)]',
'hover:bg-primary-foreground/15 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-foreground/40 focus-visible:ring-offset-2 focus-visible:ring-offset-primary',
'active:scale-95',
].join(' ');
return (
<div
className={cn(
'fixed bottom-0 left-0 right-0 z-50',
'bg-primary text-primary-foreground',
'px-4 py-4 shadow-lg border-t border-primary-foreground/10 rounded-t-[var(--radius-xl)]',
'flex items-center justify-between gap-4',
'transition-[opacity,transform,box-shadow] duration-[var(--duration-normal)]',
className,
)}
role="toolbar"
aria-label={`Actions pour ${selectedCount} piste${selectedCount > 1 ? 's' : ''} sélectionnée${selectedCount > 1 ? 's' : ''}`}
>
<div className="flex items-center gap-4">
<span className="text-sm font-medium tracking-tight text-primary-foreground/95 tabular-nums">
{selectedCount} piste{selectedCount > 1 ? 's' : ''} sélectionnée
{selectedCount > 1 ? 's' : ''}
</span>
<div className="flex items-center gap-2">
{onPlay && (
<button
type="button"
onClick={handlePlay}
className={actionButtonClass}
aria-label={`Lire ${selectedCount} piste${selectedCount > 1 ? 's' : ''}`}
>
<Play className="h-5 w-5" aria-hidden="true" />
<span className="sr-only">Lire</span>
</button>
)}
{onLike && (
<button
type="button"
onClick={handleLike}
className={actionButtonClass}
aria-label={`Ajouter ${selectedCount} piste${selectedCount > 1 ? 's' : ''} aux favoris`}
>
<Heart className="h-5 w-5" aria-hidden="true" />
<span className="sr-only">Ajouter aux favoris</span>
</button>
)}
{onDownload && (
<button
type="button"
onClick={handleDownload}
className={actionButtonClass}
aria-label={`Télécharger ${selectedCount} piste${selectedCount > 1 ? 's' : ''}`}
>
<Download className="h-5 w-5" aria-hidden="true" />
<span className="sr-only">Télécharger</span>
</button>
)}
{onDelete && (
<button
type="button"
onClick={handleDelete}
className={cn(
actionButtonClass,
'hover:bg-destructive/30 focus-visible:ring-destructive/50',
)}
aria-label={`Supprimer ${selectedCount} piste${selectedCount > 1 ? 's' : ''}`}
>
<Trash2 className="h-5 w-5" aria-hidden="true" />
<span className="sr-only">Supprimer</span>
</button>
)}
{onMore && (
<button
type="button"
onClick={handleMore}
className={actionButtonClass}
aria-label={`Plus d'options pour ${selectedCount} piste${selectedCount > 1 ? 's' : ''}`}
>
<MoreVertical className="h-5 w-5" aria-hidden="true" />
<span className="sr-only">Plus d'options</span>
</button>
)}
</div>
</div>
{onClearSelection && (
<button
type="button"
onClick={onClearSelection}
className={actionButtonClass}
aria-label="Désélectionner toutes les pistes"
>
<X className="h-5 w-5" aria-hidden="true" />
<span className="sr-only">Fermer</span>
</button>
)}
</div>
);
}
export default TrackListSelectionActions;