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
- position: absolute;
1880
- top: 50%;
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: translate(-50%, -50%) scale(1.06);
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: translate(-50%, -50%) scale(0.8) !important;
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: 6px;
1981
- background: rgba(255,255,255,0.1);
1982
- border-radius: 3px;
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: transform 0.2s ease;
1997
+ transition: height 0.2s ease;
1986
1998
  }
1987
1999
 
1988
2000
  .uvf-progress-bar-wrapper:hover {
1989
- transform: scaleY(1.5);
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.2);
1998
- border-radius: 3px;
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: absolute;
2004
- top: 0;
2005
- left: 0;
2017
+ position: relative;
2006
2018
  height: 100%;
2007
- background: linear-gradient(90deg, var(--uvf-accent-1), var(--uvf-accent-2));
2008
- border-radius: 3px;
2019
+ background: linear-gradient(90deg, #ff5722, #ff7043);
2020
+ border-radius: 2px;
2009
2021
  pointer-events: none;
2010
- box-shadow: 0 0 10px var(--uvf-accent-1-20);
2022
+ transition: width 0.2s ease;
2023
+ z-index: 2;
2011
2024
  }
2012
2025
 
2013
2026
  .uvf-progress-handle {
2014
2027
  position: absolute;
2015
- top: 50%;
2016
- transform: translate(-50%, -50%) scale(0);
2017
- width: 16px;
2018
- height: 16px;
2019
- background: #fff;
2028
+ width: 14px;
2029
+ height: 14px;
2030
+ background: #ffffff;
2031
+ border: 2px solid #ff5722;
2020
2032
  border-radius: 50%;
2021
- box-shadow: 0 0 15px rgba(255,255,255,0.5);
2022
- transition: transform 0.2s ease;
2023
- pointer-events: none;
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: translate(-50%, -50%) scale(1.06);
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: translate(-50%, -50%) scale(1.06);
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: translate(-50%, -50%) scale(1.06);
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, 110px);
3577
- height: clamp(90px, 14vw, 110px);
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: translate(-50%, -50%) scale(1.06);
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 with pulse animation
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
- container.appendChild(centerPlayBtn);
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"></div>
3921
- <div class="uvf-progress-handle" id="uvf-progress-handle"></div>
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
- this.isDragging = false;
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 && progressHandle) {
4373
+ if (this.video && progressFilled) {
4224
4374
  const percent = (this.video.currentTime / this.video.duration) * 100;
4225
4375
  progressFilled.style.width = percent + '%';
4226
- progressHandle.style.left = percent + '%';
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 {