121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
|
|
|
||
|
|
import React from 'react';
|
||
|
|
import { X, ChevronLeft, ChevronRight, Download } from 'lucide-react';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ImageViewerModalProps - Propriétés du composant ImageViewerModal
|
||
|
|
*
|
||
|
|
* @interface ImageViewerModalProps
|
||
|
|
*/
|
||
|
|
interface ImageViewerModalProps {
|
||
|
|
/**
|
||
|
|
* URL de l'image à afficher
|
||
|
|
*/
|
||
|
|
src: string;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Texte alternatif de l'image
|
||
|
|
*/
|
||
|
|
alt?: string;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fonction appelée pour fermer le visualiseur
|
||
|
|
*/
|
||
|
|
onClose: () => void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fonction appelée pour passer à l'image suivante
|
||
|
|
*/
|
||
|
|
onNext?: () => void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fonction appelée pour passer à l'image précédente
|
||
|
|
*/
|
||
|
|
onPrev?: () => void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Si `true`, affiche le bouton suivant
|
||
|
|
*/
|
||
|
|
hasNext?: boolean;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Si `true`, affiche le bouton précédent
|
||
|
|
*/
|
||
|
|
hasPrev?: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ImageViewerModal - Composant de visualisation d'image en plein écran
|
||
|
|
*
|
||
|
|
* Composant modal pour afficher une image en plein écran avec :
|
||
|
|
* - Navigation entre images (précédent/suivant)
|
||
|
|
* - Téléchargement de l'image
|
||
|
|
* - Fermeture avec bouton ou Escape
|
||
|
|
* - Fond sombre avec backdrop blur
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```tsx
|
||
|
|
* // Visualiseur simple
|
||
|
|
* <ImageViewerModal
|
||
|
|
* src={imageUrl}
|
||
|
|
* alt="Description"
|
||
|
|
* onClose={() => setShowViewer(false)}
|
||
|
|
* />
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* @example
|
||
|
|
* ```tsx
|
||
|
|
* // Avec navigation
|
||
|
|
* <ImageViewerModal
|
||
|
|
* src={images[currentIndex]}
|
||
|
|
* alt={`Image ${currentIndex + 1}`}
|
||
|
|
* onClose={() => setShowViewer(false)}
|
||
|
|
* onNext={() => setCurrentIndex(i => i + 1)}
|
||
|
|
* onPrev={() => setCurrentIndex(i => i - 1)}
|
||
|
|
* hasNext={currentIndex < images.length - 1}
|
||
|
|
* hasPrev={currentIndex > 0}
|
||
|
|
* />
|
||
|
|
* ```
|
||
|
|
*
|
||
|
|
* @component
|
||
|
|
* @param {ImageViewerModalProps} props - Propriétés du composant
|
||
|
|
* @returns {JSX.Element} Modal plein écran avec image et contrôles
|
||
|
|
*/
|
||
|
|
|
||
|
|
export const ImageViewerModal: React.FC<ImageViewerModalProps> = ({ src, alt, onClose, onNext, onPrev, hasNext, hasPrev }) => {
|
||
|
|
return (
|
||
|
|
<div className="fixed inset-0 z-[200] bg-black/95 backdrop-blur-xl flex items-center justify-center animate-fadeIn">
|
||
|
|
|
||
|
|
{/* Toolbar */}
|
||
|
|
<div className="absolute top-0 left-0 right-0 p-4 flex justify-between items-center z-10 bg-gradient-to-b from-black/50 to-transparent">
|
||
|
|
<span className="text-white/50 text-sm font-mono">{alt || 'Image Preview'}</span>
|
||
|
|
<div className="flex gap-4">
|
||
|
|
<a href={src} download className="p-2 bg-white/10 rounded-full hover:bg-white/20 text-white transition-colors" title="Download">
|
||
|
|
<Download className="w-5 h-5" />
|
||
|
|
</a>
|
||
|
|
<button onClick={onClose} className="p-2 bg-white/10 rounded-full hover:bg-white/20 text-white transition-colors" title="Close">
|
||
|
|
<X className="w-5 h-5" />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Navigation */}
|
||
|
|
{hasPrev && (
|
||
|
|
<button onClick={onPrev} className="absolute left-4 p-3 bg-white/10 rounded-full hover:bg-white/20 text-white transition-colors z-10">
|
||
|
|
<ChevronLeft className="w-8 h-8" />
|
||
|
|
</button>
|
||
|
|
)}
|
||
|
|
{hasNext && (
|
||
|
|
<button onClick={onNext} className="absolute right-4 p-3 bg-white/10 rounded-full hover:bg-white/20 text-white transition-colors z-10">
|
||
|
|
<ChevronRight className="w-8 h-8" />
|
||
|
|
</button>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Image */}
|
||
|
|
<div className="w-full h-full p-4 md:p-10 flex items-center justify-center">
|
||
|
|
<img src={src} alt={alt} className="max-w-full max-h-full object-contain shadow-2xl rounded-lg" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|