Add video viewer modal for gallery videos
All checks were successful
Build and Push Frontend Docker Image / build (push) Successful in 30s
All checks were successful
Build and Push Frontend Docker Image / build (push) Successful in 30s
- Click on video thumbnail to open in large viewer - Video plays on hover, pauses when mouse leaves - Close viewer by clicking X or clicking outside video Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -695,6 +695,52 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
/* Video Viewer */
|
||||
.video-viewer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.video-viewer-close {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.video-viewer-close:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.video-viewer-player {
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.gallery-item-media video {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Privacy Mode */
|
||||
.privacy-toggle.active {
|
||||
background: var(--primary);
|
||||
|
||||
@@ -182,6 +182,12 @@
|
||||
<div id="modal-overlay" class="modal-overlay hidden">
|
||||
<div id="modal-content" class="modal-content"></div>
|
||||
</div>
|
||||
|
||||
<!-- Video Viewer -->
|
||||
<div id="video-viewer" class="video-viewer hidden">
|
||||
<button id="video-viewer-close" class="video-viewer-close">×</button>
|
||||
<video id="video-viewer-player" class="video-viewer-player" controls loop></video>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/app.js"></script>
|
||||
|
||||
@@ -427,7 +427,7 @@ function renderGallery(container, items) {
|
||||
<div class="gallery-item">
|
||||
<div class="gallery-item-media">
|
||||
${item.status === 'completed'
|
||||
? `<video src="/api/content/${item.id}/stream" muted loop onmouseenter="this.play()" onmouseleave="this.pause()"></video>`
|
||||
? `<video src="/api/content/${item.id}/stream" muted loop data-content-id="${item.id}"></video>`
|
||||
: '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:var(--gray-500)">' + item.status + '</div>'
|
||||
}
|
||||
<span class="gallery-item-status ${item.status}">${item.status}</span>
|
||||
@@ -445,6 +445,19 @@ function renderGallery(container, items) {
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
// Video hover play/pause and click to view
|
||||
container.querySelectorAll('.gallery-item-media video').forEach(video => {
|
||||
video.addEventListener('mouseenter', () => video.play());
|
||||
video.addEventListener('mouseleave', () => {
|
||||
video.pause();
|
||||
video.currentTime = 0;
|
||||
});
|
||||
video.addEventListener('click', () => {
|
||||
const contentId = video.dataset.contentId;
|
||||
openVideoViewer(`/api/content/${contentId}/stream`);
|
||||
});
|
||||
});
|
||||
|
||||
container.querySelectorAll('.delete-content-btn').forEach(btn => {
|
||||
btn.addEventListener('click', async function() {
|
||||
const contentId = parseInt(this.dataset.contentId, 10);
|
||||
@@ -673,6 +686,28 @@ document.getElementById('modal-overlay').addEventListener('click', (e) => {
|
||||
if (e.target === e.currentTarget) hideModal();
|
||||
});
|
||||
|
||||
// Video Viewer
|
||||
const videoViewer = document.getElementById('video-viewer');
|
||||
const videoViewerPlayer = document.getElementById('video-viewer-player');
|
||||
const videoViewerClose = document.getElementById('video-viewer-close');
|
||||
|
||||
function openVideoViewer(src) {
|
||||
videoViewerPlayer.src = src;
|
||||
videoViewer.classList.remove('hidden');
|
||||
videoViewerPlayer.play();
|
||||
}
|
||||
|
||||
function closeVideoViewer() {
|
||||
videoViewerPlayer.pause();
|
||||
videoViewerPlayer.src = '';
|
||||
videoViewer.classList.add('hidden');
|
||||
}
|
||||
|
||||
videoViewerClose.addEventListener('click', closeVideoViewer);
|
||||
videoViewer.addEventListener('click', (e) => {
|
||||
if (e.target === videoViewer) closeVideoViewer();
|
||||
});
|
||||
|
||||
// Pagination
|
||||
function renderPagination(container, pagination, loadFn) {
|
||||
const { page, totalPages } = pagination;
|
||||
|
||||
Reference in New Issue
Block a user