Skip to content

Commit 87b0f5f

Browse files
committed
fix: improve Video details component
1 parent 21167b5 commit 87b0f5f

File tree

16 files changed

+193
-56
lines changed

16 files changed

+193
-56
lines changed

src/app/src/components/media/MediaEditor.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ const isAudio = computed(() => isAudioFile(props.mediaItem?.path || ''))
3232
/>
3333
<MediaEditorVideo
3434
v-else-if="isVideo"
35-
:src="mediaItem.path!"
35+
:media-item="mediaItem"
36+
:remote-file="remoteFile"
3637
/>
3738
<MediaEditorAudio
3839
v-else-if="isAudio"
Lines changed: 177 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,186 @@
1-
<template>
2-
<div class="relative w-full max-w-4xl mx-auto overflow-hidden bg-black aspect-video">
3-
<div
4-
v-if="!isPlaying"
5-
class="absolute inset-0 flex items-center justify-center bg-black/50 cursor-pointer z-10 transition-opacity hover:bg-black/60"
6-
@click="handlePlay"
7-
>
8-
<UButton
9-
icon="i-lucide-play"
10-
size="xl"
11-
color="neutral"
12-
variant="link"
13-
class="w-32 h-32 rounded-full flex items-center justify-center"
14-
:ui="{ leadingIcon: 'w-16 h-16', trailingIcon: 'w-16 h-16' }"
15-
>
16-
<template #default>
17-
<span class="sr-only">{{ $t('studio.media.playVideo') }}</span>
18-
</template>
19-
</UButton>
20-
</div>
21-
22-
<video
23-
v-if="loaded"
24-
ref="videoRef"
25-
class="w-full aspect-video"
26-
:class="{ 'opacity-50': !isPlaying }"
27-
controls
28-
autoplay
29-
@play="isPlaying = true"
30-
@pause="isPlaying = false"
31-
@ended="isPlaying = false"
32-
>
33-
<source
34-
:src="src"
35-
type="video/mp4"
36-
>
37-
{{ $t('studio.media.videoTagNotSupported') }}
38-
</video>
39-
</div>
40-
</template>
41-
421
<script setup lang="ts">
43-
import { ref } from 'vue'
2+
import { computed, onMounted, ref } from 'vue'
3+
import type { PropType } from 'vue'
4+
import { formatBytes, getFileExtension } from '../../utils/file'
5+
import type { MediaItem, GitFile } from '../../types'
6+
import { useStudio } from '../../composables/useStudio'
7+
import { joinURL } from 'ufo'
8+
import { useI18n } from 'vue-i18n'
9+
10+
const props = defineProps({
11+
mediaItem: {
12+
type: Object as PropType<MediaItem>,
13+
required: true,
14+
},
15+
remoteFile: {
16+
type: Object as PropType<GitFile>,
17+
default: null,
18+
},
19+
})
4420
45-
defineProps<{
46-
src: string
47-
}>()
21+
const { gitProvider } = useStudio()
22+
const { t } = useI18n()
4823
4924
const videoRef = ref<HTMLVideoElement | null>(null)
50-
const loaded = ref(false)
51-
const isPlaying = ref(false)
25+
const videoDimensions = ref({ width: 0, height: 0 })
26+
const duration = ref(0)
5227
53-
const handlePlay = () => {
54-
if (!loaded.value) {
55-
loaded.value = true
56-
return
28+
onMounted(() => {
29+
if (videoRef.value) {
30+
videoRef.value.onloadedmetadata = () => {
31+
console.log('videoRef.value', videoRef.value)
32+
videoDimensions.value = {
33+
width: videoRef.value?.videoWidth || 0,
34+
height: videoRef.value?.videoHeight || 0,
35+
}
36+
duration.value = videoRef.value?.duration || 0
37+
}
5738
}
39+
})
5840
59-
if (videoRef.value) {
60-
videoRef.value.play()
61-
isPlaying.value = true
41+
const fileExtension = computed(() => getFileExtension(props.mediaItem.path || '').toUpperCase())
42+
const fileName = computed(() => {
43+
if (props.remoteFile?.name) {
44+
return props.remoteFile.name
45+
}
46+
if (props.mediaItem.stem) {
47+
const ext = props.mediaItem.extension ? `.${props.mediaItem.extension}` : ''
48+
return `${props.mediaItem.stem}${ext}`
49+
}
50+
return props.mediaItem.path || 'video'
51+
})
52+
53+
54+
const formattedDuration = computed(() => {
55+
if (!duration.value) {
56+
return '0s'
6257
}
63-
}
58+
const totalSeconds = Math.round(duration.value)
59+
const minutes = Math.floor(totalSeconds / 60)
60+
const seconds = totalSeconds % 60
61+
if (minutes === 0) {
62+
return `${seconds}s`
63+
}
64+
return `${minutes}m ${seconds.toString().padStart(2, '0')}s`
65+
})
66+
67+
const videoInfo = computed(() => {
68+
const info = [
69+
{ label: t('studio.media.metaWidth'), value: `${videoDimensions.value.width}px` },
70+
{ label: t('studio.media.metaHeight'), value: `${videoDimensions.value.height}px` },
71+
{ label: t('studio.media.metaType'), value: fileExtension.value },
72+
{ label: 'Duration', value: formattedDuration.value },
73+
]
74+
75+
if (props.remoteFile) {
76+
info.push({ label: t('studio.media.metaSize'), value: formatBytes(props.remoteFile.size) })
77+
}
78+
79+
return info
80+
})
81+
82+
const markdownCode = computed(() => {
83+
return `<video src="${props.mediaItem.path}" controls />`
84+
})
85+
86+
const remotePath = computed(() => {
87+
if (!props.remoteFile?.path) {
88+
return ''
89+
}
90+
return joinURL(gitProvider.api.getBranchUrl(), props.remoteFile.path)
91+
})
6492
</script>
93+
94+
<template>
95+
<div class="flex flex-col h-full gap-4 p-4">
96+
<div class="flex items-center justify-center rounded-lg border border-default overflow-hidden max-h-[350px] bg-black">
97+
<video
98+
ref="videoRef"
99+
:src="mediaItem.path"
100+
class="max-w-full max-h-full"
101+
controls
102+
>
103+
{{ $t('studio.media.videoTagNotSupported') }}
104+
</video>
105+
</div>
106+
107+
<div class="grid grid-cols-2 gap-3">
108+
<div
109+
v-for="info in videoInfo"
110+
:key="info.label"
111+
class="p-3 rounded-lg bg-default border border-muted"
112+
>
113+
<p class="text-xs text-muted mb-1">
114+
{{ info.label }}
115+
</p>
116+
<p class="text-sm font-semibold text-highlighted">
117+
{{ info.value }}
118+
</p>
119+
</div>
120+
</div>
121+
122+
<div class="p-3 rounded-lg bg-default border border-muted">
123+
<div class="flex items-center gap-1 text-xs text-muted mb-2">
124+
<UIcon
125+
name="i-lucide-file"
126+
class="w-3.5 h-3.5"
127+
/>
128+
<span>{{ $t('studio.media.fileName') }}</span>
129+
</div>
130+
<p class="text-xs font-mono text-highlighted truncate">
131+
{{ fileName }}
132+
</p>
133+
</div>
134+
135+
<div class="p-3 rounded-lg bg-default border border-muted relative">
136+
<div class="absolute top-3 right-3">
137+
<CopyButton :content="mediaItem.path!" />
138+
</div>
139+
<div class="flex items-center gap-1 text-xs text-muted mb-2">
140+
<UIcon
141+
name="i-lucide-globe"
142+
class="w-3.5 h-3.5"
143+
/>
144+
<span>{{ $t('studio.media.publicPath') }}</span>
145+
</div>
146+
<p class="text-xs font-mono text-highlighted truncate">
147+
{{ mediaItem.path }}
148+
</p>
149+
</div>
150+
151+
<div
152+
v-if="remoteFile?.path"
153+
class="p-3 rounded-lg bg-default border border-muted relative"
154+
>
155+
<div class="absolute top-3 right-3">
156+
<CopyButton :content="remotePath" />
157+
</div>
158+
<div class="flex items-center gap-1 text-xs text-muted mb-2">
159+
<UIcon
160+
:name="gitProvider.icon"
161+
class="w-3.5 h-3.5"
162+
/>
163+
<span>{{ $t('studio.media.providerPath', { providerName: gitProvider.name }) }}</span>
164+
</div>
165+
<p class="text-xs font-mono text-highlighted truncate">
166+
{{ remoteFile.path }}
167+
</p>
168+
</div>
169+
170+
<div class="p-3 rounded-lg bg-default border border-muted relative">
171+
<div class="absolute top-3 right-3">
172+
<CopyButton :content="markdownCode" />
173+
</div>
174+
<div class="flex items-center gap-1 text-xs text-muted mb-2">
175+
<UIcon
176+
name="i-simple-icons:markdown"
177+
class="w-3.5 h-3.5"
178+
/>
179+
<span>{{ $t('studio.media.markdown') }}</span>
180+
</div>
181+
<p class="text-xs font-mono text-highlighted truncate">
182+
{{ markdownCode }}
183+
</p>
184+
</div>
185+
</div>
186+
</template>

src/app/src/locales/bg.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "Ширина",
103103
"metaHeight": "Височина",
104104
"metaType": "Тип",
105+
"metaDuration": "Продължителност",
105106
"metaSize": "Размер",
106107
"fileName": "Име на файл",
107108
"publicPath": "Публичен път",

src/app/src/locales/de.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "Breite",
103103
"metaHeight": "Höhe",
104104
"metaType": "Typ",
105+
"metaDuration": "Dauer",
105106
"metaSize": "Größe",
106107
"fileName": "Dateiname",
107108
"publicPath": "Öffentlicher Pfad",

src/app/src/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "Width",
103103
"metaHeight": "Height",
104104
"metaType": "Type",
105+
"metaDuration": "Duration",
105106
"metaSize": "Size",
106107
"fileName": "File name",
107108
"publicPath": "Public path",

src/app/src/locales/es.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "Ancho",
103103
"metaHeight": "Alto",
104104
"metaType": "Tipo",
105+
"metaDuration": "Duración",
105106
"metaSize": "Tamaño",
106107
"fileName": "Nombre del archivo",
107108
"publicPath": "Ruta pública",

src/app/src/locales/fa.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "عرض",
103103
"metaHeight": "ارتفاع",
104104
"metaType": "نوع",
105+
"metaDuration": "مدت",
105106
"metaSize": "اندازه",
106107
"fileName": "نام فایل",
107108
"publicPath": "مسیر عمومی",

src/app/src/locales/fi.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "Leveys",
103103
"metaHeight": "Korkeus",
104104
"metaType": "Tyyppi",
105+
"metaDuration": "Kesto",
105106
"metaSize": "Koko",
106107
"fileName": "Tiedostonimi",
107108
"publicPath": "Julkinen polky",

src/app/src/locales/fr.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "Largeur",
103103
"metaHeight": "Hauteur",
104104
"metaType": "Type",
105+
"metaDuration": "Durée",
105106
"metaSize": "Taille",
106107
"fileName": "Nom du fichier",
107108
"publicPath": "Chemin public",

src/app/src/locales/id.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"metaWidth": "Lebar",
103103
"metaHeight": "Tinggi",
104104
"metaType": "Tipe",
105+
"metaDuration": "Durasi",
105106
"metaSize": "Ukuran",
106107
"fileName": "Nama berkas",
107108
"publicPath": "Path publik",

0 commit comments

Comments
 (0)