diff --git a/frontend/src/components/common/LightboxIndicator.jsx b/frontend/src/components/common/LightboxIndicator.jsx new file mode 100644 index 0000000..d317282 --- /dev/null +++ b/frontend/src/components/common/LightboxIndicator.jsx @@ -0,0 +1,42 @@ +import { memo } from 'react'; + +/** + * 라이트박스 인디케이터 컴포넌트 + * 이미지 갤러리에서 현재 위치를 표시하는 슬라이딩 점 인디케이터 + * CSS transition 사용으로 GPU 가속 + */ +const LightboxIndicator = memo(function LightboxIndicator({ count, currentIndex, goToIndex }) { + const translateX = -(currentIndex * 18) + 100 - 6; + + return ( +
+ {/* 양옆 페이드 그라데이션 */} +
+ {/* 슬라이딩 컨테이너 - CSS transition으로 GPU 가속 */} +
+ {Array.from({ length: count }).map((_, i) => ( +
+
+ ); +}); + +export default LightboxIndicator; diff --git a/frontend/src/pages/pc/public/Album.jsx b/frontend/src/pages/pc/public/Album.jsx index 9ac000f..e2ac260 100644 --- a/frontend/src/pages/pc/public/Album.jsx +++ b/frontend/src/pages/pc/public/Album.jsx @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'; import { motion } from 'framer-motion'; import { Calendar, Music } from 'lucide-react'; import { getAlbums } from '../../../api/public/albums'; +import { formatDate } from '../../../utils/date'; function Album() { const navigate = useNavigate(); @@ -21,13 +22,6 @@ function Album() { }); }, []); - // 날짜 포맷팅 - const formatDate = (dateStr) => { - if (!dateStr) return ''; - const date = new Date(dateStr); - return `${date.getFullYear()}.${String(date.getMonth() + 1).padStart(2, '0')}.${String(date.getDate()).padStart(2, '0')}`; - }; - // 타이틀곡 찾기 const getTitleTrack = (tracks) => { if (!tracks || tracks.length === 0) return ''; @@ -149,7 +143,7 @@ function Album() {

- {formatDate(album.release_date)} + {formatDate(album.release_date, 'YYYY.MM.DD')}
diff --git a/frontend/src/pages/pc/public/AlbumDetail.jsx b/frontend/src/pages/pc/public/AlbumDetail.jsx index 1acad0a..e884dd3 100644 --- a/frontend/src/pages/pc/public/AlbumDetail.jsx +++ b/frontend/src/pages/pc/public/AlbumDetail.jsx @@ -3,41 +3,9 @@ import { useParams, useNavigate } from 'react-router-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Calendar, Music2, Clock, X, ChevronLeft, ChevronRight, Download, MoreVertical, FileText } from 'lucide-react'; import { getAlbumByName } from '../../../api/public/albums'; +import { formatDate } from '../../../utils/date'; +import LightboxIndicator from '../../../components/common/LightboxIndicator'; -// 인디케이터 컴포넌트 - CSS transition 사용으로 JS 블로킹에 영향받지 않음 -const LightboxIndicator = memo(function LightboxIndicator({ count, currentIndex, setLightbox }) { - const translateX = -(currentIndex * 18) + 100 - 6; - - return ( -
- {/* 양옆 페이드 그라데이션 */} -
- {/* 슬라이딩 컨테이너 - CSS transition으로 GPU 가속 */} -
- {Array.from({ length: count }).map((_, i) => ( -
-
- ); -}); function AlbumDetail() { const { name } = useParams(); const navigate = useNavigate(); @@ -171,13 +139,6 @@ function AlbumDetail() { // URL 헬퍼 함수는 더 이상 필요 없음 - API에서 직접 제공 - // 날짜 포맷팅 - const formatDate = (dateStr) => { - if (!dateStr) return ''; - const date = new Date(dateStr); - return `${date.getFullYear()}.${String(date.getMonth() + 1).padStart(2, '0')}.${String(date.getDate()).padStart(2, '0')}`; - }; - // 총 재생 시간 계산 const getTotalDuration = () => { if (!album?.tracks) return ''; @@ -317,7 +278,7 @@ function AlbumDetail() {
- {formatDate(album.release_date)} + {formatDate(album.release_date, 'YYYY.MM.DD')}
@@ -568,12 +529,12 @@ function AlbumDetail() { )} - {/* 인디케이터 - memo 컴포넌트로 분리 */} + {/* 인디케이터 - 공통 컴포넌트 사용 */} {lightbox.images.length > 1 && ( setLightbox(prev => ({ ...prev, index: i }))} /> )}
diff --git a/frontend/src/pages/pc/public/AlbumGallery.jsx b/frontend/src/pages/pc/public/AlbumGallery.jsx index 41df695..f101f8f 100644 --- a/frontend/src/pages/pc/public/AlbumGallery.jsx +++ b/frontend/src/pages/pc/public/AlbumGallery.jsx @@ -5,41 +5,7 @@ import { X, ChevronLeft, ChevronRight, Download } from 'lucide-react'; import { RowsPhotoAlbum } from 'react-photo-album'; import 'react-photo-album/rows.css'; import { getAlbumByName } from '../../../api/public/albums'; - -// 인디케이터 컴포넌트 - CSS transition 사용으로 JS 블로킹에 영향받지 않음 -const LightboxIndicator = memo(function LightboxIndicator({ count, currentIndex, setLightbox }) { - const translateX = -(currentIndex * 18) + 100 - 6; - - return ( -
- {/* 양옆 페이드 그라데이션 */} -
- {/* 슬라이딩 컨테이너 - CSS transition으로 GPU 가속 */} -
- {Array.from({ length: count }).map((_, i) => ( -
-
- ); -}); +import LightboxIndicator from '../../../components/common/LightboxIndicator'; // CSS로 호버 효과 추가 + overflow 문제 수정 + 로드 애니메이션 const galleryStyles = ` @@ -392,11 +358,11 @@ function AlbumGallery() { )} - {/* 하단 점 인디케이터 - memo 컴포넌트로 분리 */} + {/* 하단 점 인디케이터 - 공통 컴포넌트 사용 */} setLightbox(prev => ({ ...prev, index: i }))} />
diff --git a/frontend/src/pages/pc/public/Members.jsx b/frontend/src/pages/pc/public/Members.jsx index 80bb09c..e529ab3 100644 --- a/frontend/src/pages/pc/public/Members.jsx +++ b/frontend/src/pages/pc/public/Members.jsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { Instagram, Calendar } from 'lucide-react'; import { getMembers } from '../../../api/public/members'; +import { formatDate } from '../../../utils/date'; function Members() { const [members, setMembers] = useState([]); @@ -19,13 +20,6 @@ function Members() { }); }, []); - // 날짜 포맷팅 함수 - const formatDate = (dateStr) => { - if (!dateStr) return ''; - const date = new Date(dateStr); - return `${date.getFullYear()}.${String(date.getMonth() + 1).padStart(2, '0')}.${String(date.getDate()).padStart(2, '0')}`; - }; - if (loading) { return (
@@ -83,7 +77,7 @@ function Members() {
- {formatDate(member.birth_date)} + {formatDate(member.birth_date, 'YYYY.MM.DD')}
{/* 인스타그램 링크 */} @@ -142,7 +136,7 @@ function Members() {
- {formatDate(member.birth_date)} + {formatDate(member.birth_date, 'YYYY.MM.DD')}