feat: clickable file name in video player for full file playback
- File name in header is now clickable - Click reloads video with full file range (startFrame=0, endFrame=999999) - Added play icon and hover effect for visual feedback
This commit is contained in:
@@ -3,7 +3,10 @@
|
||||
<div class="ms-modal ms-modal-video" :class="{ 'ms-video-ui-idle': uiIdle }" @mouseenter="showUi" @mousemove="showUi" @mouseleave="hideUi">
|
||||
<div class="ms-modal-video-header">
|
||||
<div class="ms-video-header-row">
|
||||
<h3 v-if="actualFileName" class="ms-video-file-name">{{ actualFileName }}</h3>
|
||||
<h3 v-if="actualFileName" class="ms-video-file-name" @click="playFullFile" title="Click to play full file">
|
||||
{{ actualFileName }}
|
||||
<svg class="ms-video-fullfile-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 3 19 12 5 21 5 3"/></svg>
|
||||
</h3>
|
||||
<button class="ms-modal-video-close" @click="close">×</button>
|
||||
</div>
|
||||
<div class="ms-video-header-row ms-video-title-row">
|
||||
@@ -1370,6 +1373,35 @@ function formatTime(sec: number): string {
|
||||
return `${m}:${s.toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
async function playFullFile() {
|
||||
videoLoading.value = true
|
||||
videoError.value = ''
|
||||
marks.value = marks.value.filter(m => m.source !== 'face')
|
||||
try {
|
||||
const data = await apiCall('get_video_stream', {
|
||||
uuid: props.fileUuid,
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
startFrame: 0,
|
||||
endFrame: 999999,
|
||||
original: props.useOriginal,
|
||||
})
|
||||
if (typeof data === 'string') {
|
||||
videoSrc.value = data
|
||||
} else {
|
||||
const blob = new Blob([new Uint8Array(data)], { type: 'video/mp4' })
|
||||
videoSrc.value = URL.createObjectURL(blob)
|
||||
}
|
||||
frameOffset.value = 0
|
||||
await nextTick()
|
||||
videoEl.value?.load()
|
||||
} catch (e: any) {
|
||||
videoError.value = e?.message || 'Failed to load full video'
|
||||
} finally {
|
||||
videoLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onKeydown(e: KeyboardEvent) {
|
||||
if (!visible.value) return
|
||||
switch (e.key) {
|
||||
@@ -1538,7 +1570,10 @@ onUnmounted(() => {
|
||||
}
|
||||
.ms-modal-video-header { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
|
||||
.ms-video-header-row { display: flex; align-items: center; justify-content: space-between; }
|
||||
.ms-video-file-name { font-size: 12px; font-weight: 500; color: var(--text-secondary); margin: 0; max-width: 70%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.ms-video-file-name { font-size: 12px; font-weight: 500; color: var(--text-secondary); margin: 0; max-width: 70%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }
|
||||
.ms-video-file-name:hover { color: var(--primary-color); }
|
||||
.ms-video-fullfile-icon { opacity: 0.5; transition: opacity .15s; }
|
||||
.ms-video-file-name:hover .ms-video-fullfile-icon { opacity: 1; }
|
||||
.ms-video-frame-info { font-size: 12px; color: var(--text-secondary); white-space: nowrap; flex-shrink: 0; }
|
||||
.ms-video-keyframe { color: #ff9800; font-weight: 600; cursor: pointer; }
|
||||
.ms-video-keyframe:hover { text-decoration: underline; }
|
||||
|
||||
Reference in New Issue
Block a user