diff options
Diffstat (limited to 'components/common/video-background.tsx')
| -rw-r--r-- | components/common/video-background.tsx | 181 |
1 files changed, 0 insertions, 181 deletions
diff --git a/components/common/video-background.tsx b/components/common/video-background.tsx deleted file mode 100644 index 96b9b4ac..00000000 --- a/components/common/video-background.tsx +++ /dev/null @@ -1,181 +0,0 @@ -'use client'; - -import { useState, useEffect, useRef } from 'react'; -import { cn } from '@/lib/utils'; -import { registerServiceWorker, getCacheStatus } from '@/lib/service-worker/register'; - -interface VideoBackgroundProps { - videos: string[]; - className?: string; - overlayClassName?: string; - showIndicators?: boolean; - showCacheStatus?: boolean; - onVideoChange?: (index: number) => void; -} - -/** - * VideoBackground 컴포넌트 - * - * 특징: - * - 영상 프리로드로 부드러운 전환 - * - 자동 재생 및 순환 - * - Service Worker를 통한 영구 캐싱 - * - HTTP 캐시 헤더 지원 - * - 인디케이터 지원 - */ -export function VideoBackground({ - videos, - className, - overlayClassName, - showIndicators = true, - showCacheStatus = false, - onVideoChange, -}: VideoBackgroundProps) { - const [currentVideoIndex, setCurrentVideoIndex] = useState(0); - const [isVideoLoaded, setIsVideoLoaded] = useState(false); - const [cachedVideos, setCachedVideos] = useState(0); - const videoRef = useRef<HTMLVideoElement>(null); - const preloadedVideos = useRef<HTMLVideoElement[]>([]); - - // Service Worker 등록 - useEffect(() => { - const setupServiceWorker = async () => { - const registration = await registerServiceWorker(); - - if (registration) { - console.log('✅ Service Worker registered - Videos will be cached'); - - // 캐시 상태 확인 - setTimeout(async () => { - const status = await getCacheStatus(); - if (status) { - setCachedVideos(status.cached); - console.log(`📦 Cached videos: ${status.cached}/${status.total}`); - } - }, 2000); - } - }; - - setupServiceWorker(); - }, []); - - // 초기 랜덤 비디오 선택 - useEffect(() => { - const randomIndex = Math.floor(Math.random() * videos.length); - setCurrentVideoIndex(randomIndex); - }, [videos.length]); - - // 모든 비디오 프리로드 - useEffect(() => { - // 이미 프리로드된 경우 스킵 - if (preloadedVideos.current.length > 0) return; - - const preloadVideos = async () => { - const loadedVideos: HTMLVideoElement[] = []; - - for (let i = 0; i < videos.length; i++) { - const video = document.createElement('video'); - video.preload = 'auto'; - video.muted = true; - video.playsInline = true; - video.src = videos[i]; - - // 메타데이터 로드 대기 - await new Promise<void>((resolve) => { - video.addEventListener('loadedmetadata', () => resolve(), { once: true }); - // 타임아웃 설정 (10초) - setTimeout(() => resolve(), 10000); - }); - - loadedVideos.push(video); - } - - preloadedVideos.current = loadedVideos; - setIsVideoLoaded(true); - }; - - preloadVideos(); - - // 컴포넌트 언마운트 시 비디오 리소스 정리 - return () => { - preloadedVideos.current.forEach((video) => { - video.src = ''; - video.load(); - }); - preloadedVideos.current = []; - }; - }, [videos]); - - // 비디오 변경 시 콜백 호출 - useEffect(() => { - if (onVideoChange) { - onVideoChange(currentVideoIndex); - } - }, [currentVideoIndex, onVideoChange]); - - // 비디오 종료 시 다음 비디오로 전환 - const handleVideoEnd = () => { - setCurrentVideoIndex((prevIndex) => (prevIndex + 1) % videos.length); - }; - - // 인디케이터 클릭 핸들러 - const handleIndicatorClick = (index: number) => { - setCurrentVideoIndex(index); - // 비디오 즉시 재생 - if (videoRef.current) { - videoRef.current.currentTime = 0; - videoRef.current.play(); - } - }; - - return ( - <div className={cn('absolute inset-0 overflow-hidden', className)}> - {/* 비디오 배경 */} - <video - ref={videoRef} - key={currentVideoIndex} - autoPlay - muted - playsInline - onEnded={handleVideoEnd} - className="absolute inset-0 w-full h-full object-cover" - > - <source src={videos[currentVideoIndex]} type="video/mp4" /> - </video> - - {/* 오버레이 */} - <div className={cn('absolute inset-0 bg-black/40', overlayClassName)}></div> - - {/* 캐시 상태 표시 (개발용) */} - {showCacheStatus && cachedVideos > 0 && ( - <div className="absolute top-4 right-4 z-10 bg-black/70 text-white text-xs px-3 py-2 rounded-lg backdrop-blur-sm"> - <div className="flex items-center space-x-2"> - <span> - Cached: {cachedVideos}/{videos.length} - </span> - </div> - </div> - )} - - {/* 비디오 인디케이터 */} - {showIndicators && isVideoLoaded && ( - <div className="absolute bottom-8 left-1/2 transform -translate-x-1/2 z-10 flex justify-center space-x-2"> - {videos.map((_, index) => ( - <button - key={index} - onClick={() => handleIndicatorClick(index)} - className={cn( - 'h-2 rounded-full transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-white/50', - index === currentVideoIndex - ? 'bg-white w-8' - : 'bg-white/50 hover:bg-white/75 w-2' - )} - aria-label={`비디오 ${index + 1}로 이동`} - /> - ))} - </div> - )} - </div> - ); -} - |
