@sigmaott/base-library-next 2.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +1 -0
  2. package/locales/en.yaml +289 -0
  3. package/locales/vi.yaml +294 -0
  4. package/nuxt.config.ts +18 -0
  5. package/package.json +33 -0
  6. package/public/routes.json +34 -0
  7. package/src/api/axios.ts +3 -0
  8. package/src/api/index.ts +86 -0
  9. package/src/api-client-library/.openapi-generator/FILES +20 -0
  10. package/src/api-client-library/.openapi-generator/VERSION +1 -0
  11. package/src/api-client-library/.openapi-generator-ignore +23 -0
  12. package/src/api-client-library/api/health-api.ts +119 -0
  13. package/src/api-client-library/api/presets-api.ts +599 -0
  14. package/src/api-client-library/api/profiles-api.ts +676 -0
  15. package/src/api-client-library/api.ts +20 -0
  16. package/src/api-client-library/base.ts +72 -0
  17. package/src/api-client-library/common.ts +150 -0
  18. package/src/api-client-library/configuration.ts +101 -0
  19. package/src/api-client-library/git_push.sh +57 -0
  20. package/src/api-client-library/index.ts +18 -0
  21. package/src/api-client-library/models/create-preset-dto.ts +223 -0
  22. package/src/api-client-library/models/create-profile-dto.ts +45 -0
  23. package/src/api-client-library/models/health-controller-get-health200-response-info-value.ts +32 -0
  24. package/src/api-client-library/models/health-controller-get-health200-response.ts +51 -0
  25. package/src/api-client-library/models/health-controller-get-health503-response.ts +51 -0
  26. package/src/api-client-library/models/index.ts +7 -0
  27. package/src/api-client-library/models/update-preset-dto.ts +223 -0
  28. package/src/api-client-library/models/update-profile-dto.ts +45 -0
  29. package/src/components/MediaSelection.vue +40 -0
  30. package/src/components/PresetModify.vue +154 -0
  31. package/src/components/PresetTable.vue +114 -0
  32. package/src/components/ProfileAllList.vue +137 -0
  33. package/src/components/ProfileFormModal.vue +79 -0
  34. package/src/components/ProfileModify.vue +152 -0
  35. package/src/components/ProfileTable.vue +68 -0
  36. package/src/components/WatermarkDraggableItem.vue +88 -0
  37. package/src/components/channel/ConfigWatermarkItem.vue +239 -0
  38. package/src/components/channel/WatermarkPreview.vue +19 -0
  39. package/src/components/common/Vue3DraggableResizable/Container.vue +71 -0
  40. package/src/components/common/Vue3DraggableResizable/index.vue +1327 -0
  41. package/src/components/common/Vue3DraggableResizable/utils/dom.js +63 -0
  42. package/src/components/common/Vue3DraggableResizable/utils/fns.js +37 -0
  43. package/src/components/common/VueDraggableResizable/dom.js +63 -0
  44. package/src/components/common/VueDraggableResizable/fns.js +37 -0
  45. package/src/components/common/VueDraggableResizable/index.vue +958 -0
  46. package/src/components/preset/ConfigItem.vue +956 -0
  47. package/src/components/profile/ConfigItem.vue +765 -0
  48. package/src/components/profile/TableColumns.vue +137 -0
  49. package/src/components/shared/AudioInfoViewer.vue +101 -0
  50. package/src/components/shared/MediaInfoViewer.vue +249 -0
  51. package/src/components/shared/MediaInfoViewerSmall.vue +105 -0
  52. package/src/components/shared/PopoverProfile.vue +17 -0
  53. package/src/components/shared/VideoInfoViewer.vue +136 -0
  54. package/src/components/shared/fileSizeFilter.ts +26 -0
  55. package/src/composables/preset.ts +141 -0
  56. package/src/public/apple-touch-icon-180x180.png +0 -0
  57. package/src/public/build-time.json +1 -0
  58. package/src/public/favicon.ico +0 -0
  59. package/src/public/favicon.svg +15 -0
  60. package/src/public/logo.png +0 -0
  61. package/src/public/logo.svg +9 -0
  62. package/src/public/maskable-icon-512x512.png +0 -0
  63. package/src/public/pwa-192x192.png +0 -0
  64. package/src/public/pwa-512x512.png +0 -0
  65. package/src/public/pwa-64x64.png +0 -0
  66. package/src/public/routes.json +87 -0
  67. package/src/utils/common.ts +175 -0
  68. package/src/utils/config.ts +19 -0
  69. package/src/utils/preset.ts +353 -0
  70. package/src/utils/profile.ts +30 -0
  71. package/tsconfig.json +3 -0
