11<script setup lang="ts">
2- import { computed } from ' vue' ;
2+ import { computed , ref } from ' vue' ;
33import { useRouter } from ' vue-router' ;
44import { useStreamStore } from ' @/stores/stream' ;
5+ import { ArrowLeft , Download , Maximize } from ' lucide-vue-next' ;
56
67const router = useRouter ();
78
@@ -14,88 +15,77 @@ const props = defineProps<{
1415}>();
1516
1617const recording = computed (() => streamStore .recordings .find (r => r .id === props .recording ));
18+ const videoContainer = ref <HTMLDivElement | null >(null );
19+
20+ const toggleFullscreen = () => {
21+ if (! videoContainer .value ) return ;
22+
23+ if (! document .fullscreenElement ) {
24+ videoContainer .value .requestFullscreen ();
25+ } else {
26+ document .exitFullscreen ();
27+ }
28+ };
1729 </script >
1830
1931<template >
20- <div class =" h-full flex flex-col" >
21- <div class =" relative h-full flex flex-col" >
22- <div class =" absolute top-4 right-4 z-10" >
23- <button @click.prevent =" router.push({ name: 'recordings' })" class =" bg-gray-900 text-white p-2 rounded cursor-pointer" >
24- ✕
25- </button >
26- </div >
27-
28- <div class =" flex-1 bg-gray-700 flex items-center justify-center" >
29- <div class =" w-full h-full flex items-center justify-center bg-gray-700" >
30- <video
31- v-if =" recording"
32- style =" max-height : 80vh "
33- :src =" recording.path"
34- muted
35- controls
36- autoplay
37- />
38- </div >
39- </div >
40-
41- <!-- <div class="h-16 bg-gray-800 flex items-center justify-between px-4">
42- <div class="flex items-center gap-4">
43- <button class="text-white">
44- ⏸️
45- </button>
46- <button class="text-white">
47- 🔇
48- </button>
49- <div class="flex items-center text-white gap-1">
50- <span>00:22</span>
51- <span>/</span>
52- <span>04:12</span>
53- </div>
54- <div class="w-64 h-1 bg-gray-600 rounded-full overflow-hidden">
55- <div class="w-1/4 h-full bg-nvrblue"></div>
32+ <div class =" h-full flex flex-col bg-gray-900" >
33+ <div class =" absolute top-4 left-4 z-10 flex gap-2" >
34+ <button
35+ @click =" router.push({ name: 'recordings' })"
36+ class =" bg-gray-900/80 hover:bg-gray-900 text-white p-3 rounded-md cursor-pointer transition-colors backdrop-blur-sm"
37+ title =" Back to Recordings"
38+ >
39+ <ArrowLeft :size =" 20" />
40+ </button >
41+ </div >
42+
43+ <div class =" absolute top-4 right-4 z-10 flex gap-2" >
44+ <a
45+ v-if =" recording"
46+ :href =" recording.path"
47+ download
48+ class =" bg-gray-900/80 hover:bg-gray-900 text-white p-3 rounded-md cursor-pointer transition-colors backdrop-blur-sm"
49+ title =" Download Recording"
50+ >
51+ <Download :size =" 20" />
52+ </a >
53+ <button
54+ @click =" toggleFullscreen"
55+ class =" bg-gray-900/80 hover:bg-gray-900 text-white p-3 rounded-md cursor-pointer transition-colors backdrop-blur-sm"
56+ title =" Toggle Fullscreen"
57+ >
58+ <Maximize :size =" 20" />
59+ </button >
60+ </div >
61+
62+ <div v-if =" recording" class =" flex-1 flex flex-col items-center justify-center relative" >
63+ <div ref =" videoContainer" class =" w-full h-full max-w-7xl bg-black relative" >
64+ <video
65+ class =" w-full h-full"
66+ :src =" recording.path"
67+ muted
68+ controls
69+ autoplay
70+ />
71+
72+ <div class =" absolute bottom-16 left-4 z-20 bg-gray-900/90 text-white px-4 py-2 rounded-md backdrop-blur-sm max-w-[calc(100%-2rem)]" >
73+ <h2 class =" text-lg font-medium mb-1" >{{ recording.stream_name }}</h2 >
74+ <div class =" flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2 text-sm text-gray-300" >
75+ <RouterLink :to =" `/cameras/${recording.stream_id}`" class =" hover:underline" >
76+ View Camera
77+ </RouterLink >
78+ <span class =" hidden sm:inline" >•</span >
79+ <span >{{ (new Date(recording.start)).toLocaleString() }}</span >
80+ <span class =" hidden sm:inline" >•</span >
81+ <span >{{ Math.round(((new Date(recording.end)).getTime() - (new Date(recording.start)).getTime()) / (1000 * 60)) }} min</span >
5682 </div >
5783 </div >
58-
59- <div class="flex items-center gap-2">
60- <button class="text-white">
61- 📺
62- </button>
63- </div>
64- </div> -->
65-
66- <div v-if =" recording" class =" bg-gray-900 text-white p-4" >
67- <div class =" flex items-center justify-between" >
68- <h3 class =" text-lg font-medium" >Info</h3 >
69- <button >▼</button >
70- </div >
71-
72- <div class =" grid grid-cols-2 gap-y-2 mt-4" >
73- <div >Stream</div >
74- <div class =" text-right" >{{ recording.stream_name }}</div >
75-
76- <div >Date/Time</div >
77- <div class =" text-right" >{{ (new Date(recording.start)).toLocaleString() }}</div >
78-
79- <div >Duration</div >
80- <div class =" text-right" >{{ Math.round(((new Date(recording.end)).getTime() - (new Date(recording.start)).getTime()) / (1000 * 60)) }} minutes</div >
81-
82- <!--
83- <div>Unlocked</div>
84- <div class="text-right flex items-center justify-end">
85- <div class="h-6 w-6 rounded bg-gray-700 mr-1"></div>
86- <button class="h-6 w-6 rounded bg-gray-700">🔓</button>
87- </div> -->
88- </div >
89- </div >
90-
91- <div v-if =" recording" class =" p-4 bg-gray-100 flex justify-end gap-2" >
92- <a class =" nvr-button bg-blue-500 flex items-center gap-2 py-2" :href =" recording.path" download >
93- ⬇️ DOWNLOAD
94- </a >
95- <!-- <button class="border border-gray-300 px-4 py-2 rounded flex items-center gap-2 text-sm">
96- 🗑️ DELETE
97- </button> -->
9884 </div >
9985 </div >
86+
87+ <div v-else class =" flex-1 flex items-center justify-center text-white" >
88+ <p >Recording not found</p >
89+ </div >
10090 </div >
10191</template >
0 commit comments