veza/apps/web/src/features/player/components/RepeatShuffleButtons.tsx

151 lines
4.5 KiB
TypeScript

/**
* Composant RepeatShuffleButtons
* Boutons pour contrôler le mode repeat et shuffle
*/
import { Repeat, Shuffle } from 'lucide-react';
import { cn } from '@/lib/utils';
export interface RepeatShuffleButtonsProps {
repeat: 'off' | 'track' | 'playlist';
shuffle: boolean;
onRepeatChange: (repeat: 'off' | 'track' | 'playlist') => void;
onShuffleToggle: () => void;
className?: string;
disabled?: boolean;
size?: 'sm' | 'md' | 'lg';
variant?: 'default' | 'ghost' | 'outline';
}
export function RepeatShuffleButtons({
repeat,
shuffle,
onRepeatChange,
onShuffleToggle,
className,
disabled = false,
size = 'md',
variant = 'ghost',
}: RepeatShuffleButtonsProps) {
const sizeClasses = {
sm: 'h-8 w-8',
md: 'h-10 w-10',
lg: 'h-12 w-12',
};
const iconSizes = {
sm: 'h-4 w-4',
md: 'h-5 w-5',
lg: 'h-6 w-6',
};
const variantClasses = {
default:
'bg-kodo-cyan text-white hover:bg-kodo-cyan focus:ring-blue-500 dark:bg-kodo-cyan dark:hover:bg-kodo-cyan',
ghost:
'bg-transparent text-kodo-text-main hover:bg-kodo-void focus:ring-gray-500 dark:text-kodo-text-main dark:hover:bg-kodo-graphite',
outline:
'border border-kodo-steel bg-white text-kodo-text-main hover:bg-kodo-void focus:ring-gray-500 dark:border-kodo-steel dark:bg-kodo-graphite dark:text-kodo-text-main dark:hover:bg-kodo-steel',
};
const handleRepeatClick = () => {
if (disabled) return;
// Cycle: off -> track -> playlist -> off
if (repeat === 'off') {
onRepeatChange('track');
} else if (repeat === 'track') {
onRepeatChange('playlist');
} else {
onRepeatChange('off');
}
};
const getRepeatLabel = () => {
switch (repeat) {
case 'track':
return 'Répéter la piste';
case 'playlist':
return 'Répéter la playlist';
default:
return 'Répéter désactivé';
}
};
const getRepeatAriaLabel = () => {
switch (repeat) {
case 'track':
return 'Répéter la piste (actif)';
case 'playlist':
return 'Répéter la playlist (actif)';
default:
return 'Répéter désactivé';
}
};
return (
<div className={cn('flex items-center gap-2', className)}>
{/* Repeat Button */}
<button
type="button"
onClick={handleRepeatClick}
disabled={disabled}
className={cn(
'rounded-full flex items-center justify-center transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 relative',
sizeClasses[size],
variantClasses[variant],
repeat !== 'off' &&
'bg-kodo-cyan text-white hover:bg-kodo-cyan dark:bg-kodo-cyan dark:hover:bg-kodo-cyan',
disabled && 'opacity-50 cursor-not-allowed',
)}
aria-label={getRepeatAriaLabel()}
aria-pressed={repeat !== 'off'}
aria-disabled={disabled}
title={getRepeatLabel()}
>
<Repeat
className={cn(iconSizes[size], repeat === 'track' && 'fill-current')}
aria-hidden="true"
/>
{repeat === 'playlist' && (
<span
className="absolute bottom-0 right-0 text-[8px] font-bold leading-none bg-kodo-cyan dark:bg-kodo-cyan rounded-full w-3 h-3 flex items-center justify-center"
aria-hidden="true"
>
1
</span>
)}
<span className="sr-only">{getRepeatLabel()}</span>
</button>
{/* Shuffle Button */}
<button
type="button"
onClick={onShuffleToggle}
disabled={disabled}
className={cn(
'rounded-full flex items-center justify-center transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2',
sizeClasses[size],
variantClasses[variant],
shuffle &&
'bg-kodo-cyan text-white hover:bg-kodo-cyan dark:bg-kodo-cyan dark:hover:bg-kodo-cyan',
disabled && 'opacity-50 cursor-not-allowed',
)}
aria-label={shuffle ? 'Mélanger activé' : 'Mélanger désactivé'}
aria-pressed={shuffle}
aria-disabled={disabled}
title={shuffle ? 'Mélanger activé' : 'Mélanger désactivé'}
>
<Shuffle
className={cn(iconSizes[size], shuffle && 'fill-current')}
aria-hidden="true"
/>
<span className="sr-only">
{shuffle ? 'Mélanger activé' : 'Mélanger désactivé'}
</span>
</button>
</div>
);
}
export default RepeatShuffleButtons;