itube-specs 0.0.826 → 0.0.830
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.
- package/components/player/core.vue +1 -1
- package/components/player/menu.vue +203 -160
- package/package.json +1 -1
|
@@ -250,7 +250,7 @@ const options = computed<Omit<PlayerOptions, 'source'>>(() => ({
|
|
|
250
250
|
},
|
|
251
251
|
icons: PLAYER_ICONS,
|
|
252
252
|
// Заголовок дропдауна выбора типа сцен (дефолт «Scene type»).
|
|
253
|
-
labels: { sceneTypes: t('
|
|
253
|
+
labels: { sceneTypes: t('jump_to') },
|
|
254
254
|
// Запоминаем громкость/mute в localStorage.
|
|
255
255
|
persist: { key: PLAYER_PERSIST_KEY },
|
|
256
256
|
}));
|
|
@@ -3,161 +3,163 @@
|
|
|
3
3
|
колбэками, которые сами применяют выбор. Рендерим её в нашем ui-popup (--sheet).
|
|
4
4
|
Дрилл «Настройки → Скорость/Качество» — через стек drill с кнопкой «назад». -->
|
|
5
5
|
<template>
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<template #title>
|
|
15
|
-
{{ drill?.label ?? request.title }}
|
|
16
|
-
</template>
|
|
17
|
-
|
|
18
|
-
<!-- Дрилл: опции одной настройки (скорость / качество / субтитры) -->
|
|
19
|
-
<ul
|
|
20
|
-
v-if="drill"
|
|
21
|
-
class="player-menu__options"
|
|
6
|
+
<transition mode="out-in">
|
|
7
|
+
<UiPopup
|
|
8
|
+
v-if="open && request"
|
|
9
|
+
v-model="open"
|
|
10
|
+
sheet
|
|
11
|
+
:back="!!drill"
|
|
12
|
+
class="player-menu"
|
|
13
|
+
@back="drill = null"
|
|
22
14
|
>
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
<template #title>
|
|
16
|
+
{{ drill?.label ?? request.title }}
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<!-- Дрилл: опции одной настройки (скорость / качество / субтитры) -->
|
|
20
|
+
<ul
|
|
21
|
+
v-if="drill"
|
|
22
|
+
class="player-menu__options"
|
|
26
23
|
>
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
type="button"
|
|
31
|
-
@click="pick(drill.select, option.value)"
|
|
24
|
+
<li
|
|
25
|
+
v-for="option in drill.options"
|
|
26
|
+
:key="option.value"
|
|
32
27
|
>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
28
|
+
<button
|
|
29
|
+
:class="{ '--active': option.active }"
|
|
30
|
+
class="player-menu__option"
|
|
31
|
+
type="button"
|
|
32
|
+
@click="pick(drill.select, option.value)"
|
|
33
|
+
>
|
|
34
|
+
{{ option.label }}
|
|
35
|
+
</button>
|
|
36
|
+
</li>
|
|
37
|
+
</ul>
|
|
38
|
+
|
|
39
|
+
<!-- Шестерёнка: тоглы + строки-дриллы -->
|
|
40
|
+
<ul
|
|
41
|
+
v-else-if="request.kind === 'settings'"
|
|
42
|
+
class="player-menu__rows"
|
|
47
43
|
>
|
|
48
|
-
<
|
|
49
|
-
v-
|
|
50
|
-
|
|
44
|
+
<li
|
|
45
|
+
v-for="entry in request.entries"
|
|
46
|
+
:key="entry.key"
|
|
47
|
+
class="player-menu__row"
|
|
51
48
|
>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class="player-menu__row-btn"
|
|
61
|
-
type="button"
|
|
62
|
-
@click="drill = { label: entry.label, options: entry.options, select: entry.select }"
|
|
63
|
-
>
|
|
64
|
-
<span class="player-menu__label">{{ entry.label }}</span>
|
|
65
|
-
<span class="player-menu__value">
|
|
66
|
-
{{ entry.value }}
|
|
67
|
-
<UiIcon
|
|
68
|
-
name="angle-right"
|
|
69
|
-
size="16"
|
|
49
|
+
<div
|
|
50
|
+
v-if="entry.toggle"
|
|
51
|
+
class="player-menu__toggle-row"
|
|
52
|
+
>
|
|
53
|
+
<span class="player-menu__label">{{ entry.label }}</span>
|
|
54
|
+
<UiToggle
|
|
55
|
+
:model-value="entry.toggle.value"
|
|
56
|
+
@update:model-value="entry.toggle.set(!!$event)"
|
|
70
57
|
/>
|
|
71
|
-
</
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
58
|
+
</div>
|
|
59
|
+
<button
|
|
60
|
+
v-else-if="entry.options && entry.select"
|
|
61
|
+
class="player-menu__row-btn"
|
|
62
|
+
type="button"
|
|
63
|
+
@click="drill = { label: entry.label, options: entry.options, select: entry.select }"
|
|
64
|
+
>
|
|
65
|
+
<span class="player-menu__label">{{ entry.label }}</span>
|
|
66
|
+
<span class="player-menu__value">
|
|
67
|
+
{{ entry.value }}
|
|
68
|
+
<UiIcon
|
|
69
|
+
name="chevron-right"
|
|
70
|
+
size="16"
|
|
71
|
+
/>
|
|
72
|
+
</span>
|
|
73
|
+
</button>
|
|
74
|
+
<div
|
|
75
|
+
v-else
|
|
76
|
+
class="player-menu__toggle-row"
|
|
77
|
+
>
|
|
78
|
+
<span class="player-menu__label">{{ entry.label }}</span>
|
|
79
|
+
<span class="player-menu__value">{{ entry.value }}</span>
|
|
80
|
+
</div>
|
|
81
|
+
</li>
|
|
82
|
+
</ul>
|
|
83
|
+
|
|
84
|
+
<!-- Тайм-коды: аккордеон типов сцен -->
|
|
85
|
+
<ul
|
|
86
|
+
v-else-if="request.kind === 'sceneTypes'"
|
|
87
|
+
class="player-menu__groups"
|
|
91
88
|
>
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@toggle="onGroupToggle($event, group)"
|
|
89
|
+
<li
|
|
90
|
+
v-for="group in request.groups"
|
|
91
|
+
:key="group.id"
|
|
96
92
|
>
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
93
|
+
<details
|
|
94
|
+
:open="group.active"
|
|
95
|
+
class="player-menu__group"
|
|
96
|
+
@toggle="onGroupToggle($event, group)"
|
|
97
|
+
>
|
|
98
|
+
<summary class="player-menu__summary">
|
|
99
|
+
<span
|
|
100
|
+
v-if="iconSvg(group.icon)"
|
|
101
|
+
class="player-menu__summary-icon"
|
|
102
|
+
v-html="iconSvg(group.icon)"
|
|
103
|
+
/>
|
|
104
|
+
<span class="player-menu__summary-title">{{ group.title }}</span>
|
|
105
|
+
<UiIcon
|
|
106
|
+
name="chevron-down"
|
|
107
|
+
size="20"
|
|
108
|
+
class="player-menu__summary-arrow"
|
|
109
|
+
/>
|
|
110
|
+
</summary>
|
|
111
|
+
<ul class="player-menu__scenes">
|
|
112
|
+
<li
|
|
113
|
+
v-for="scene in group.scenes"
|
|
114
|
+
:key="scene.start"
|
|
115
|
+
>
|
|
116
|
+
<button
|
|
117
|
+
:class="{ '--current': scene.current }"
|
|
118
|
+
class="player-menu__scene"
|
|
119
|
+
type="button"
|
|
120
|
+
@click="selectScene(group.id, scene.start)"
|
|
121
|
+
>
|
|
122
|
+
<span class="player-menu__scene-label">{{ scene.label }}</span>
|
|
123
|
+
<span class="player-menu__scene-time">{{ scene.time }}</span>
|
|
124
|
+
</button>
|
|
125
|
+
</li>
|
|
126
|
+
</ul>
|
|
127
|
+
</details>
|
|
128
|
+
</li>
|
|
129
|
+
</ul>
|
|
130
|
+
|
|
131
|
+
<!-- ⋯ и одиночные меню (скорость/качество/субтитры, если вынесены кнопками) -->
|
|
132
|
+
<template v-else-if="request.kind === 'menu'">
|
|
133
|
+
<section
|
|
134
|
+
v-for="(section, index) in request.sections"
|
|
135
|
+
:key="index"
|
|
136
|
+
class="player-menu__section"
|
|
137
|
+
>
|
|
138
|
+
<h3
|
|
139
|
+
v-if="section.title"
|
|
140
|
+
class="player-menu__section-title"
|
|
141
|
+
>
|
|
142
|
+
{{ section.title }}
|
|
143
|
+
</h3>
|
|
144
|
+
<ul class="player-menu__options">
|
|
111
145
|
<li
|
|
112
|
-
v-for="
|
|
113
|
-
:key="
|
|
146
|
+
v-for="item in section.items"
|
|
147
|
+
:key="item.value"
|
|
114
148
|
>
|
|
115
149
|
<button
|
|
116
|
-
:class="{ '--
|
|
117
|
-
class="player-
|
|
150
|
+
:class="{ '--active': item.active }"
|
|
151
|
+
class="player-menu__option"
|
|
118
152
|
type="button"
|
|
119
|
-
@click="
|
|
153
|
+
@click="pick(section.select, item.value)"
|
|
120
154
|
>
|
|
121
|
-
|
|
122
|
-
<span class="player-menu__scene-time">{{ scene.time }}</span>
|
|
155
|
+
{{ item.label }}
|
|
123
156
|
</button>
|
|
124
157
|
</li>
|
|
125
158
|
</ul>
|
|
126
|
-
</
|
|
127
|
-
</
|
|
128
|
-
</
|
|
129
|
-
|
|
130
|
-
<!-- ⋯ и одиночные меню (скорость/качество/субтитры, если вынесены кнопками) -->
|
|
131
|
-
<template v-else-if="request.kind === 'menu'">
|
|
132
|
-
<section
|
|
133
|
-
v-for="(section, index) in request.sections"
|
|
134
|
-
:key="index"
|
|
135
|
-
class="player-menu__section"
|
|
136
|
-
>
|
|
137
|
-
<h3
|
|
138
|
-
v-if="section.title"
|
|
139
|
-
class="player-menu__section-title"
|
|
140
|
-
>
|
|
141
|
-
{{ section.title }}
|
|
142
|
-
</h3>
|
|
143
|
-
<ul class="player-menu__options">
|
|
144
|
-
<li
|
|
145
|
-
v-for="item in section.items"
|
|
146
|
-
:key="item.value"
|
|
147
|
-
>
|
|
148
|
-
<button
|
|
149
|
-
:class="{ '--active': item.active }"
|
|
150
|
-
class="player-menu__option"
|
|
151
|
-
type="button"
|
|
152
|
-
@click="pick(section.select, item.value)"
|
|
153
|
-
>
|
|
154
|
-
{{ item.label }}
|
|
155
|
-
</button>
|
|
156
|
-
</li>
|
|
157
|
-
</ul>
|
|
158
|
-
</section>
|
|
159
|
-
</template>
|
|
160
|
-
</UiPopup>
|
|
159
|
+
</section>
|
|
160
|
+
</template>
|
|
161
|
+
</UiPopup>
|
|
162
|
+
</transition>
|
|
161
163
|
</template>
|
|
162
164
|
|
|
163
165
|
<script setup lang="ts">
|
|
@@ -213,12 +215,18 @@ function onGroupToggle(event: Event, group: SceneGroup): void {
|
|
|
213
215
|
</script>
|
|
214
216
|
|
|
215
217
|
<style lang="scss">
|
|
216
|
-
// Фон шторки
|
|
218
|
+
// Фон шторки (bg-zinc-900); шапка/бордеры ui-popup уже совпадают с v0 (#0d0d0d, zinc-800).
|
|
217
219
|
.player-menu .ui-popup__wrapper,
|
|
218
220
|
.player-menu .ui-popup__content {
|
|
219
221
|
background-color: $player-menu-bg;
|
|
220
222
|
}
|
|
221
223
|
|
|
224
|
+
// Вертикальный воздух списка + safe-area снизу (py-2 pb-[env(safe-area-inset-bottom)] в v0).
|
|
225
|
+
// Сильный селектор — перебиваем padding:0 у .ui-popup--sheet на мобиле.
|
|
226
|
+
.player-menu.ui-popup[open].--sheet .ui-popup__content {
|
|
227
|
+
padding: 8px 0 calc(8px + env(safe-area-inset-bottom, 0px));
|
|
228
|
+
}
|
|
229
|
+
|
|
222
230
|
.player-menu__rows,
|
|
223
231
|
.player-menu__groups,
|
|
224
232
|
.player-menu__options {
|
|
@@ -247,14 +255,26 @@ function onGroupToggle(event: Event, group: SceneGroup): void {
|
|
|
247
255
|
}
|
|
248
256
|
}
|
|
249
257
|
|
|
258
|
+
// Без слота лейбл ui-toggle нулевой ширины → абсолютный трек уезжает за padding шторки.
|
|
259
|
+
// Резервируем ширину контрола и перекрашиваем вкл-состояние в indigo (в v0 bg-indigo-500).
|
|
260
|
+
.player-menu .ui-toggle {
|
|
261
|
+
flex-shrink: 0;
|
|
262
|
+
width: 36px;
|
|
263
|
+
height: 20px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.player-menu .ui-toggle.ui-toggle--checked::before {
|
|
267
|
+
background: $player-menu-toggle-bg--active;
|
|
268
|
+
}
|
|
269
|
+
|
|
250
270
|
.player-menu__label {
|
|
251
|
-
@include font-
|
|
271
|
+
@include font-md;
|
|
252
272
|
|
|
253
273
|
color: $player-menu-row-text;
|
|
254
274
|
}
|
|
255
275
|
|
|
256
276
|
.player-menu__value {
|
|
257
|
-
@include font-
|
|
277
|
+
@include font-md;
|
|
258
278
|
|
|
259
279
|
display: inline-flex;
|
|
260
280
|
align-items: center;
|
|
@@ -263,7 +283,7 @@ function onGroupToggle(event: Event, group: SceneGroup): void {
|
|
|
263
283
|
}
|
|
264
284
|
|
|
265
285
|
.player-menu__option {
|
|
266
|
-
@include font-
|
|
286
|
+
@include font-md;
|
|
267
287
|
|
|
268
288
|
position: relative;
|
|
269
289
|
display: flex;
|
|
@@ -301,8 +321,8 @@ function onGroupToggle(event: Event, group: SceneGroup): void {
|
|
|
301
321
|
display: flex;
|
|
302
322
|
align-items: center;
|
|
303
323
|
gap: 10px;
|
|
304
|
-
min-height:
|
|
305
|
-
padding:
|
|
324
|
+
min-height: 44px;
|
|
325
|
+
padding: 8px 20px;
|
|
306
326
|
color: $player-menu-acc-head-text;
|
|
307
327
|
cursor: pointer;
|
|
308
328
|
list-style: none;
|
|
@@ -311,6 +331,10 @@ function onGroupToggle(event: Event, group: SceneGroup): void {
|
|
|
311
331
|
&::-webkit-details-marker {
|
|
312
332
|
display: none;
|
|
313
333
|
}
|
|
334
|
+
|
|
335
|
+
@include hover(background-color) {
|
|
336
|
+
background-color: $player-menu-acc-head-bg--hover;
|
|
337
|
+
}
|
|
314
338
|
}
|
|
315
339
|
|
|
316
340
|
.player-menu__group[open] .player-menu__summary {
|
|
@@ -320,63 +344,82 @@ function onGroupToggle(event: Event, group: SceneGroup): void {
|
|
|
320
344
|
.player-menu__summary-icon {
|
|
321
345
|
display: grid;
|
|
322
346
|
place-content: center;
|
|
323
|
-
|
|
347
|
+
flex-shrink: 0;
|
|
324
348
|
|
|
325
349
|
svg {
|
|
326
|
-
width:
|
|
327
|
-
height:
|
|
350
|
+
width: 16px;
|
|
351
|
+
height: 16px;
|
|
328
352
|
}
|
|
329
353
|
}
|
|
330
354
|
|
|
331
355
|
.player-menu__summary-title {
|
|
332
|
-
@include font-
|
|
356
|
+
@include font-md;
|
|
333
357
|
|
|
334
358
|
flex: 1;
|
|
359
|
+
font-weight: 500;
|
|
335
360
|
overflow: hidden;
|
|
336
361
|
text-overflow: ellipsis;
|
|
337
362
|
white-space: nowrap;
|
|
338
363
|
}
|
|
339
364
|
|
|
340
365
|
.player-menu__summary-arrow {
|
|
366
|
+
margin-right: 12px;
|
|
341
367
|
flex-shrink: 0;
|
|
342
368
|
color: $player-menu-icon;
|
|
343
|
-
transition: transform var(--transition);
|
|
369
|
+
transition: transform var(--transition), color var(--transition);
|
|
344
370
|
}
|
|
345
371
|
|
|
346
372
|
.player-menu__group[open] .player-menu__summary-arrow {
|
|
347
|
-
|
|
373
|
+
color: $player-menu-icon--open;
|
|
374
|
+
transform: rotate(180deg);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.player-menu__scenes {
|
|
378
|
+
padding-bottom: 4px;
|
|
348
379
|
}
|
|
349
380
|
|
|
350
381
|
.player-menu__scene {
|
|
351
|
-
@include font-
|
|
382
|
+
@include font-md;
|
|
352
383
|
|
|
353
384
|
position: relative;
|
|
354
385
|
display: flex;
|
|
355
386
|
align-items: center;
|
|
356
387
|
justify-content: space-between;
|
|
357
|
-
gap:
|
|
388
|
+
gap: 12px;
|
|
358
389
|
width: 100%;
|
|
359
|
-
min-height:
|
|
360
|
-
padding:
|
|
390
|
+
min-height: 48px;
|
|
391
|
+
padding: 6px 20px 6px 56px;
|
|
361
392
|
color: $player-menu-scene-text;
|
|
362
393
|
|
|
363
|
-
@include hover(background-color
|
|
394
|
+
@include hover(background-color) {
|
|
364
395
|
background-color: $player-menu-scene-bg--hover;
|
|
365
|
-
color: $player-menu-scene-text--current;
|
|
366
396
|
}
|
|
367
397
|
}
|
|
368
398
|
|
|
369
399
|
.player-menu__scene.--current {
|
|
370
400
|
background-color: $player-menu-scene-bg--current;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.player-menu__scene.--current::before {
|
|
404
|
+
content: '';
|
|
405
|
+
position: absolute;
|
|
406
|
+
inset-block: 0;
|
|
407
|
+
left: 0;
|
|
408
|
+
width: 2px;
|
|
409
|
+
background-color: $player-menu-scene-bar--current;
|
|
374
410
|
}
|
|
375
411
|
|
|
376
412
|
.player-menu__scene-label {
|
|
413
|
+
flex: 1;
|
|
377
414
|
overflow: hidden;
|
|
378
415
|
text-overflow: ellipsis;
|
|
379
416
|
white-space: nowrap;
|
|
417
|
+
text-align: left;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.player-menu__scene.--current .player-menu__scene-label {
|
|
421
|
+
font-weight: 500;
|
|
422
|
+
color: $player-menu-scene-text--current;
|
|
380
423
|
}
|
|
381
424
|
|
|
382
425
|
.player-menu__scene-time {
|