summaryrefslogtreecommitdiff
path: root/components/common/video-background.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/common/video-background.tsx')
-rw-r--r--components/common/video-background.tsx181
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>
- );
-}
-