151 lines
4.5 KiB
TypeScript
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;
|