unified-video-framework 1.4.100 → 1.4.102
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.
|
@@ -1890,8 +1890,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
1890
1890
|
|
|
1891
1891
|
/* Center Play Button */
|
|
1892
1892
|
.uvf-center-play-btn {
|
|
1893
|
-
width: clamp(
|
|
1894
|
-
height: clamp(
|
|
1893
|
+
width: clamp(50px, 14vw, 96px);
|
|
1894
|
+
height: clamp(50px, 14vw, 96px);
|
|
1895
1895
|
background: linear-gradient(135deg, var(--uvf-accent-1), var(--uvf-accent-2));
|
|
1896
1896
|
border: 0;
|
|
1897
1897
|
border-radius: 50%;
|
|
@@ -1981,22 +1981,24 @@ export class WebPlayer extends BasePlayer {
|
|
|
1981
1981
|
|
|
1982
1982
|
/* Progress Bar */
|
|
1983
1983
|
.uvf-progress-section {
|
|
1984
|
+
width: 100%;
|
|
1984
1985
|
margin-bottom: 15px;
|
|
1985
1986
|
}
|
|
1986
1987
|
|
|
1987
1988
|
.uvf-progress-bar-wrapper {
|
|
1988
|
-
position: relative;
|
|
1989
1989
|
width: 100%;
|
|
1990
|
-
height:
|
|
1991
|
-
|
|
1992
|
-
|
|
1990
|
+
height: 4px;
|
|
1991
|
+
position: relative;
|
|
1992
|
+
background: rgba(255,255,255,0.15);
|
|
1993
|
+
border-radius: 2px;
|
|
1993
1994
|
cursor: pointer;
|
|
1995
|
+
padding: 12px 0;
|
|
1994
1996
|
overflow: visible;
|
|
1995
|
-
transition:
|
|
1997
|
+
transition: height 0.2s ease;
|
|
1996
1998
|
}
|
|
1997
1999
|
|
|
1998
2000
|
.uvf-progress-bar-wrapper:hover {
|
|
1999
|
-
|
|
2001
|
+
height: 6px;
|
|
2000
2002
|
}
|
|
2001
2003
|
|
|
2002
2004
|
.uvf-progress-buffered {
|
|
@@ -2004,39 +2006,134 @@ export class WebPlayer extends BasePlayer {
|
|
|
2004
2006
|
top: 0;
|
|
2005
2007
|
left: 0;
|
|
2006
2008
|
height: 100%;
|
|
2007
|
-
background: rgba(255,255,255,0.
|
|
2008
|
-
border-radius:
|
|
2009
|
+
background: rgba(255,255,255,0.35);
|
|
2010
|
+
border-radius: 2px;
|
|
2009
2011
|
pointer-events: none;
|
|
2012
|
+
transition: width 0.2s ease;
|
|
2013
|
+
z-index: 1;
|
|
2010
2014
|
}
|
|
2011
2015
|
|
|
2012
2016
|
.uvf-progress-filled {
|
|
2013
|
-
position:
|
|
2014
|
-
top: 0;
|
|
2015
|
-
left: 0;
|
|
2017
|
+
position: relative;
|
|
2016
2018
|
height: 100%;
|
|
2017
|
-
background: linear-gradient(90deg,
|
|
2018
|
-
border-radius:
|
|
2019
|
+
background: linear-gradient(90deg, #ff5722, #ff7043);
|
|
2020
|
+
border-radius: 2px;
|
|
2019
2021
|
pointer-events: none;
|
|
2020
|
-
|
|
2022
|
+
transition: width 0.2s ease;
|
|
2023
|
+
z-index: 2;
|
|
2021
2024
|
}
|
|
2022
2025
|
|
|
2023
2026
|
.uvf-progress-handle {
|
|
2024
2027
|
position: absolute;
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
background: #fff;
|
|
2028
|
+
width: 12px;
|
|
2029
|
+
height: 12px;
|
|
2030
|
+
background: #ffffff;
|
|
2031
|
+
border: 2px solid #ff5722;
|
|
2030
2032
|
border-radius: 50%;
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2033
|
+
top: 50%;
|
|
2034
|
+
left: 100%;
|
|
2035
|
+
margin-left: -6px;
|
|
2036
|
+
transform: translateY(-50%);
|
|
2037
|
+
opacity: 0;
|
|
2038
|
+
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2039
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
2040
|
+
cursor: grab;
|
|
2041
|
+
z-index: 3;
|
|
2034
2042
|
}
|
|
2035
2043
|
|
|
2036
2044
|
.uvf-progress-bar-wrapper:hover .uvf-progress-handle {
|
|
2037
|
-
|
|
2045
|
+
opacity: 1;
|
|
2046
|
+
transform: translateY(-50%) scale(1);
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
.uvf-progress-handle:hover {
|
|
2050
|
+
transform: translateY(-50%) scale(1.15);
|
|
2051
|
+
box-shadow: 0 3px 12px rgba(255, 87, 34, 0.4);
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
.uvf-progress-handle:active,
|
|
2055
|
+
.uvf-progress-handle.dragging {
|
|
2056
|
+
cursor: grabbing;
|
|
2057
|
+
transform: translateY(-50%) scale(1.3);
|
|
2058
|
+
box-shadow: 0 4px 16px rgba(255, 87, 34, 0.6);
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
.uvf-time-tooltip {
|
|
2062
|
+
position: absolute;
|
|
2063
|
+
bottom: 24px;
|
|
2064
|
+
left: 50%;
|
|
2065
|
+
transform: translateX(-50%);
|
|
2066
|
+
background: rgba(0, 0, 0, 0.95);
|
|
2067
|
+
color: #ffffff;
|
|
2068
|
+
padding: 8px 14px;
|
|
2069
|
+
border-radius: 8px;
|
|
2070
|
+
font-size: 13px;
|
|
2071
|
+
font-weight: 600;
|
|
2072
|
+
white-space: nowrap;
|
|
2073
|
+
opacity: 0;
|
|
2074
|
+
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2075
|
+
pointer-events: none;
|
|
2076
|
+
z-index: 4;
|
|
2077
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
|
|
2078
|
+
backdrop-filter: blur(12px);
|
|
2079
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
.uvf-time-tooltip::after {
|
|
2083
|
+
content: '';
|
|
2084
|
+
position: absolute;
|
|
2085
|
+
bottom: -8px;
|
|
2086
|
+
left: 50%;
|
|
2087
|
+
transform: translateX(-50%);
|
|
2088
|
+
width: 0;
|
|
2089
|
+
height: 0;
|
|
2090
|
+
border-left: 8px solid transparent;
|
|
2091
|
+
border-right: 8px solid transparent;
|
|
2092
|
+
border-top: 8px solid rgba(0, 0, 0, 0.95);
|
|
2038
2093
|
}
|
|
2039
2094
|
|
|
2095
|
+
.uvf-time-tooltip::before {
|
|
2096
|
+
content: '';
|
|
2097
|
+
position: absolute;
|
|
2098
|
+
bottom: -9px;
|
|
2099
|
+
left: 50%;
|
|
2100
|
+
transform: translateX(-50%);
|
|
2101
|
+
width: 0;
|
|
2102
|
+
height: 0;
|
|
2103
|
+
border-left: 9px solid transparent;
|
|
2104
|
+
border-right: 9px solid transparent;
|
|
2105
|
+
border-top: 9px solid rgba(255, 255, 255, 0.1);
|
|
2106
|
+
z-index: -1;
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
.uvf-progress-bar-wrapper:hover .uvf-time-tooltip {
|
|
2110
|
+
opacity: 1;
|
|
2111
|
+
transform: translateX(-50%) translateY(-2px);
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
/* Mobile responsive handle sizing */
|
|
2115
|
+
@media (max-width: 768px) {
|
|
2116
|
+
.uvf-progress-handle {
|
|
2117
|
+
width: 16px;
|
|
2118
|
+
height: 16px;
|
|
2119
|
+
margin-left: -8px;
|
|
2120
|
+
opacity: 0.7; /* Slightly visible always on mobile */
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
.uvf-progress-bar-wrapper:hover .uvf-progress-handle,
|
|
2124
|
+
.uvf-progress-handle:active {
|
|
2125
|
+
opacity: 1;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
.uvf-progress-handle:hover {
|
|
2129
|
+
transform: translateY(-50%) scale(1.1);
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
.uvf-progress-handle:active,
|
|
2133
|
+
.uvf-progress-handle.dragging {
|
|
2134
|
+
transform: translateY(-50%) scale(1.25);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2040
2137
|
/* Controls Row */
|
|
2041
2138
|
.uvf-controls-row {
|
|
2042
2139
|
display: flex;
|
|
@@ -2352,7 +2449,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
2352
2449
|
right: 20px;
|
|
2353
2450
|
z-index: 10;
|
|
2354
2451
|
display: flex;
|
|
2355
|
-
|
|
2452
|
+
align-items: center;
|
|
2453
|
+
gap: 12px;
|
|
2356
2454
|
opacity: 0;
|
|
2357
2455
|
transform: translateY(-10px);
|
|
2358
2456
|
transition: all 0.3s ease;
|
|
@@ -2451,6 +2549,11 @@ export class WebPlayer extends BasePlayer {
|
|
|
2451
2549
|
padding: 4px 8px;
|
|
2452
2550
|
border-radius: 4px;
|
|
2453
2551
|
text-transform: uppercase;
|
|
2552
|
+
display: none; /* Hidden by default, only shown when quality info is available */
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
.uvf-quality-badge.active {
|
|
2556
|
+
display: inline-block;
|
|
2454
2557
|
}
|
|
2455
2558
|
|
|
2456
2559
|
/* Time Tooltip */
|
|
@@ -3583,8 +3686,8 @@ export class WebPlayer extends BasePlayer {
|
|
|
3583
3686
|
}
|
|
3584
3687
|
|
|
3585
3688
|
.uvf-center-play-btn {
|
|
3586
|
-
width: clamp(90px, 14vw,
|
|
3587
|
-
height: clamp(90px, 14vw,
|
|
3689
|
+
width: clamp(90px, 14vw, 60px);
|
|
3690
|
+
height: clamp(90px, 14vw, 60px);
|
|
3588
3691
|
background: linear-gradient(135deg, var(--uvf-accent-1), var(--uvf-accent-2));
|
|
3589
3692
|
border: 0;
|
|
3590
3693
|
box-shadow: 0 10px 32px var(--uvf-accent-1-20);
|
|
@@ -3932,8 +4035,15 @@ export class WebPlayer extends BasePlayer {
|
|
|
3932
4035
|
progressBar.id = 'uvf-progress-bar';
|
|
3933
4036
|
progressBar.innerHTML = `
|
|
3934
4037
|
<div class="uvf-progress-buffered" id="uvf-progress-buffered"></div>
|
|
3935
|
-
<div class="uvf-progress-filled" id="uvf-progress-filled"
|
|
3936
|
-
|
|
4038
|
+
<div class="uvf-progress-filled" id="uvf-progress-filled">
|
|
4039
|
+
<div class="uvf-progress-handle" id="uvf-progress-handle"
|
|
4040
|
+
role="slider"
|
|
4041
|
+
tabindex="0"
|
|
4042
|
+
aria-label="Seek"
|
|
4043
|
+
aria-valuemin="0"
|
|
4044
|
+
aria-valuemax="100"
|
|
4045
|
+
aria-valuenow="0"></div>
|
|
4046
|
+
</div>
|
|
3937
4047
|
<div class="uvf-time-tooltip" id="uvf-time-tooltip">00:00</div>
|
|
3938
4048
|
`;
|
|
3939
4049
|
progressSection.appendChild(progressBar);
|
|
@@ -4204,12 +4314,72 @@ export class WebPlayer extends BasePlayer {
|
|
|
4204
4314
|
this.handleVolumeChange(e as MouseEvent);
|
|
4205
4315
|
});
|
|
4206
4316
|
|
|
4317
|
+
|
|
4318
|
+
// Enhanced progress bar interactions
|
|
4319
|
+
const progressHandle = document.getElementById('uvf-progress-handle') as HTMLElement;
|
|
4320
|
+
const timeTooltip = document.getElementById('uvf-time-tooltip') as HTMLElement;
|
|
4321
|
+
|
|
4322
|
+
// Progress bar click
|
|
4323
|
+
progressBar?.addEventListener('click', (e) => {
|
|
4324
|
+
if (!this.isDragging) {
|
|
4325
|
+
this.handleProgressChange(e as MouseEvent);
|
|
4326
|
+
}
|
|
4327
|
+
});
|
|
4328
|
+
|
|
4329
|
+
// Handle dragging
|
|
4330
|
+
progressHandle?.addEventListener('mousedown', (e) => {
|
|
4331
|
+
e.stopPropagation();
|
|
4332
|
+
this.isDragging = true;
|
|
4333
|
+
progressHandle.classList.add('dragging');
|
|
4334
|
+
});
|
|
4335
|
+
|
|
4336
|
+
// Keyboard support for handle
|
|
4337
|
+
progressHandle?.addEventListener('keydown', (e) => {
|
|
4338
|
+
if (!this.video) return;
|
|
4339
|
+
|
|
4340
|
+
const step = 5; // 5 seconds
|
|
4341
|
+
let handled = false;
|
|
4342
|
+
|
|
4343
|
+
switch(e.key) {
|
|
4344
|
+
case 'ArrowLeft':
|
|
4345
|
+
case 'ArrowDown':
|
|
4346
|
+
this.seek(Math.max(0, this.video.currentTime - step));
|
|
4347
|
+
handled = true;
|
|
4348
|
+
break;
|
|
4349
|
+
case 'ArrowRight':
|
|
4350
|
+
case 'ArrowUp':
|
|
4351
|
+
this.seek(Math.min(this.video.duration, this.video.currentTime + step));
|
|
4352
|
+
handled = true;
|
|
4353
|
+
break;
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4356
|
+
if (handled) {
|
|
4357
|
+
e.preventDefault();
|
|
4358
|
+
e.stopPropagation();
|
|
4359
|
+
}
|
|
4360
|
+
});
|
|
4361
|
+
|
|
4362
|
+
progressBar?.addEventListener('mousedown', (e) => {
|
|
4363
|
+
if (e.target === progressHandle) return;
|
|
4364
|
+
this.isDragging = true;
|
|
4365
|
+
this.handleProgressChange(e as MouseEvent);
|
|
4366
|
+
});
|
|
4367
|
+
|
|
4368
|
+
// Mouse move handler for progress bar tooltip and dragging
|
|
4369
|
+
progressBar?.addEventListener('mousemove', (e) => {
|
|
4370
|
+
if (!this.isDragging) {
|
|
4371
|
+
this.updateTimeTooltip(e as MouseEvent);
|
|
4372
|
+
}
|
|
4373
|
+
});
|
|
4374
|
+
|
|
4375
|
+
// Global mouse events for enhanced dragging
|
|
4207
4376
|
document.addEventListener('mousemove', (e) => {
|
|
4208
4377
|
if (this.isVolumeSliding) {
|
|
4209
4378
|
this.handleVolumeChange(e);
|
|
4210
4379
|
}
|
|
4211
4380
|
if (this.isDragging && progressBar) {
|
|
4212
4381
|
this.handleProgressChange(e);
|
|
4382
|
+
this.updateProgressTooltip(e);
|
|
4213
4383
|
}
|
|
4214
4384
|
});
|
|
4215
4385
|
|
|
@@ -4222,23 +4392,26 @@ export class WebPlayer extends BasePlayer {
|
|
|
4222
4392
|
}
|
|
4223
4393
|
}, 2000);
|
|
4224
4394
|
}
|
|
4225
|
-
|
|
4395
|
+
|
|
4396
|
+
if (this.isDragging) {
|
|
4397
|
+
this.isDragging = false;
|
|
4398
|
+
progressHandle?.classList.remove('dragging');
|
|
4399
|
+
}
|
|
4226
4400
|
});
|
|
4227
4401
|
|
|
4228
|
-
// Progress bar
|
|
4229
|
-
progressBar?.addEventListener('click', (e) => this.handleProgressChange(e as MouseEvent));
|
|
4230
|
-
progressBar?.addEventListener('mousedown', () => this.isDragging = true);
|
|
4231
|
-
|
|
4232
4402
|
// Update progress bar
|
|
4233
4403
|
this.video.addEventListener('timeupdate', () => {
|
|
4234
4404
|
const progressFilled = document.getElementById('uvf-progress-filled') as HTMLElement;
|
|
4235
4405
|
const progressHandle = document.getElementById('uvf-progress-handle') as HTMLElement;
|
|
4236
|
-
const timeDisplay = document.getElementById('uvf-time-display');
|
|
4237
4406
|
|
|
4238
|
-
if (this.video && progressFilled
|
|
4407
|
+
if (this.video && progressFilled) {
|
|
4239
4408
|
const percent = (this.video.currentTime / this.video.duration) * 100;
|
|
4240
4409
|
progressFilled.style.width = percent + '%';
|
|
4241
|
-
|
|
4410
|
+
|
|
4411
|
+
// Update handle aria-valuenow for accessibility
|
|
4412
|
+
if (progressHandle) {
|
|
4413
|
+
progressHandle.setAttribute('aria-valuenow', percent.toString());
|
|
4414
|
+
}
|
|
4242
4415
|
}
|
|
4243
4416
|
|
|
4244
4417
|
// Update time display using the dedicated method
|
|
@@ -4369,9 +4542,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
4369
4542
|
}
|
|
4370
4543
|
});
|
|
4371
4544
|
|
|
4372
|
-
// Progress bar hover tooltip
|
|
4373
|
-
progressBar?.addEventListener('mousemove', (e) => this.updateTimeTooltip(e as MouseEvent));
|
|
4374
|
-
progressBar?.addEventListener('mouseleave', () => this.hideTimeTooltip());
|
|
4375
4545
|
|
|
4376
4546
|
// Settings menu - dynamically populated
|
|
4377
4547
|
const settingsMenu = document.getElementById('uvf-settings-menu');
|
|
@@ -4992,6 +5162,21 @@ export class WebPlayer extends BasePlayer {
|
|
|
4992
5162
|
timeTooltip.style.opacity = '0';
|
|
4993
5163
|
}
|
|
4994
5164
|
}
|
|
5165
|
+
|
|
5166
|
+
private updateProgressTooltip(e: MouseEvent): void {
|
|
5167
|
+
const progressBar = document.getElementById('uvf-progress-bar');
|
|
5168
|
+
const timeTooltip = document.getElementById('uvf-time-tooltip');
|
|
5169
|
+
if (!progressBar || !timeTooltip || !this.video) return;
|
|
5170
|
+
|
|
5171
|
+
const rect = progressBar.getBoundingClientRect();
|
|
5172
|
+
const position = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
|
|
5173
|
+
const percent = (position / rect.width) * 100;
|
|
5174
|
+
const time = (percent / 100) * this.video.duration;
|
|
5175
|
+
|
|
5176
|
+
timeTooltip.textContent = this.formatTime(time);
|
|
5177
|
+
timeTooltip.style.left = percent + '%';
|
|
5178
|
+
timeTooltip.style.opacity = '1';
|
|
5179
|
+
}
|
|
4995
5180
|
|
|
4996
5181
|
|
|
4997
5182
|
private showShortcutIndicator(text: string): void {
|