unified-video-framework 1.4.99 → 1.4.101
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.
|
@@ -1874,14 +1874,24 @@ export class WebPlayer extends BasePlayer {
|
|
|
1874
1874
|
to { transform: rotate(360deg); }
|
|
1875
1875
|
}
|
|
1876
1876
|
|
|
1877
|
+
/* Center Play Button Container */
|
|
1878
|
+
.uvf-center-play-container {
|
|
1879
|
+
position: absolute;
|
|
1880
|
+
top: 0;
|
|
1881
|
+
left: 0;
|
|
1882
|
+
width: 100%;
|
|
1883
|
+
height: 100%;
|
|
1884
|
+
display: flex;
|
|
1885
|
+
align-items: center;
|
|
1886
|
+
justify-content: center;
|
|
1887
|
+
pointer-events: none;
|
|
1888
|
+
z-index: 8;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1877
1891
|
/* Center Play Button */
|
|
1878
1892
|
.uvf-center-play-btn {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
left: 50%;
|
|
1882
|
-
transform: translate(-50%, -50%);
|
|
1883
|
-
width: clamp(64px, 14vw, 96px);
|
|
1884
|
-
height: clamp(64px, 14vw, 96px);
|
|
1893
|
+
width: clamp(50px, 14vw, 96px);
|
|
1894
|
+
height: clamp(50px, 14vw, 96px);
|
|
1885
1895
|
background: linear-gradient(135deg, var(--uvf-accent-1), var(--uvf-accent-2));
|
|
1886
1896
|
border: 0;
|
|
1887
1897
|
border-radius: 50%;
|
|
@@ -1889,15 +1899,15 @@ export class WebPlayer extends BasePlayer {
|
|
|
1889
1899
|
align-items: center;
|
|
1890
1900
|
justify-content: center;
|
|
1891
1901
|
cursor: pointer;
|
|
1902
|
+
pointer-events: auto;
|
|
1892
1903
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
1893
|
-
z-index: 8;
|
|
1894
1904
|
opacity: 1;
|
|
1895
1905
|
visibility: visible;
|
|
1896
1906
|
box-shadow: 0 8px 28px var(--uvf-accent-1-20);
|
|
1897
1907
|
}
|
|
1898
1908
|
|
|
1899
1909
|
.uvf-center-play-btn:hover {
|
|
1900
|
-
transform:
|
|
1910
|
+
transform: scale(1.06);
|
|
1901
1911
|
filter: saturate(1.08) brightness(1.05);
|
|
1902
1912
|
box-shadow: 0 12px 36px var(--uvf-accent-1-20);
|
|
1903
1913
|
}
|
|
@@ -1905,7 +1915,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
1905
1915
|
.uvf-center-play-btn.hidden {
|
|
1906
1916
|
opacity: 0 !important;
|
|
1907
1917
|
visibility: hidden !important;
|
|
1908
|
-
transform:
|
|
1918
|
+
transform: scale(0.8) !important;
|
|
1909
1919
|
pointer-events: none !important;
|
|
1910
1920
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
1911
1921
|
}
|
|
@@ -1971,22 +1981,24 @@ export class WebPlayer extends BasePlayer {
|
|
|
1971
1981
|
|
|
1972
1982
|
/* Progress Bar */
|
|
1973
1983
|
.uvf-progress-section {
|
|
1984
|
+
width: 100%;
|
|
1974
1985
|
margin-bottom: 15px;
|
|
1975
1986
|
}
|
|
1976
1987
|
|
|
1977
1988
|
.uvf-progress-bar-wrapper {
|
|
1978
|
-
position: relative;
|
|
1979
1989
|
width: 100%;
|
|
1980
|
-
height:
|
|
1981
|
-
|
|
1982
|
-
|
|
1990
|
+
height: 5px;
|
|
1991
|
+
position: relative;
|
|
1992
|
+
background: rgba(255,255,255,0.15);
|
|
1993
|
+
border-radius: 2px;
|
|
1983
1994
|
cursor: pointer;
|
|
1995
|
+
padding: 12px 0;
|
|
1984
1996
|
overflow: visible;
|
|
1985
|
-
transition:
|
|
1997
|
+
transition: height 0.2s ease;
|
|
1986
1998
|
}
|
|
1987
1999
|
|
|
1988
2000
|
.uvf-progress-bar-wrapper:hover {
|
|
1989
|
-
|
|
2001
|
+
height: 7px;
|
|
1990
2002
|
}
|
|
1991
2003
|
|
|
1992
2004
|
.uvf-progress-buffered {
|
|
@@ -1994,39 +2006,106 @@ export class WebPlayer extends BasePlayer {
|
|
|
1994
2006
|
top: 0;
|
|
1995
2007
|
left: 0;
|
|
1996
2008
|
height: 100%;
|
|
1997
|
-
background: rgba(255,255,255,0.
|
|
1998
|
-
border-radius:
|
|
2009
|
+
background: rgba(255,255,255,0.3);
|
|
2010
|
+
border-radius: 2px;
|
|
1999
2011
|
pointer-events: none;
|
|
2012
|
+
transition: width 0.2s ease;
|
|
2013
|
+
z-index: 1;
|
|
2000
2014
|
}
|
|
2001
2015
|
|
|
2002
2016
|
.uvf-progress-filled {
|
|
2003
|
-
position:
|
|
2004
|
-
top: 0;
|
|
2005
|
-
left: 0;
|
|
2017
|
+
position: relative;
|
|
2006
2018
|
height: 100%;
|
|
2007
|
-
background: linear-gradient(90deg,
|
|
2008
|
-
border-radius:
|
|
2019
|
+
background: linear-gradient(90deg, #ff5722, #ff7043);
|
|
2020
|
+
border-radius: 2px;
|
|
2009
2021
|
pointer-events: none;
|
|
2010
|
-
|
|
2022
|
+
transition: width 0.2s ease;
|
|
2023
|
+
z-index: 2;
|
|
2011
2024
|
}
|
|
2012
2025
|
|
|
2013
2026
|
.uvf-progress-handle {
|
|
2014
2027
|
position: absolute;
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
background: #fff;
|
|
2028
|
+
width: 14px;
|
|
2029
|
+
height: 14px;
|
|
2030
|
+
background: #ffffff;
|
|
2031
|
+
border: 2px solid #ff5722;
|
|
2020
2032
|
border-radius: 50%;
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2033
|
+
top: 50%;
|
|
2034
|
+
left: 100%;
|
|
2035
|
+
transform: translate(-50%, -50%) scale(0.8);
|
|
2036
|
+
opacity: 0;
|
|
2037
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2038
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
|
|
2039
|
+
cursor: grab;
|
|
2040
|
+
z-index: 3;
|
|
2024
2041
|
}
|
|
2025
2042
|
|
|
2026
2043
|
.uvf-progress-bar-wrapper:hover .uvf-progress-handle {
|
|
2044
|
+
opacity: 1;
|
|
2027
2045
|
transform: translate(-50%, -50%) scale(1);
|
|
2028
2046
|
}
|
|
2029
2047
|
|
|
2048
|
+
.uvf-progress-handle:hover {
|
|
2049
|
+
transform: translate(-50%, -50%) scale(1.2);
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
.uvf-progress-handle:active,
|
|
2053
|
+
.uvf-progress-handle.dragging {
|
|
2054
|
+
cursor: grabbing;
|
|
2055
|
+
transform: translate(-50%, -50%) scale(1.4);
|
|
2056
|
+
box-shadow: 0 4px 16px rgba(255, 87, 34, 0.6);
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
.uvf-time-tooltip {
|
|
2060
|
+
position: absolute;
|
|
2061
|
+
bottom: 22px;
|
|
2062
|
+
left: 50%;
|
|
2063
|
+
transform: translateX(-50%);
|
|
2064
|
+
background: rgba(0, 0, 0, 0.92);
|
|
2065
|
+
color: #ffffff;
|
|
2066
|
+
padding: 6px 12px;
|
|
2067
|
+
border-radius: 6px;
|
|
2068
|
+
font-size: 13px;
|
|
2069
|
+
font-weight: 500;
|
|
2070
|
+
white-space: nowrap;
|
|
2071
|
+
opacity: 0;
|
|
2072
|
+
transition: opacity 0.2s ease;
|
|
2073
|
+
pointer-events: none;
|
|
2074
|
+
z-index: 4;
|
|
2075
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
2076
|
+
backdrop-filter: blur(10px);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
.uvf-time-tooltip::after {
|
|
2080
|
+
content: '';
|
|
2081
|
+
position: absolute;
|
|
2082
|
+
bottom: -5px;
|
|
2083
|
+
left: 50%;
|
|
2084
|
+
transform: translateX(-50%);
|
|
2085
|
+
width: 0;
|
|
2086
|
+
height: 0;
|
|
2087
|
+
border-left: 6px solid transparent;
|
|
2088
|
+
border-right: 6px solid transparent;
|
|
2089
|
+
border-top: 6px solid rgba(0, 0, 0, 0.92);
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
.uvf-progress-bar-wrapper:hover .uvf-time-tooltip {
|
|
2093
|
+
opacity: 1;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
/* Mobile responsive handle sizing */
|
|
2097
|
+
@media (max-width: 768px) {
|
|
2098
|
+
.uvf-progress-handle {
|
|
2099
|
+
width: 18px;
|
|
2100
|
+
height: 18px;
|
|
2101
|
+
opacity: 0.8; /* Slightly visible always on mobile */
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
.uvf-progress-bar-wrapper:hover .uvf-progress-handle,
|
|
2105
|
+
.uvf-progress-handle:active {
|
|
2106
|
+
opacity: 1;
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2030
2109
|
/* Controls Row */
|
|
2031
2110
|
.uvf-controls-row {
|
|
2032
2111
|
display: flex;
|
|
@@ -3006,7 +3085,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
3006
3085
|
}
|
|
3007
3086
|
|
|
3008
3087
|
.uvf-center-play-btn:hover {
|
|
3009
|
-
transform:
|
|
3088
|
+
transform: scale(1.06);
|
|
3010
3089
|
filter: saturate(1.08) brightness(1.05);
|
|
3011
3090
|
box-shadow: 0 14px 36px var(--uvf-accent-1-20);
|
|
3012
3091
|
}
|
|
@@ -3305,7 +3384,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
3305
3384
|
}
|
|
3306
3385
|
|
|
3307
3386
|
.uvf-center-play-btn:hover {
|
|
3308
|
-
transform:
|
|
3387
|
+
transform: scale(1.06);
|
|
3309
3388
|
filter: saturate(1.08) brightness(1.05);
|
|
3310
3389
|
box-shadow: 0 12px 32px var(--uvf-accent-1-20);
|
|
3311
3390
|
}
|
|
@@ -3477,7 +3556,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
3477
3556
|
}
|
|
3478
3557
|
|
|
3479
3558
|
.uvf-center-play-btn:hover {
|
|
3480
|
-
transform:
|
|
3559
|
+
transform: scale(1.06);
|
|
3481
3560
|
filter: saturate(1.08) brightness(1.05);
|
|
3482
3561
|
box-shadow: 0 12px 36px var(--uvf-accent-1-20);
|
|
3483
3562
|
}
|
|
@@ -3573,15 +3652,15 @@ export class WebPlayer extends BasePlayer {
|
|
|
3573
3652
|
}
|
|
3574
3653
|
|
|
3575
3654
|
.uvf-center-play-btn {
|
|
3576
|
-
width: clamp(90px, 14vw,
|
|
3577
|
-
height: clamp(90px, 14vw,
|
|
3655
|
+
width: clamp(90px, 14vw, 60px);
|
|
3656
|
+
height: clamp(90px, 14vw, 60px);
|
|
3578
3657
|
background: linear-gradient(135deg, var(--uvf-accent-1), var(--uvf-accent-2));
|
|
3579
3658
|
border: 0;
|
|
3580
3659
|
box-shadow: 0 10px 32px var(--uvf-accent-1-20);
|
|
3581
3660
|
}
|
|
3582
3661
|
|
|
3583
3662
|
.uvf-center-play-btn:hover {
|
|
3584
|
-
transform:
|
|
3663
|
+
transform: scale(1.06);
|
|
3585
3664
|
filter: saturate(1.08) brightness(1.05);
|
|
3586
3665
|
box-shadow: 0 16px 40px var(--uvf-accent-1-20);
|
|
3587
3666
|
}
|
|
@@ -3890,12 +3969,17 @@ export class WebPlayer extends BasePlayer {
|
|
|
3890
3969
|
loadingContainer.innerHTML = '<div class="uvf-loading-spinner"></div>';
|
|
3891
3970
|
container.appendChild(loadingContainer);
|
|
3892
3971
|
|
|
3893
|
-
// Add center play button
|
|
3972
|
+
// Add center play button container for proper responsive centering
|
|
3973
|
+
const centerPlayContainer = document.createElement('div');
|
|
3974
|
+
centerPlayContainer.className = 'uvf-center-play-container';
|
|
3975
|
+
|
|
3894
3976
|
const centerPlayBtn = document.createElement('div');
|
|
3895
3977
|
centerPlayBtn.className = 'uvf-center-play-btn uvf-pulse';
|
|
3896
3978
|
centerPlayBtn.id = 'uvf-center-play';
|
|
3897
3979
|
centerPlayBtn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
|
|
3898
|
-
|
|
3980
|
+
|
|
3981
|
+
centerPlayContainer.appendChild(centerPlayBtn);
|
|
3982
|
+
container.appendChild(centerPlayContainer);
|
|
3899
3983
|
|
|
3900
3984
|
// Add shortcut indicator
|
|
3901
3985
|
const shortcutIndicator = document.createElement('div');
|
|
@@ -3917,8 +4001,15 @@ export class WebPlayer extends BasePlayer {
|
|
|
3917
4001
|
progressBar.id = 'uvf-progress-bar';
|
|
3918
4002
|
progressBar.innerHTML = `
|
|
3919
4003
|
<div class="uvf-progress-buffered" id="uvf-progress-buffered"></div>
|
|
3920
|
-
<div class="uvf-progress-filled" id="uvf-progress-filled"
|
|
3921
|
-
|
|
4004
|
+
<div class="uvf-progress-filled" id="uvf-progress-filled">
|
|
4005
|
+
<div class="uvf-progress-handle" id="uvf-progress-handle"
|
|
4006
|
+
role="slider"
|
|
4007
|
+
tabindex="0"
|
|
4008
|
+
aria-label="Seek"
|
|
4009
|
+
aria-valuemin="0"
|
|
4010
|
+
aria-valuemax="100"
|
|
4011
|
+
aria-valuenow="0"></div>
|
|
4012
|
+
</div>
|
|
3922
4013
|
<div class="uvf-time-tooltip" id="uvf-time-tooltip">00:00</div>
|
|
3923
4014
|
`;
|
|
3924
4015
|
progressSection.appendChild(progressBar);
|
|
@@ -4189,12 +4280,72 @@ export class WebPlayer extends BasePlayer {
|
|
|
4189
4280
|
this.handleVolumeChange(e as MouseEvent);
|
|
4190
4281
|
});
|
|
4191
4282
|
|
|
4283
|
+
|
|
4284
|
+
// Enhanced progress bar interactions
|
|
4285
|
+
const progressHandle = document.getElementById('uvf-progress-handle') as HTMLElement;
|
|
4286
|
+
const timeTooltip = document.getElementById('uvf-time-tooltip') as HTMLElement;
|
|
4287
|
+
|
|
4288
|
+
// Progress bar click
|
|
4289
|
+
progressBar?.addEventListener('click', (e) => {
|
|
4290
|
+
if (!this.isDragging) {
|
|
4291
|
+
this.handleProgressChange(e as MouseEvent);
|
|
4292
|
+
}
|
|
4293
|
+
});
|
|
4294
|
+
|
|
4295
|
+
// Handle dragging
|
|
4296
|
+
progressHandle?.addEventListener('mousedown', (e) => {
|
|
4297
|
+
e.stopPropagation();
|
|
4298
|
+
this.isDragging = true;
|
|
4299
|
+
progressHandle.classList.add('dragging');
|
|
4300
|
+
});
|
|
4301
|
+
|
|
4302
|
+
// Keyboard support for handle
|
|
4303
|
+
progressHandle?.addEventListener('keydown', (e) => {
|
|
4304
|
+
if (!this.video) return;
|
|
4305
|
+
|
|
4306
|
+
const step = 5; // 5 seconds
|
|
4307
|
+
let handled = false;
|
|
4308
|
+
|
|
4309
|
+
switch(e.key) {
|
|
4310
|
+
case 'ArrowLeft':
|
|
4311
|
+
case 'ArrowDown':
|
|
4312
|
+
this.seek(Math.max(0, this.video.currentTime - step));
|
|
4313
|
+
handled = true;
|
|
4314
|
+
break;
|
|
4315
|
+
case 'ArrowRight':
|
|
4316
|
+
case 'ArrowUp':
|
|
4317
|
+
this.seek(Math.min(this.video.duration, this.video.currentTime + step));
|
|
4318
|
+
handled = true;
|
|
4319
|
+
break;
|
|
4320
|
+
}
|
|
4321
|
+
|
|
4322
|
+
if (handled) {
|
|
4323
|
+
e.preventDefault();
|
|
4324
|
+
e.stopPropagation();
|
|
4325
|
+
}
|
|
4326
|
+
});
|
|
4327
|
+
|
|
4328
|
+
progressBar?.addEventListener('mousedown', (e) => {
|
|
4329
|
+
if (e.target === progressHandle) return;
|
|
4330
|
+
this.isDragging = true;
|
|
4331
|
+
this.handleProgressChange(e as MouseEvent);
|
|
4332
|
+
});
|
|
4333
|
+
|
|
4334
|
+
// Mouse move handler for progress bar tooltip and dragging
|
|
4335
|
+
progressBar?.addEventListener('mousemove', (e) => {
|
|
4336
|
+
if (!this.isDragging) {
|
|
4337
|
+
this.updateTimeTooltip(e as MouseEvent);
|
|
4338
|
+
}
|
|
4339
|
+
});
|
|
4340
|
+
|
|
4341
|
+
// Global mouse events for enhanced dragging
|
|
4192
4342
|
document.addEventListener('mousemove', (e) => {
|
|
4193
4343
|
if (this.isVolumeSliding) {
|
|
4194
4344
|
this.handleVolumeChange(e);
|
|
4195
4345
|
}
|
|
4196
4346
|
if (this.isDragging && progressBar) {
|
|
4197
4347
|
this.handleProgressChange(e);
|
|
4348
|
+
this.updateProgressTooltip(e);
|
|
4198
4349
|
}
|
|
4199
4350
|
});
|
|
4200
4351
|
|
|
@@ -4207,23 +4358,26 @@ export class WebPlayer extends BasePlayer {
|
|
|
4207
4358
|
}
|
|
4208
4359
|
}, 2000);
|
|
4209
4360
|
}
|
|
4210
|
-
|
|
4361
|
+
|
|
4362
|
+
if (this.isDragging) {
|
|
4363
|
+
this.isDragging = false;
|
|
4364
|
+
progressHandle?.classList.remove('dragging');
|
|
4365
|
+
}
|
|
4211
4366
|
});
|
|
4212
4367
|
|
|
4213
|
-
// Progress bar
|
|
4214
|
-
progressBar?.addEventListener('click', (e) => this.handleProgressChange(e as MouseEvent));
|
|
4215
|
-
progressBar?.addEventListener('mousedown', () => this.isDragging = true);
|
|
4216
|
-
|
|
4217
4368
|
// Update progress bar
|
|
4218
4369
|
this.video.addEventListener('timeupdate', () => {
|
|
4219
4370
|
const progressFilled = document.getElementById('uvf-progress-filled') as HTMLElement;
|
|
4220
4371
|
const progressHandle = document.getElementById('uvf-progress-handle') as HTMLElement;
|
|
4221
|
-
const timeDisplay = document.getElementById('uvf-time-display');
|
|
4222
4372
|
|
|
4223
|
-
if (this.video && progressFilled
|
|
4373
|
+
if (this.video && progressFilled) {
|
|
4224
4374
|
const percent = (this.video.currentTime / this.video.duration) * 100;
|
|
4225
4375
|
progressFilled.style.width = percent + '%';
|
|
4226
|
-
|
|
4376
|
+
|
|
4377
|
+
// Update handle aria-valuenow for accessibility
|
|
4378
|
+
if (progressHandle) {
|
|
4379
|
+
progressHandle.setAttribute('aria-valuenow', percent.toString());
|
|
4380
|
+
}
|
|
4227
4381
|
}
|
|
4228
4382
|
|
|
4229
4383
|
// Update time display using the dedicated method
|
|
@@ -4354,9 +4508,6 @@ export class WebPlayer extends BasePlayer {
|
|
|
4354
4508
|
}
|
|
4355
4509
|
});
|
|
4356
4510
|
|
|
4357
|
-
// Progress bar hover tooltip
|
|
4358
|
-
progressBar?.addEventListener('mousemove', (e) => this.updateTimeTooltip(e as MouseEvent));
|
|
4359
|
-
progressBar?.addEventListener('mouseleave', () => this.hideTimeTooltip());
|
|
4360
4511
|
|
|
4361
4512
|
// Settings menu - dynamically populated
|
|
4362
4513
|
const settingsMenu = document.getElementById('uvf-settings-menu');
|
|
@@ -4977,6 +5128,21 @@ export class WebPlayer extends BasePlayer {
|
|
|
4977
5128
|
timeTooltip.style.opacity = '0';
|
|
4978
5129
|
}
|
|
4979
5130
|
}
|
|
5131
|
+
|
|
5132
|
+
private updateProgressTooltip(e: MouseEvent): void {
|
|
5133
|
+
const progressBar = document.getElementById('uvf-progress-bar');
|
|
5134
|
+
const timeTooltip = document.getElementById('uvf-time-tooltip');
|
|
5135
|
+
if (!progressBar || !timeTooltip || !this.video) return;
|
|
5136
|
+
|
|
5137
|
+
const rect = progressBar.getBoundingClientRect();
|
|
5138
|
+
const position = Math.max(0, Math.min(e.clientX - rect.left, rect.width));
|
|
5139
|
+
const percent = (position / rect.width) * 100;
|
|
5140
|
+
const time = (percent / 100) * this.video.duration;
|
|
5141
|
+
|
|
5142
|
+
timeTooltip.textContent = this.formatTime(time);
|
|
5143
|
+
timeTooltip.style.left = percent + '%';
|
|
5144
|
+
timeTooltip.style.opacity = '1';
|
|
5145
|
+
}
|
|
4980
5146
|
|
|
4981
5147
|
|
|
4982
5148
|
private showShortcutIndicator(text: string): void {
|