feat: Add reusable video modal component with Alist-style UI

This commit is contained in:
2026-01-04 15:36:52 +09:00
parent 4c20f96cef
commit 150a3a9fb0
19 changed files with 859 additions and 215 deletions

View File

@@ -0,0 +1,61 @@
<!-- Video Modal Component for Anime Downloader -->
<!-- Usage: include 'anime_downloader/components/video_modal.html' in your template -->
<!-- Video.js CDN -->
<link href="https://vjs.zencdn.net/8.10.0/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script>
<!-- Video Player Modal -->
<div class="modal fade" id="videoModal" tabindex="-1" role="dialog" aria-labelledby="videoModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content" style="background: #0f172a; border-radius: 12px;">
<div class="modal-header" style="border-bottom: 1px solid rgba(255,255,255,0.1);">
<h5 class="modal-title" id="videoModalLabel" style="color: #f1f5f9;">비디오 플레이어</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="color: #f1f5f9;">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" style="padding: 0;">
<div class="video-container" style="position: relative; overflow: hidden; background: #000;">
<video id="video-player" class="video-js vjs-big-play-centered vjs-theme-fantasy" controls preload="auto" playsinline webkit-playsinline style="width: 100%; height: auto; max-height: 80vh;">
<p class="vjs-no-js">JavaScript가 필요합니다.</p>
</video>
<!-- 화면 꽉 채우기 토글 버튼 (모바일용) -->
<button id="btn-video-zoom" class="video-zoom-btn" title="화면 비율 조절">
<i class="fa fa-expand"></i>
</button>
</div>
<!-- 플레이리스트 컨트롤 UI (Alist 스타일) -->
<div class="playlist-controls">
<!-- 에피소드 선택 드롭다운 + 자동 다음 토글 -->
<div class="episode-selector-row">
<div class="episode-dropdown-wrapper">
<select id="episode-dropdown" class="episode-dropdown">
<!-- JavaScript에서 옵션 동적 생성 -->
</select>
<svg class="dropdown-arrow" viewBox="0 0 15 15" aria-hidden="true">
<path d="M4.93179 5.43179C4.75605 5.60753 4.75605 5.89245 4.93179 6.06819C5.10753 6.24392 5.39245 6.24392 5.56819 6.06819L7.49999 4.13638L9.43179 6.06819C9.60753 6.24392 9.89245 6.24392 10.0682 6.06819C10.2439 5.89245 10.2439 5.60753 10.0682 5.43179L7.81819 3.18179C7.73379 3.0974 7.61933 3.04999 7.49999 3.04999C7.38064 3.04999 7.26618 3.0974 7.18179 3.18179L4.93179 5.43179ZM10.0682 9.56819C10.2439 9.39245 10.2439 9.10753 10.0682 8.93179C9.89245 8.75606 9.60753 8.75606 9.43179 8.93179L7.49999 10.8636L5.56819 8.93179C5.39245 8.75606 5.10753 8.75606 4.93179 8.93179C4.75605 9.10753 4.75605 9.39245 4.93179 9.56819L7.18179 11.8182C7.35753 11.9939 7.64245 11.9939 7.81819 11.8182L10.0682 9.56819Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path>
</svg>
</div>
<label class="auto-next-toggle">
<input type="checkbox" id="auto-next-checkbox" checked>
<span class="toggle-label">자동 다음</span>
<span class="toggle-switch"></span>
</label>
</div>
<!-- 외부 플레이어 버튼 -->
<div class="external-players">
<div class="external-players-grid" id="external-player-buttons">
<!-- 버튼들은 JavaScript에서 동적 생성 -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="{{ url_for('.static', filename='css/video_modal.css') }}"/>
<script src="{{ url_for('.static', filename='js/video_modal.js') }}"></script>