返回 slidev
RecordingDialog.vue
根目录 / packages / client / internals / RecordingDialog.vue
1 <script setup lang="ts">
2 import { useVModel } from '@vueuse/core'
3 import { nextTick } from 'vue'
4 import { bitRate, frameRate, getFilename, mimeType, recordCamera, recorder, recordingName, resolution } from '../logic/recording'
5 import DevicesSelectors from './DevicesSelectors.vue'
6 import Modal from './Modal.vue'
7
8 const props = defineProps({
9 modelValue: {
10 default: false,
11 },
12 })
13
14 const emit = defineEmits<{
15 (e: any): void
16 }>()
17 const value = useVModel(props, 'modelValue', emit)
18
19 const { startRecording } = recorder
20
21 const frameRateOptions = [15, 24, 30, 60]
22 const resolutionOptions = [
23 { value: '1280x720', label: '720p (1280x720)' },
24 { value: '1920x1080', label: '1080p (1920x1080)' },
25 { value: '2560x1440', label: '1440p (2560x1440)' },
26 { value: '3840x2160', label: '2160p (3840x2160)' },
27 ]
28
29 function close() {
30 value.value = false
31 }
32
33 async function start() {
34 close()
35 await nextTick()
36 startRecording({
37 mimeType: mimeType.value,
38 bitsPerSecond: bitRate.value * 1024,
39 })
40 }
41 </script>
42
43 <template>
44 <Modal v-model="value" class="px-6 py-4 recording-dialog flex flex-col gap-2">
45 <div class="flex gap-2 text-xl">
46 <div class="i-carbon:video my-auto" />Recording
47 </div>
48 <div class="grid grid-cols-2 gap-4">
49 <div class="flex flex-col gap-2 py-2">
50 <div class="form-text">
51 <label for="title">Recording Name</label>
52 <input
53 v-model="recordingName"
54 class="bg-transparent text-current"
55 name="title"
56 type="text"
57 placeholder="Enter the title..."
58 >
59 <div class="text-xs w-full opacity-50 py-2">
60 <div>This will be used in the output filename that might <br>help you better organize your recording chips.</div>
61 </div>
62 </div>
63
64 <div class="form-text">
65 <label for="framerate">Frame Rate</label>
66 <select
67 v-model="frameRate"
68 class="bg-transparent text-current border border-main rounded px-2 py-1"
69 name="framerate"
70 >
71 <option v-for="rate in frameRateOptions" :key="rate" :value="rate">
72 {{ rate }} fps
73 </option>
74 </select>
75 </div>
76
77 <div class="form-text">
78 <label for="resolution">Resolution</label>
79 <select
80 v-model="resolution"
81 class="bg-transparent text-current border border-main rounded px-2 py-1"
82 name="resolution"
83 >
84 <option v-for="res in resolutionOptions" :key="res.value" :value="res.value">
85 {{ res.label }}
86 </option>
87 </select>
88 </div>
89
90 <div class="form-text">
91 <label for="bitrate">Bitrate</label>
92 <div class="relative">
93 <input
94 v-model.number="bitRate"
95 type="number"
96 min="1000"
97 step="1000"
98 class="bg-transparent text-current border border-main rounded px-2 py-1 w-full pr-12"
99 name="bitrate"
100 >
101 <span class="absolute right-3 top-1/2 transform -translate-y-1/2 text-sm opacity-50">kbps</span>
102 </div>
103 </div>
104
105 <div class="form-check">
106 <input
107 v-model="recordCamera"
108 name="record-camera"
109 type="checkbox"
110 >
111 <label for="record-camera" @click="recordCamera = !recordCamera">Record camera separately</label>
112 </div>
113
114 <div class="text-xs w-full opacity-50">
115 <div class="mt-2 opacity-50">
116 Enumerated filenames
117 </div>
118 <div class="font-mono">
119 {{ getFilename('screen', mimeType) }}
120 </div>
121 <div v-if="recordCamera" class="font-mono">
122 {{ getFilename('camera', mimeType) }}
123 </div>
124 </div>
125 </div>
126 <DevicesSelectors />
127 </div>
128 <div class="flex my-1">
129 <button class="slidev-form-button" @click="close">
130 Cancel
131 </button>
132 <div class="flex-auto" />
133 <button class="slidev-form-button primary" @click="start">
134 Start
135 </button>
136 </div>
137 </Modal>
138 </template>
139
140 <style lang="postcss">
141 .recording-dialog {
142 .form-text {
143 @apply flex flex-col;
144
145 label {
146 @apply text-xs uppercase opacity-50 tracking-widest py-1;
147 }
148 }
149
150 .form-check {
151 @apply leading-5;
152
153 * {
154 @apply my-auto align-middle;
155 }
156
157 label {
158 @apply ml-1 text-sm select-none;
159 }
160 }
161
162 input[type='text'] {
163 @apply border border-main rounded px-2 py-1;
164 }
165 }
166 </style>
167
167 lines Plain Text