Refine map lightbox UX and map click behavior across pages
This commit is contained in:
parent
7f45193a6f
commit
5408aba01a
4 changed files with 24 additions and 16 deletions
|
|
@ -255,7 +255,7 @@ $baseParams = ($rawKeyword !== '') ? ['q' => $rawKeyword] : [];
|
||||||
$map = pathinfo($name, PATHINFO_FILENAME).".png";
|
$map = pathinfo($name, PATHINFO_FILENAME).".png";
|
||||||
if(is_file($config['videos_dir']."/".$map)):
|
if(is_file($config['videos_dir']."/".$map)):
|
||||||
?>
|
?>
|
||||||
<img class="map-image" src="<?=h($config['public_videos']."/".rawurlencode($map))?>" alt="Map">
|
<a class="map-image-link" href="<?=h($config['public_videos']."/".rawurlencode($map))?>"><img class="map-image" src="<?=h($config['public_videos']."/".rawurlencode($map))?>" alt="Map"></a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="video-info">
|
<div class="video-info">
|
||||||
|
|
@ -305,6 +305,6 @@ $baseParams = ($rawKeyword !== '') ? ['q' => $rawKeyword] : [];
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script src="js/map_lightbox.js" defer></script>
|
<script src="js/map_lightbox.js?v=20260531c" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(() => {
|
(() => {
|
||||||
const SELECTOR = 'img.map-image';
|
const SELECTOR = 'a.map-image-link, img.map-image';
|
||||||
let lightbox = null;
|
let lightbox = null;
|
||||||
let lightboxImg = null;
|
let lightboxImg = null;
|
||||||
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
const hint = document.createElement('div');
|
const hint = document.createElement('div');
|
||||||
hint.className = 'map-lightbox__hint';
|
hint.className = 'map-lightbox__hint';
|
||||||
hint.textContent = 'Esc or click outside to close';
|
hint.textContent = 'Esc or click/tap outside to close';
|
||||||
|
|
||||||
lightbox.appendChild(closeBtn);
|
lightbox.appendChild(closeBtn);
|
||||||
lightbox.appendChild(lightboxImg);
|
lightbox.appendChild(lightboxImg);
|
||||||
|
|
@ -30,21 +30,18 @@
|
||||||
document.body.appendChild(lightbox);
|
document.body.appendChild(lightbox);
|
||||||
|
|
||||||
closeBtn.addEventListener('click', closeLightbox);
|
closeBtn.addEventListener('click', closeLightbox);
|
||||||
|
|
||||||
lightbox.addEventListener('click', (ev) => {
|
lightbox.addEventListener('click', (ev) => {
|
||||||
if (ev.target === lightbox) closeLightbox();
|
if (ev.target === lightbox) closeLightbox();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('keydown', (ev) => {
|
document.addEventListener('keydown', (ev) => {
|
||||||
if (ev.key === 'Escape' && lightbox.classList.contains('is-open')) {
|
if (ev.key === 'Escape' && lightbox.classList.contains('is-open')) closeLightbox();
|
||||||
closeLightbox();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return lightbox;
|
return lightbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openLightbox(src, alt) {
|
function openLightbox(src, alt) {
|
||||||
|
if (!src) return;
|
||||||
ensureLightbox();
|
ensureLightbox();
|
||||||
lightboxImg.src = src;
|
lightboxImg.src = src;
|
||||||
lightboxImg.alt = alt || 'Map preview';
|
lightboxImg.alt = alt || 'Map preview';
|
||||||
|
|
@ -59,17 +56,20 @@
|
||||||
lightbox.setAttribute('aria-hidden', 'true');
|
lightbox.setAttribute('aria-hidden', 'true');
|
||||||
document.body.classList.remove('map-lightbox-open');
|
document.body.classList.remove('map-lightbox-open');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!lightbox.classList.contains('is-open')) {
|
if (!lightbox.classList.contains('is-open')) lightboxImg.removeAttribute('src');
|
||||||
lightboxImg.removeAttribute('src');
|
|
||||||
}
|
|
||||||
}, 260);
|
}, 260);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('click', (ev) => {
|
document.addEventListener('click', (ev) => {
|
||||||
const target = ev.target instanceof Element ? ev.target.closest(SELECTOR) : null;
|
const target = ev.target instanceof Element ? ev.target.closest(SELECTOR) : null;
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
|
const img = target.matches('img.map-image') ? target : target.querySelector('img.map-image');
|
||||||
|
const src = img ? (img.currentSrc || img.src) : target.getAttribute('href');
|
||||||
|
if (!src) return;
|
||||||
|
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
openLightbox(target.currentSrc || target.src, target.alt || 'Map preview');
|
openLightbox(src, img ? img.alt : 'Map preview');
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
4
new.php
4
new.php
|
|
@ -645,7 +645,7 @@ $runningJobs = active_worker_jobs($config);
|
||||||
<?php if($err): ?><div class="err"><?=h($err)?></div><?php endif; ?>
|
<?php if($err): ?><div class="err"><?=h($err)?></div><?php endif; ?>
|
||||||
|
|
||||||
<?php if($tab==='videos'): ?><section><h2>Videos without input dir</h2><?php if(!$orphanVideos): ?><p>No orphan videos.</p><?php endif; ?><div class="admin-list"><?php foreach($orphanVideosPage as $v): $vn=basename($v); ?><form method="post" class="admin-item" onsubmit="return confirm('Delete this generated video?') js-ajax-form"><div><strong><?=h($vn)?></strong><br><span><?=h(round(filesize($v)/1048576,1))?> MB</span></div><input type="hidden" name="action" value="delete_video"><input type="hidden" name="video" value="<?=h($vn)?>"><button type="submit">Delete video</button></form><?php endforeach; ?></div><?=page_links('videos',$videoPage,$videoPages)?></section><?php endif; ?>
|
<?php if($tab==='videos'): ?><section><h2>Videos without input dir</h2><?php if(!$orphanVideos): ?><p>No orphan videos.</p><?php endif; ?><div class="admin-list"><?php foreach($orphanVideosPage as $v): $vn=basename($v); ?><form method="post" class="admin-item" onsubmit="return confirm('Delete this generated video?') js-ajax-form"><div><strong><?=h($vn)?></strong><br><span><?=h(round(filesize($v)/1048576,1))?> MB</span></div><input type="hidden" name="action" value="delete_video"><input type="hidden" name="video" value="<?=h($vn)?>"><button type="submit">Delete video</button></form><?php endforeach; ?></div><?=page_links('videos',$videoPage,$videoPages)?></section><?php endif; ?>
|
||||||
<?php if($tab==='edit' && !$editDir): ?><section><h2>Existing input dirs</h2><?php if(!$dirs): ?><p>No input directories yet.</p><?php endif; ?><div class="admin-list video-list"><?php foreach($dirsPage as $d): $runStatus=input_dir_status($d); $running=input_dir_running($d); $enabled=input_dir_enabled($d); $preview=input_dir_preview($d); $state=input_dir_state($d); $fullOutput=basename((string)($state['output'] ?? '')); $previewOutput=basename((string)($state['preview_output'] ?? '')); $hasFullVideo=$fullOutput !== '' && is_file($config['videos_dir'].'/'.$fullOutput); $hasPreviewVideo=$previewOutput !== '' && is_file($config['videos_dir'].'/'.$previewOutput); $displayOutput=($preview && $hasPreviewVideo) ? $previewOutput : ($hasFullVideo ? $fullOutput : ($hasPreviewVideo ? $previewOutput : '')); $hasVideo=$displayOutput !== ''; $displayVideoPath=$hasVideo ? $config['videos_dir'].'/'.$displayOutput : ''; $previewVideo=$hasVideo && $displayOutput === $previewOutput; $canShow=$hasFullVideo && !$preview; $visible=$canShow && input_dir_visible($d); $info=$dirInfo[basename($d)] ?? input_dir_info($d); $data=read_data($d); $meta=cached_video_metadata($displayOutput, $data); $currentSignature=$info['signature'] ?? ''; $fullFingerprint=is_array($state)?(string)($state['fingerprint'] ?? ''):''; $previewFingerprint=is_array($state)?(string)($state['preview_fingerprint'] ?? ''):''; $editedSinceRender=$hasFullVideo && $currentSignature !== '' && $fullFingerprint !== '' && $currentSignature !== $fullFingerprint; $editedSincePreview=!$hasFullVideo && $previewVideo && $currentSignature !== '' && $previewFingerprint !== '' && $currentSignature !== $previewFingerprint; $staleLabel=$editedSinceRender ? 'Edited since render' : ($editedSincePreview ? 'Edited since preview' : ''); ?><article class="video-row admin-video-row<?= $visible ? ' shown' : '' ?>" data-job="<?=h(basename($d))?>"><div><?php if($hasVideo): ?><div class="video-wrapper"><video controls preload="metadata" src="<?=h($config['public_videos'].'/'.rawurlencode($displayOutput))?>"></video><?php $map_n = ($displayOutput !== '' ? pathinfo($displayOutput, PATHINFO_FILENAME) : basename($d)) . '.png'; if(is_file($config['videos_dir'].'/'.$map_n)): ?><img class="map-image" src="<?=h($config['public_videos'].'/'.rawurlencode($map_n))?>" alt="Map"><?php endif; ?></div><?php else: ?><div class="video-placeholder"><img src="assets/img/moto_travel.png" alt=""><span>No video yet</span></div><?php endif; ?></div><div class="video-info"><div class="admin-row-top"><div class="admin-switches">
|
<?php if($tab==='edit' && !$editDir): ?><section><h2>Existing input dirs</h2><?php if(!$dirs): ?><p>No input directories yet.</p><?php endif; ?><div class="admin-list video-list"><?php foreach($dirsPage as $d): $runStatus=input_dir_status($d); $running=input_dir_running($d); $enabled=input_dir_enabled($d); $preview=input_dir_preview($d); $state=input_dir_state($d); $fullOutput=basename((string)($state['output'] ?? '')); $previewOutput=basename((string)($state['preview_output'] ?? '')); $hasFullVideo=$fullOutput !== '' && is_file($config['videos_dir'].'/'.$fullOutput); $hasPreviewVideo=$previewOutput !== '' && is_file($config['videos_dir'].'/'.$previewOutput); $displayOutput=($preview && $hasPreviewVideo) ? $previewOutput : ($hasFullVideo ? $fullOutput : ($hasPreviewVideo ? $previewOutput : '')); $hasVideo=$displayOutput !== ''; $displayVideoPath=$hasVideo ? $config['videos_dir'].'/'.$displayOutput : ''; $previewVideo=$hasVideo && $displayOutput === $previewOutput; $canShow=$hasFullVideo && !$preview; $visible=$canShow && input_dir_visible($d); $info=$dirInfo[basename($d)] ?? input_dir_info($d); $data=read_data($d); $meta=cached_video_metadata($displayOutput, $data); $currentSignature=$info['signature'] ?? ''; $fullFingerprint=is_array($state)?(string)($state['fingerprint'] ?? ''):''; $previewFingerprint=is_array($state)?(string)($state['preview_fingerprint'] ?? ''):''; $editedSinceRender=$hasFullVideo && $currentSignature !== '' && $fullFingerprint !== '' && $currentSignature !== $fullFingerprint; $editedSincePreview=!$hasFullVideo && $previewVideo && $currentSignature !== '' && $previewFingerprint !== '' && $currentSignature !== $previewFingerprint; $staleLabel=$editedSinceRender ? 'Edited since render' : ($editedSincePreview ? 'Edited since preview' : ''); ?><article class="video-row admin-video-row<?= $visible ? ' shown' : '' ?>" data-job="<?=h(basename($d))?>"><div><?php if($hasVideo): ?><div class="video-wrapper"><video controls preload="metadata" src="<?=h($config['public_videos'].'/'.rawurlencode($displayOutput))?>"></video><?php $map_n = ($displayOutput !== '' ? pathinfo($displayOutput, PATHINFO_FILENAME) : basename($d)) . '.png'; if(is_file($config['videos_dir'].'/'.$map_n)): ?><a class="map-image-link" href="<?=h($config['public_videos'].'/'.rawurlencode($map_n))?>"><img class="map-image" src="<?=h($config['public_videos'].'/'.rawurlencode($map_n))?>" alt="Map"></a><?php endif; ?></div><?php else: ?><div class="video-placeholder"><img src="assets/img/moto_travel.png" alt=""><span>No video yet</span></div><?php endif; ?></div><div class="video-info"><div class="admin-row-top"><div class="admin-switches">
|
||||||
<form method="post" class="inline-form switch-form" data-switch="preview">
|
<form method="post" class="inline-form switch-form" data-switch="preview">
|
||||||
<input type="hidden" name="action" value="set_preview">
|
<input type="hidden" name="action" value="set_preview">
|
||||||
<input type="hidden" name="dir" value="<?=h(basename($d))?>">
|
<input type="hidden" name="dir" value="<?=h(basename($d))?>">
|
||||||
|
|
@ -1098,5 +1098,5 @@ function applySwitchPayload(payload){
|
||||||
|
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script src="js/map_lightbox.js" defer></script>
|
<script src="js/map_lightbox.js?v=20260531c" defer></script>
|
||||||
</body></html>
|
</body></html>
|
||||||
10
style.css
10
style.css
|
|
@ -45,14 +45,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.describe-button{display:inline-block;margin-right:.6rem}
|
.describe-button{display:inline-block;margin-right:.6rem}
|
||||||
|
.map-image-link {
|
||||||
|
display: block;
|
||||||
|
margin-top: 1rem;
|
||||||
|
touch-action: manipulation;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
.map-image {
|
.map-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 16 / 9;
|
aspect-ratio: 16 / 9;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
background: #111315;
|
background: #111315;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
margin-top: 1rem;
|
margin-top: 0;
|
||||||
cursor: zoom-in;
|
cursor: zoom-in;
|
||||||
|
touch-action: manipulation;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
transition: transform .22s ease, box-shadow .22s ease;
|
transition: transform .22s ease, box-shadow .22s ease;
|
||||||
}
|
}
|
||||||
.map-image:hover {
|
.map-image:hover {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue