- utils/youtube.js: YouTube URL 파싱 유틸리티 생성 - getYoutubeVideoId, getYoutubeThumbnail, getYoutubeEmbedUrl - utils/format.js: parseCredits, calculateTotalDuration 함수 추가 - hooks/useLightbox.js: 라이트박스 상태 관리 훅 생성 - components/common/ErrorMessage.jsx: 에러 메시지 컴포넌트 생성 - components/common/Loading.jsx: size prop 추가 (sm, md, lg) - TrackDetail (PC/Mobile): 중복 함수 제거, 유틸리티 사용 - AlbumDetail (PC/Mobile): getTotalDuration -> calculateTotalDuration 유틸리티 사용 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
36 lines
1.1 KiB
JavaScript
36 lines
1.1 KiB
JavaScript
import { motion } from 'framer-motion';
|
|
import { AlertCircle, RefreshCw } from 'lucide-react';
|
|
|
|
/**
|
|
* 에러 메시지 컴포넌트
|
|
* @param {string} message - 에러 메시지
|
|
* @param {function} onRetry - 재시도 콜백 함수
|
|
* @param {string} className - 추가 CSS 클래스
|
|
*/
|
|
function ErrorMessage({
|
|
message = '데이터를 불러오는데 실패했습니다.',
|
|
onRetry,
|
|
className = '',
|
|
}) {
|
|
return (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className={`flex flex-col items-center justify-center py-12 px-4 ${className}`}
|
|
>
|
|
<AlertCircle size={48} className="text-red-400 mb-4" aria-hidden="true" />
|
|
<p className="text-gray-600 text-center mb-4">{message}</p>
|
|
{onRetry && (
|
|
<button
|
|
onClick={onRetry}
|
|
className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-dark transition-colors"
|
|
>
|
|
<RefreshCw size={16} aria-hidden="true" />
|
|
다시 시도
|
|
</button>
|
|
)}
|
|
</motion.div>
|
|
);
|
|
}
|
|
|
|
export default ErrorMessage;
|