59 lines
1.8 KiB
React
59 lines
1.8 KiB
React
|
|
/**
|
||
|
|
* 사진/비디오 미리보기 모달 컴포넌트
|
||
|
|
*/
|
||
|
|
import { memo } from 'react';
|
||
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
||
|
|
import { X } from 'lucide-react';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param {Object} props
|
||
|
|
* @param {Object|null} props.photo - 미리보기할 사진/비디오 객체
|
||
|
|
* @param {Function} props.onClose - 닫기 핸들러
|
||
|
|
*/
|
||
|
|
const PhotoPreviewModal = memo(function PhotoPreviewModal({ photo, onClose }) {
|
||
|
|
return (
|
||
|
|
<AnimatePresence>
|
||
|
|
{photo && (
|
||
|
|
<motion.div
|
||
|
|
initial={{ opacity: 0 }}
|
||
|
|
animate={{ opacity: 1 }}
|
||
|
|
exit={{ opacity: 0 }}
|
||
|
|
className="fixed inset-0 z-50 flex items-center justify-center bg-black/90"
|
||
|
|
onClick={onClose}
|
||
|
|
>
|
||
|
|
<button
|
||
|
|
onClick={onClose}
|
||
|
|
className="absolute top-4 right-4 p-2 text-white/70 hover:text-white transition-colors"
|
||
|
|
>
|
||
|
|
<X size={24} />
|
||
|
|
</button>
|
||
|
|
{photo.isVideo ? (
|
||
|
|
<motion.video
|
||
|
|
initial={{ scale: 0.9 }}
|
||
|
|
animate={{ scale: 1 }}
|
||
|
|
exit={{ scale: 0.9 }}
|
||
|
|
src={photo.preview || photo.url}
|
||
|
|
className="max-w-[90vw] max-h-[90vh] object-contain"
|
||
|
|
onClick={(e) => e.stopPropagation()}
|
||
|
|
controls
|
||
|
|
autoPlay
|
||
|
|
/>
|
||
|
|
) : (
|
||
|
|
<motion.img
|
||
|
|
initial={{ scale: 0.9 }}
|
||
|
|
animate={{ scale: 1 }}
|
||
|
|
exit={{ scale: 0.9 }}
|
||
|
|
src={photo.preview || photo.url}
|
||
|
|
alt={photo.filename}
|
||
|
|
className="max-w-[90vw] max-h-[90vh] object-contain"
|
||
|
|
onClick={(e) => e.stopPropagation()}
|
||
|
|
/>
|
||
|
|
)}
|
||
|
|
</motion.div>
|
||
|
|
)}
|
||
|
|
</AnimatePresence>
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
export default PhotoPreviewModal;
|