- PendingFileItem.jsx 추출 (업로드 대기 파일 아이템) - BulkEditPanel.jsx 추출 (일괄 편집 도구 + parseRange 함수) - PhotoGrid.jsx 추출 (컨셉 포토/티저 그리드) - PhotoPreviewModal.jsx 추출 (이미지/비디오 미리보기) - AlbumPhotos.jsx: 1536줄 → 1033줄 (503줄 감소) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
58 lines
1.8 KiB
JavaScript
58 lines
1.8 KiB
JavaScript
/**
|
|
* 사진/비디오 미리보기 모달 컴포넌트
|
|
*/
|
|
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;
|