diff --git a/app/static/public/css/video.css b/app/static/public/css/video.css index 5dda91c..1dc1784 100644 --- a/app/static/public/css/video.css +++ b/app/static/public/css/video.css @@ -661,6 +661,87 @@ body { background: #fafafa; } +#cacheVideoModal.modal-overlay { + position: fixed; + inset: 0; + z-index: 80; + background: transparent; +} + +#cacheVideoModal.hidden { + display: none; +} + +#cacheVideoModal .modal-content { + position: fixed; + width: min(560px, calc(100vw - 24px)); + max-height: min(72vh, 560px); + border-radius: 12px; + border: 1px solid var(--video-outline); + background: var(--video-surface); + box-shadow: 0 14px 40px rgba(0, 0, 0, 0.18); + display: flex; + flex-direction: column; + overflow: hidden; +} + +#cacheVideoModal .modal-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + padding: 10px 12px; + border-bottom: 1px solid var(--video-outline); +} + +#cacheVideoModal .modal-title { + font-size: 13px; + font-weight: 600; + color: var(--accents-7); +} + +#cacheVideoModal .modal-close { + width: 28px; + height: 28px; + border-radius: 8px; + border: 1px solid var(--video-outline); + display: inline-flex; + align-items: center; + justify-content: center; +} + +#cacheVideoModal .modal-close:hover { + background: var(--video-muted); +} + +html[data-theme='dark'] #cacheVideoModal .modal-content { + background: #131a24; + border-color: #2b3440; + box-shadow: 0 16px 44px rgba(0, 0, 0, 0.45); +} + +html[data-theme='dark'] #cacheVideoModal .modal-title { + color: #e6edf3; +} + +html[data-theme='dark'] #cacheVideoModal .modal-close { + border-color: #2b3440; + color: #e6edf3; +} + +html[data-theme='dark'] #cacheVideoModal .modal-close:hover { + background: #1b2432; +} + +html[data-theme='dark'] .cache-video-list { + background: #131a24; + border-color: #2b3440; +} + +html[data-theme='dark'] .cache-video-item { + border-bottom-color: #2b3440; +} + .cache-video-item { display: flex; align-items: center; diff --git a/app/static/public/js/video.js b/app/static/public/js/video.js index a4fd262..fcbe8c8 100644 --- a/app/static/public/js/video.js +++ b/app/static/public/js/video.js @@ -91,6 +91,7 @@ let mergeCutMsA = 0; let mergeCutMsB = 0; let cacheModalPickMode = 'edit'; + let cacheModalAnchorEl = null; function toast(message, type) { if (typeof showToast === 'function') { @@ -1093,16 +1094,44 @@ if (editBody) editBody.classList.remove('hidden'); } - function openCacheVideoModal() { + function positionCacheVideoModal() { if (!cacheVideoModal) return; + const content = cacheVideoModal.querySelector('.modal-content'); + if (!(content instanceof HTMLElement)) return; + const anchor = cacheModalAnchorEl instanceof HTMLElement ? cacheModalAnchorEl : null; + if (!anchor) return; + const rect = anchor.getBoundingClientRect(); + const margin = 8; + const vw = window.innerWidth || document.documentElement.clientWidth || 0; + const vh = window.innerHeight || document.documentElement.clientHeight || 0; + const width = Math.min(560, Math.max(280, vw - 24)); + let left = rect.left; + if (left + width > vw - 12) { + left = vw - 12 - width; + } + if (left < 12) left = 12; + let top = rect.bottom + margin; + const maxTop = vh - 120; + if (top > maxTop) { + top = Math.max(12, rect.top - margin - 420); + } + content.style.left = `${Math.round(left)}px`; + content.style.top = `${Math.round(top)}px`; + } + + function openCacheVideoModal(anchorEl) { + if (!cacheVideoModal) return; + cacheModalAnchorEl = anchorEl instanceof HTMLElement ? anchorEl : null; cacheVideoModal.classList.remove('hidden'); cacheVideoModal.classList.add('is-open'); + positionCacheVideoModal(); } function closeCacheVideoModal() { if (!cacheVideoModal) return; cacheVideoModal.classList.remove('is-open'); cacheVideoModal.classList.add('hidden'); + cacheModalAnchorEl = null; } function formatBytes(bytes) { @@ -2026,7 +2055,7 @@ pickCachedVideoBtn.addEventListener('click', async () => { try { cacheModalPickMode = 'edit'; - openCacheVideoModal(); + openCacheVideoModal(pickCachedVideoBtn); if (cacheVideoList) { cacheVideoList.innerHTML = '