- 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>
163 lines
5 KiB
TypeScript
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;
|