@@ -0,0 +1,137 @@
1
+ <script lang="ts" setup>
2
+
3
+ </script>
4
+
5
+ <template>
6
+ <el-table-column :label="$t('profile.name')" prop="name" width="250" show-overflow-tooltip sortable>
7
+ <template #default="scope">
8
+ {{ scope.row.name }}
9
+ </template>
10
+ </el-table-column>
11
+ <el-table-column label="Video" prop="video" width="515">
12
+ <template #default="scope">
13
+ <el-scrollbar max-height="135px" class="pr-4px">
14
+ <SharedMediaInfoViewer
15
+ v-for="(item, idx) in scope.row.video || []" :key="idx" :media="item"
16
+ class="w-96% justify-center"
17
+ />
18
+ </el-scrollbar>
19
+ <!-- <SharedPopoverProfile :media="scope.row.video" /> -->
20
+ </template>
21
+ </el-table-column>
22
+ <el-table-column label="Audio" prop="audio" min-width="350">
23
+ <template #default="scope">
24
+ <div v-if="scope.row?.audio?.length === 0" class="text-center" style="color: #97a8be; margin-left: 8px">
25
+ No Item
26
+ </div>
27
+
28
+ <div v-else class="flex gap-2px">
29
+ <template v-for="(item) in scope.row.audio?.slice(0, 2) || []" :key="item.id">
30
+ <div v-if="scope.row.audio?.length > 2" class="item-list-row max-w-150px flex items-center gap-1">
31
+ <div class="i-ep:headset min-w-14px text-primary" />
32
+ <SSTooltipEllipsis :content="item.name" :line-clamp="1" />
33
+ </div>
34
+ <el-popover
35
+ v-else
36
+ placement="bottom"
37
+ trigger="hover"
38
+ :width="500"
39
+ >
40
+ <template #reference>
41
+ <div class="item-list-row max-w-150px flex items-center gap-1">
42
+ <div class="i-ep:headset min-w-14px text-primary" />
43
+ <SSTooltipEllipsis :content="item.name" :line-clamp="1" />
44
+ </div>
45
+ </template>
46
+ <el-scrollbar>
47
+ <SharedMediaInfoViewer
48
+ v-for="(i, idx) in scope.row.audio || []" :key="idx" class="w-96% justify-center"
49
+ :media="i"
50
+ />
51
+ </el-scrollbar>
52
+ </el-popover>
53
+ </template>
54
+ <el-popover
55
+ v-if="scope.row.audio?.length > 2"
56
+ placement="bottom"
57
+ trigger="hover"
58
+ :width="500"
59
+ >
60
+ <template #reference>
61
+ <span class="item-list-row">
62
+ ...
63
+ </span>
64
+ </template>
65
+ <el-scrollbar height="200px">
66
+ <SharedMediaInfoViewer
67
+ v-for="(i, idx) in scope.row.audio || []" :key="idx" class="w-96% justify-center"
68
+ :media="i"
69
+ />
70
+ </el-scrollbar>
71
+ </el-popover>
72
+ <!-- <SharedPopoverProfile :media="scope.row.audio" /> -->
73
+ </div>
74
+ </template>
75
+ </el-table-column>
76
+ <el-table-column label="Data" prop="data" min-width="350">
77
+ <template #default="scope">
78
+ <div v-if="scope.row?.data?.length === 0" class="text-center" style="color: #97a8be; margin-left: 8px">
79
+ No Item
80
+ </div>
81
+ <div v-else class="flex gap-2px">
82
+ <template v-for="(item) in scope.row.data?.slice(0, 2) || []" :key="item.id">
83
+ <div v-if="scope.row.data?.length > 2" class="item-list-row max-w-150px flex items-center gap-1">
84
+ <div class="i-ep:menu min-w-14px text-primary" />
85
+ <SSTooltipEllipsis :content="item.name" :line-clamp="1" />
86
+ </div>
87
+ <el-popover
88
+ v-else
89
+ placement="bottom"
90
+ trigger="hover"
91
+ :width="500"
92
+ >
93
+ <template #reference>
94
+ <div class="item-list-row max-w-150px flex items-center gap-1">
95
+ <div class="i-ep:menu min-w-14px text-primary" />
96
+ <SSTooltipEllipsis :content="item.name" :line-clamp="1" />
97
+ </div>
98
+ </template>
99
+ <el-scrollbar>
100
+ <SharedMediaInfoViewer
101
+ v-for="(i, idx) in scope.row.data || []" :key="idx" class="w-96% justify-center"
102
+ :media="i"
103
+ />
104
+ </el-scrollbar>
105
+ </el-popover>
106
+ </template>
107
+ <el-popover
108
+ v-if="scope.row.data?.length > 2"
109
+ placement="bottom"
110
+ trigger="hover"
111
+ :width="500"
112
+ >
113
+ <template #reference>
114
+ <span class="item-list-row">
115
+ ...
116
+ </span>
117
+ </template>
118
+ <el-scrollbar height="200px">
119
+ <SharedMediaInfoViewer
120
+ v-for="(i, idx) in scope.row.data || []" :key="idx" class="w-96% justify-center"
121
+ :media="i"
122
+ />
123
+ </el-scrollbar>
124
+ </el-popover>
125
+ </div>
126
+ </template>
127
+ </el-table-column>
128
+ </template>
129
+
130
+ <style scoped>
131
+ .item-list-row {
132
+ padding: 5px;
133
+ position: relative;
134
+ border: 1px solid rgba(64, 158, 255, 0.4);
135
+ border-radius: 4px;
136
+ }
137
+ </style>
@@ -0,0 +1,101 @@
1
+ <script lang="ts" setup>
2
+ import { fileSizeFilter } from './fileSizeFilter'
3
+
4
+ defineProps<{
5
+ audio: any
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <div class="item-list-row flex justify-center">
11
+ <ul class="flex flex-wrap justify-center">
12
+ <li>
13
+ <el-icon>
14
+ <div class="i-ep:headset text-primary" />
15
+ </el-icon>
16
+ <el-icon v-if="audio.codec === 'copy'" class="text-indigo-500" name="document-copy">
17
+ <div class="i-ep:document-copy text-indigo-500" />
18
+ </el-icon>&nbsp;
19
+ <span class="item__name" :title="audio.name">{{
20
+ (audio && audio.name) || '-'
21
+ }}</span>
22
+ </li>
23
+ <span class="text-gray-400">&nbsp;|&nbsp;</span>
24
+ <li title="Codec">
25
+ <el-icon>
26
+ <div class="i-ep:grid text-indigo-500" />
27
+ </el-icon>&nbsp;
28
+ <span class="item__name">{{ audio.codec }}</span>
29
+ </li>
30
+ <span class="text-gray-400">&nbsp;|&nbsp;</span>
31
+ <li title="Bitrate">
32
+ <el-icon>
33
+ <div class="i-ep:scale-to-original text-teal-600" />
34
+ </el-icon>&nbsp;
35
+ <span>{{ audio.bitrate ? fileSizeFilter(audio.bitrate) : fileSizeFilter(audio.audioBitrate) }}/s</span>
36
+ </li>
37
+ <span class="text-gray-400">&nbsp;|&nbsp;</span>
38
+ <li title="Sample rate">
39
+ <el-icon>
40
+ <div class="i-ep:message-box text-indigo-500" />
41
+ </el-icon>&nbsp;
42
+ <span>{{ audio.sampleRate || '-' }}</span>
43
+ </li>
44
+ <span class="text-gray-400">&nbsp;|&nbsp;</span>
45
+ <li title="Profile">
46
+ <el-icon>
47
+ <div class="i-ep:credit-card" :class="!audio.profile || 'text-teal-600'" />
48
+ </el-icon>&nbsp;
49
+ <span>{{ audio.profile || '-' }}</span>
50
+ </li>
51
+ <span class="text-gray-400">&nbsp;|&nbsp;</span>
52
+ <li title="Channel">
53
+ <el-icon>
54
+ <div class="i-ep:scale-to-original text-teal-600" />
55
+ </el-icon>&nbsp;
56
+ <span>{{ audio.channel || '-' }}</span>
57
+ </li>
58
+ </ul>
59
+
60
+ <div v-if="$slots && $slots.anchor" class="anchor">
61
+ <slot name="anchor" />
62
+ </div>
63
+ </div>
64
+ </template>
65
+
66
+ <style lang="scss" scoped>
67
+ .item-list-row {
68
+ margin: 5px;
69
+ padding: 5px;
70
+ position: relative;
71
+ border: 1px solid rgba(230, 162, 60, 0.4);
72
+ border-radius: 4px;
73
+
74
+ ul {
75
+ li {
76
+ white-space: nowrap;
77
+ display: flex;
78
+ align-items: center;
79
+ }
80
+
81
+ .item__name {
82
+ max-width: 85px;
83
+ overflow: hidden;
84
+ white-space: nowrap;
85
+ text-overflow: ellipsis;
86
+ }
87
+ }
88
+
89
+ .anchor {
90
+ padding: 5px;
91
+ margin: -5px -5px -5px 5px;
92
+ display: flex;
93
+ flex-direction: column;
94
+ border-left: 1px solid;
95
+ border-color: inherit;
96
+ background-color: rgba(230, 162, 60, 0.2);
97
+ border-top-right-radius: inherit;
98
+ border-bottom-right-radius: inherit;
99
+ }
100
+ }
101
+ </style>
@@ -0,0 +1,249 @@
1
+ <script setup lang="ts">
2
+ // import { fileSizeFilter } from './fileSizeFilter'
3
+
4
+ const props = defineProps<{ media: any }>()
5
+
6
+ const hasInterlaced = computed(() => {
7
+ return (
8
+ (props.media && props.media.interlaced)
9
+ || (props.media
10
+ && !props.media.interlaced
11
+ && typeof props.media.interlaced === 'boolean')
12
+ )
13
+ })
14
+
15
+ const hasCbr = computed(() => {
16
+ return (
17
+ (props.media && props.media.cbr)
18
+ || (props.media && !props.media.cbr && typeof props.media.cbr === 'boolean')
19
+ )
20
+ })
21
+
22
+ function fileSizeFilter(size: number) {
23
+ if (Number.isNaN(size))
24
+ size = 0
25
+
26
+ return `${(size / 1024).toFixed(2)} KB`
27
+ }
28
+ </script>
29
+
30
+ <template>
31
+ <div class="item-list-row inline-flex">
32
+ <ul class="flex flex-wrap items-center justify-center">
33
+ <template v-if="media && media.name && media.type !== 'video'">
34
+ <li title="Name">
35
+ <el-icon>
36
+ <div class="i-ep:camera-filled text-primary" :class="media.type === 'audio' ? 'i-ep:headset' : 'i-ep:menu'" />
37
+ </el-icon>&nbsp;
38
+ <span v-if="media.codec === 'copy'">&nbsp;</span>
39
+ <span class="item__name" :title="media.name">{{
40
+ (media && media.name) || '-'
41
+ }}</span>
42
+ </li>
43
+ </template>
44
+ <template v-if="media && media.codec">
45
+ <li title="Codec">
46
+ <el-icon>
47
+ <div class="i-ep:grid text-indigo-500" />
48
+ </el-icon>&nbsp;
49
+ <span>{{ media.codec }}</span>
50
+ </li>
51
+ </template>
52
+ <template v-if="media && (media.height || media.width) && media.type !== 'data'">
53
+ <li title="Resolution">
54
+ <el-icon name="crop">
55
+ <div class="i-ep:crop text-pink-600" />
56
+ </el-icon>&nbsp;
57
+ <span>{{ media.width }}x{{ media.height }}</span>
58
+ </li>
59
+ </template>
60
+ <template v-if="(media?.videoBitrate || media?.audioBitrate) && media.type !== 'data'">
61
+ <li title="Bitrate">
62
+ <el-icon>
63
+ <div class="i-ep:scale-to-original text-teal-600" />
64
+ </el-icon>&nbsp;
65
+ <span>{{ media.audioBitrate ? fileSizeFilter(media.audioBitrate || media.bitrate) : fileSizeFilter(media.videoBitrate || media.bitrate) }}/s</span>
66
+ </li>
67
+ </template>
68
+ <template v-if="media?.fps && media?.fps !== 0 && media.type !== 'data'">
69
+ <li title="FPS">
70
+ <el-icon>
71
+ <div class="i-ep:sort text-green-600" />
72
+ </el-icon>&nbsp;
73
+ <span>{{ media.fps }} fps</span>
74
+ </li>
75
+ </template>
76
+ <template v-if="media && media?.sampleRate && media.type !== 'data' && media.type !== 'video'">
77
+ <li title="Sample rate">
78
+ <el-icon>
79
+ <div class="i-ep:message-box text-indigo-500" />
80
+ </el-icon>&nbsp;
81
+ <span>{{ media.sampleRate || '-' }}</span>
82
+ </li>
83
+ </template>
84
+ <!-- <template v-if="media.type === 'video'">
85
+ <li title="CBR">
86
+ <el-icon>
87
+ <div class="i-ep:switch-button" :class="media.cbr ? 'text-success' : 'text-gray-400'" />
88
+ </el-icon>
89
+ &nbsp;
90
+ <span> cbr </span>
91
+ </li>
92
+ </template>
93
+ <template v-if="media.type === 'video'">
94
+ <li title="Pixel format">
95
+ <el-icon>
96
+ <div class="i-ep:picture" :class="!media.pixelFormat || 'text-indigo-500'" />
97
+ </el-icon>&nbsp;
98
+ <span>{{ media.pixelFormat || '-' }}</span>
99
+ </li>
100
+ </template>
101
+ <template v-if="media.type === 'video'">
102
+ <li title="Scale type">
103
+ <el-icon>
104
+ <div class="i-ep:scale-to-original" :class="!media.scaleType || 'text-pink-600'" />
105
+ </el-icon>&nbsp;
106
+ <span>{{ media.scaleType || '-' }}</span>
107
+ </li>
108
+ </template>
109
+
110
+ <template v-if="media.type === 'video'">
111
+ <li title="Constant quality">
112
+ <el-icon>
113
+ <div class="i-ep:star-filled" :class="!media.cq || 'text-teal-600'" />
114
+ </el-icon>&nbsp;
115
+ <span>{{ media.cq || '-' }}</span>
116
+ </li>
117
+ </template>
118
+
119
+ <template v-if="media.type === 'video'">
120
+ <li title="Interlaced mode">
121
+ <el-icon>
122
+ <div class="i-ep:switch-button" :class="media.interlaced ? 'text-success' : 'text-gray-400'" />
123
+ </el-icon>
124
+ &nbsp;
125
+ <span> interlaced </span>
126
+ </li>
127
+ </template> -->
128
+ <template v-if="media && media.channel && media.type === 'audio'">
129
+ <li title="Channel">
130
+ <el-icon>
131
+ <div class="i-ep:platform text-pink-600" />
132
+ </el-icon>&nbsp;
133
+ <span>{{ media.channel || '-' }}</span>
134
+ </li>
135
+ </template>
136
+ <template v-if="media && media.bframe && media.type !== 'video' && media.type !== 'data'">
137
+ <li title="Bframe">
138
+ <el-icon>
139
+ <div class="i-ep:full-screen text-indigo-500" />
140
+ </el-icon>&nbsp;
141
+ <span>{{ media.bframe || '-' }}</span>
142
+ </li>
143
+ </template>
144
+ <template v-if="media && media.profile && media.type !== 'data'">
145
+ <li title="Profile">
146
+ <el-icon>
147
+ <div class="i-ep:credit-card text-gray-400" />
148
+ </el-icon>&nbsp;
149
+ <span>{{ media.profile || '-' }}</span>
150
+ </li>
151
+ </template>
152
+ <template v-if="media && media.level">
153
+ <li title="Level">
154
+ <el-icon>
155
+ <div class="i-ep:star text-indigo-500" />
156
+ </el-icon>&nbsp;
157
+ <span>{{ media.level || '-' }}</span>
158
+ </li>
159
+ </template>
160
+ <template v-if="media && media.colorRange">
161
+ <li title="Color range">
162
+ <el-icon>
163
+ <div class="i-ep:brush text-green-600" />
164
+ </el-icon>&nbsp;
165
+ <span>Range:
166
+ <span class="font-medium">{{ media.colorRange || '-' }}</span></span>
167
+ </li>
168
+ </template>
169
+ <template v-if="media && media.colorTransfer">
170
+ <li title="Color transfer">
171
+ <el-icon>
172
+ <div class="i-ep:brush text-green-600" />
173
+ </el-icon>&nbsp;
174
+ <span>Transfer:
175
+ <span class="font-medium">{{
176
+ media.colorTransfer || '-'
177
+ }}</span></span>
178
+ </li>
179
+ </template>
180
+ <template v-if="media && media.colorPrimaries">
181
+ <li title="Color primaries">
182
+ <el-icon>
183
+ <div class="i-ep:brush text-green-600" />
184
+ </el-icon>&nbsp;
185
+ <span>Primary:
186
+ <span class="font-medium">{{
187
+ media.colorPrimaries || '-'
188
+ }}</span></span>
189
+ </li>
190
+ </template>
191
+ <template v-if="media && media.colorSpace">
192
+ <li title="Color space">
193
+ <el-icon>
194
+ <div class="i-ep:brush text-green-600" />
195
+ </el-icon>&nbsp;
196
+ <span>Space:
197
+ <span class="font-medium">{{ media.colorSpace || '-' }}</span></span>
198
+ </li>
199
+ </template>
200
+ </ul>
201
+ <div v-if="$slots && $slots.anchor" class="anchor">
202
+ <slot name="anchor" />
203
+ </div>
204
+ </div>
205
+ </template>
206
+
207
+ <style lang="scss" scoped>
208
+ .item-list-row {
209
+ margin: 5px;
210
+ padding: 5px;
211
+ position: relative;
212
+ border: 1px solid rgba(64, 158, 255, 0.4);
213
+ border-radius: 4px;
214
+
215
+ ul {
216
+ li {
217
+ white-space: nowrap;
218
+ display: flex;
219
+ align-items: center;
220
+
221
+ &:not(:last-child):after {
222
+ content: '|';
223
+ display: inline-block;
224
+ color: #9ca3af;
225
+ padding: 0 0.3rem;
226
+ }
227
+ }
228
+
229
+ .item__name {
230
+ max-width: 85px;
231
+ overflow: hidden;
232
+ white-space: nowrap;
233
+ text-overflow: ellipsis;
234
+ }
235
+ }
236
+
237
+ .anchor {
238
+ padding: 5px;
239
+ margin: -5px -5px -5px 5px;
240
+ display: flex;
241
+ flex-direction: column;
242
+ border-left: 1px solid;
243
+ border-color: inherit;
244
+ background-color: rgba(64, 158, 255, 0.2);
245
+ border-top-right-radius: inherit;
246
+ border-bottom-right-radius: inherit;
247
+ }
248
+ }
249
+ </style>
@@ -0,0 +1,105 @@
1
+ <script setup lang="ts">
2
+ // import { fileSizeFilter } from './fileSizeFilter'
3
+
4
+ defineProps<{ media: any; encoding?: boolean }>()
5
+
6
+ function fileSizeFilter(size: number) {
7
+ if (Number.isNaN(size))
8
+ size = 0
9
+
10
+ return `${(size / 1024).toFixed(2)} KB`
11
+ }
12
+ </script>
13
+
14
+ <template>
15
+ <div class="item-list-row relative inline-flex border-1px border-primary rounded-4px border-solid p-5px">
16
+ <ul class="flex flex-wrap items-center justify-center">
17
+ <template v-if="media?.name && media?.type !== 'video'">
18
+ <el-tooltip :content="$t('profile.name')" placement="top">
19
+ <li>
20
+ <el-icon>
21
+ <div class="i-ep:camera-filled text-primary" />
22
+ </el-icon>&nbsp;
23
+ <el-icon v-if="media.codec === 'copy'" class="">
24
+ <div class="i-ep:document-copy text-indigo-500" />
25
+ </el-icon>
26
+ <span v-if="media.codec === 'copy'">&nbsp;</span>
27
+ <span class="item__name">{{ (media.name) || '-' }}</span>
28
+ </li>
29
+ </el-tooltip>
30
+ </template>
31
+ <template v-if="media?.codec">
32
+ <el-tooltip content="Codec" placement="top">
33
+ <li>
34
+ <el-icon>
35
+ <div class="i-ep:grid text-indigo-500" />
36
+ </el-icon>&nbsp;
37
+ <span>{{ media.codec }}</span>
38
+ </li>
39
+ </el-tooltip>
40
+ </template>
41
+ <template v-if="media && (media.height || media.width)">
42
+ <el-tooltip content="Resolution" placement="top">
43
+ <li>
44
+ <el-icon name="crop">
45
+ <div class="i-ep:crop text-pink-600" />
46
+ </el-icon>&nbsp;
47
+ <span>{{ media.width }}x{{ media.height }}</span>
48
+ </li>
49
+ </el-tooltip>
50
+ </template>
51
+ <template v-if="media.bitrate">
52
+ <el-tooltip content="Bitrate" placement="top">
53
+ <li>
54
+ <el-icon>
55
+ <div class="i-ep:scale-to-original text-teal-600" />
56
+ </el-icon>&nbsp;
57
+ <span v-if="!encoding">{{ fileSizeFilter(media.bitrate) }}/s</span>
58
+ <span v-else>optimized</span>
59
+ </li>
60
+ </el-tooltip>
61
+ </template>
62
+ <template v-if="media.fps && media.fps !== 0">
63
+ <el-tooltip content="FPS" placement="top">
64
+ <li>
65
+ <el-icon>
66
+ <div class="i-ep:sort text-green-600" />
67
+ </el-icon>&nbsp;
68
+ <span>{{ media.fps }} fps</span>
69
+ </li>
70
+ </el-tooltip>
71
+ </template>
72
+ </ul>
73
+ </div>
74
+ </template>
75
+
76
+ <style lang="scss" scoped>
77
+ .item-list-row {
78
+ padding: 5px;
79
+ position: relative;
80
+ border: 1px solid rgba(64, 158, 255, 0.4);
81
+ border-radius: 4px;
82
+
83
+ ul {
84
+ li {
85
+ white-space: nowrap;
86
+ display: flex;
87
+ align-items: center;
88
+
89
+ &:not(:last-child):after {
90
+ content: '|';
91
+ display: inline-block;
92
+ color: #9ca3af;
93
+ padding: 0 0.3rem;
94
+ }
95
+ }
96
+
97
+ .item__name {
98
+ max-width: 85px;
99
+ overflow: hidden;
100
+ white-space: nowrap;
101
+ text-overflow: ellipsis;
102
+ }
103
+ }
104
+ }
105
+ </style>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps<{ media: any }>()
3
+ </script>
4
+
5
+ <template>
6
+ <el-popover placement="bottom" trigger="hover" width="auto">
7
+ <template #reference>
8
+ <el-tag type="info" class="mx-1 my-1">
9
+ {{ props?.media?.length ?? 0 }}
10
+ </el-tag>
11
+ </template>
12
+ <SharedMediaInfoViewer
13
+ v-for="(item, idx) in props.media || []" :key="idx" :media="item"
14
+ class="w-96% justify-center"
15
+ />
16
+ </el-popover>
17
+ </template>