unified-video-framework 1.4.208 → 1.4.210
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/package.json +1 -1
- package/packages/core/dist/BasePlayer.d.ts +6 -5
- package/packages/core/dist/BasePlayer.d.ts.map +1 -1
- package/packages/core/dist/BasePlayer.js.map +1 -1
- package/packages/core/dist/VideoPlayer.js +1 -1
- package/packages/core/dist/VideoPlayer.js.map +1 -1
- package/packages/core/dist/interfaces/IVideoPlayer.d.ts +5 -3
- package/packages/core/dist/interfaces/IVideoPlayer.d.ts.map +1 -1
- package/packages/core/dist/interfaces.d.ts +26 -1
- package/packages/core/dist/interfaces.d.ts.map +1 -1
- package/packages/core/src/BasePlayer.ts +5 -5
- package/packages/core/src/VideoPlayer.ts +1 -1
- package/packages/core/src/interfaces/IVideoPlayer.ts +6 -3
- package/packages/core/src/interfaces.ts +60 -26
- package/packages/web/dist/WebPlayer.d.ts +8 -0
- package/packages/web/dist/WebPlayer.d.ts.map +1 -1
- package/packages/web/dist/WebPlayer.js +557 -36
- package/packages/web/dist/WebPlayer.js.map +1 -1
- package/packages/web/dist/react/components/EPGOverlay-improved-positioning.d.ts.map +1 -1
- package/packages/web/dist/react/components/EPGOverlay-improved-positioning.js +0 -8
- package/packages/web/dist/react/components/EPGOverlay-improved-positioning.js.map +1 -1
- package/packages/web/dist/react/components/EPGOverlay.d.ts.map +1 -1
- package/packages/web/dist/react/components/EPGOverlay.js +0 -8
- package/packages/web/dist/react/components/EPGOverlay.js.map +1 -1
- package/packages/web/src/WebPlayer.ts +651 -41
- package/packages/web/src/react/components/EPGOverlay-improved-positioning.tsx +0 -8
- package/packages/web/src/react/components/EPGOverlay.tsx +0 -8
|
@@ -882,7 +882,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
882
882
|
}
|
|
883
883
|
setupClickToUnmute() {
|
|
884
884
|
if (this.clickToUnmuteHandler) {
|
|
885
|
-
this.playerWrapper?.removeEventListener('click', this.clickToUnmuteHandler);
|
|
885
|
+
this.playerWrapper?.removeEventListener('click', this.clickToUnmuteHandler, true);
|
|
886
886
|
}
|
|
887
887
|
this.clickToUnmuteHandler = (e) => {
|
|
888
888
|
const unmuteBtn = document.getElementById('uvf-unmute-btn');
|
|
@@ -894,15 +894,17 @@ export class WebPlayer extends BasePlayer {
|
|
|
894
894
|
target.closest('.uvf-settings-menu')) {
|
|
895
895
|
return;
|
|
896
896
|
}
|
|
897
|
+
e.stopPropagation();
|
|
898
|
+
e.preventDefault();
|
|
897
899
|
this.video.muted = false;
|
|
898
900
|
this.debugLog('🔊 Video unmuted by clicking on player');
|
|
899
901
|
this.hideUnmuteButton();
|
|
900
902
|
if (this.clickToUnmuteHandler) {
|
|
901
|
-
this.playerWrapper?.removeEventListener('click', this.clickToUnmuteHandler);
|
|
903
|
+
this.playerWrapper?.removeEventListener('click', this.clickToUnmuteHandler, true);
|
|
902
904
|
this.clickToUnmuteHandler = null;
|
|
903
905
|
}
|
|
904
906
|
};
|
|
905
|
-
this.playerWrapper?.addEventListener('click', this.clickToUnmuteHandler);
|
|
907
|
+
this.playerWrapper?.addEventListener('click', this.clickToUnmuteHandler, true);
|
|
906
908
|
this.debugLog('👆 Click anywhere to unmute enabled');
|
|
907
909
|
}
|
|
908
910
|
hideUnmuteButton() {
|
|
@@ -912,7 +914,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
912
914
|
this.debugLog('Unmute button removed');
|
|
913
915
|
}
|
|
914
916
|
if (this.clickToUnmuteHandler) {
|
|
915
|
-
this.playerWrapper?.removeEventListener('click', this.clickToUnmuteHandler);
|
|
917
|
+
this.playerWrapper?.removeEventListener('click', this.clickToUnmuteHandler, true);
|
|
916
918
|
this.clickToUnmuteHandler = null;
|
|
917
919
|
}
|
|
918
920
|
}
|
|
@@ -2717,6 +2719,37 @@ export class WebPlayer extends BasePlayer {
|
|
|
2717
2719
|
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4));
|
|
2718
2720
|
}
|
|
2719
2721
|
|
|
2722
|
+
/* PiP Button Specific Styling */
|
|
2723
|
+
#uvf-pip-btn {
|
|
2724
|
+
background: var(--uvf-button-bg);
|
|
2725
|
+
border: 1px solid var(--uvf-button-border);
|
|
2726
|
+
position: relative;
|
|
2727
|
+
z-index: 10;
|
|
2728
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
#uvf-pip-btn:hover {
|
|
2732
|
+
transform: scale(1.08);
|
|
2733
|
+
box-shadow: 0 4px 12px var(--uvf-button-shadow);
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
#uvf-pip-btn:active {
|
|
2737
|
+
transform: scale(0.95);
|
|
2738
|
+
transition: all 0.1s ease;
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
#uvf-pip-btn svg {
|
|
2742
|
+
opacity: 0.9;
|
|
2743
|
+
transition: all 0.3s ease;
|
|
2744
|
+
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.3));
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
#uvf-pip-btn:hover svg {
|
|
2748
|
+
opacity: 1;
|
|
2749
|
+
transform: scale(1.05);
|
|
2750
|
+
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.4));
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2720
2753
|
/* Fullscreen Button Specific Styling */
|
|
2721
2754
|
#uvf-fullscreen-btn {
|
|
2722
2755
|
background: var(--uvf-button-bg);
|
|
@@ -3220,7 +3253,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
3220
3253
|
margin-left: 10px;
|
|
3221
3254
|
}
|
|
3222
3255
|
|
|
3223
|
-
/* Top Bar Container - Contains Title (left) and Controls (right) */
|
|
3256
|
+
/* Top Bar Container - Contains Navigation + Title (left) and Controls (right) */
|
|
3224
3257
|
.uvf-top-bar {
|
|
3225
3258
|
position: absolute;
|
|
3226
3259
|
top: 0;
|
|
@@ -3237,16 +3270,97 @@ export class WebPlayer extends BasePlayer {
|
|
|
3237
3270
|
transition: all 0.3s ease;
|
|
3238
3271
|
}
|
|
3239
3272
|
|
|
3273
|
+
/* Left side container for navigation + title */
|
|
3274
|
+
.uvf-left-side {
|
|
3275
|
+
display: flex;
|
|
3276
|
+
align-items: center;
|
|
3277
|
+
gap: 12px;
|
|
3278
|
+
flex: 1;
|
|
3279
|
+
max-width: 70%;
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
/* Navigation controls container */
|
|
3283
|
+
.uvf-navigation-controls {
|
|
3284
|
+
display: flex;
|
|
3285
|
+
align-items: center;
|
|
3286
|
+
gap: 8px;
|
|
3287
|
+
flex-shrink: 0;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
/* Navigation button styles */
|
|
3291
|
+
.uvf-nav-btn {
|
|
3292
|
+
width: 40px;
|
|
3293
|
+
height: 40px;
|
|
3294
|
+
min-width: 40px;
|
|
3295
|
+
min-height: 40px;
|
|
3296
|
+
border-radius: 50%;
|
|
3297
|
+
background: rgba(0, 0, 0, 0.6);
|
|
3298
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
3299
|
+
color: white;
|
|
3300
|
+
cursor: pointer;
|
|
3301
|
+
display: flex;
|
|
3302
|
+
align-items: center;
|
|
3303
|
+
justify-content: center;
|
|
3304
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
3305
|
+
backdrop-filter: blur(8px);
|
|
3306
|
+
position: relative;
|
|
3307
|
+
overflow: hidden;
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
.uvf-nav-btn:hover {
|
|
3311
|
+
background: rgba(255, 255, 255, 0.15);
|
|
3312
|
+
border-color: rgba(255, 255, 255, 0.4);
|
|
3313
|
+
transform: scale(1.05);
|
|
3314
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
3315
|
+
}
|
|
3316
|
+
|
|
3317
|
+
.uvf-nav-btn:active {
|
|
3318
|
+
transform: scale(0.95);
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
.uvf-nav-btn svg {
|
|
3322
|
+
width: 20px;
|
|
3323
|
+
height: 20px;
|
|
3324
|
+
fill: currentColor;
|
|
3325
|
+
transition: all 0.2s ease;
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
.uvf-nav-btn:hover svg {
|
|
3329
|
+
transform: scale(1.1);
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
/* Back button specific styles */
|
|
3333
|
+
#uvf-back-btn {
|
|
3334
|
+
background: rgba(0, 0, 0, 0.7);
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
#uvf-back-btn:hover {
|
|
3338
|
+
background: rgba(255, 255, 255, 0.2);
|
|
3339
|
+
border-color: var(--uvf-accent-1, #ff0000);
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
/* Close button specific styles */
|
|
3343
|
+
#uvf-close-btn {
|
|
3344
|
+
background: rgba(220, 53, 69, 0.8);
|
|
3345
|
+
border-color: rgba(220, 53, 69, 0.6);
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
#uvf-close-btn:hover {
|
|
3349
|
+
background: rgba(220, 53, 69, 1);
|
|
3350
|
+
border-color: rgba(220, 53, 69, 1);
|
|
3351
|
+
box-shadow: 0 4px 12px rgba(220, 53, 69, 0.4);
|
|
3352
|
+
}
|
|
3353
|
+
|
|
3240
3354
|
.uvf-player-wrapper:hover .uvf-top-bar,
|
|
3241
3355
|
.uvf-player-wrapper.controls-visible .uvf-top-bar {
|
|
3242
3356
|
opacity: 1;
|
|
3243
3357
|
transform: translateY(0);
|
|
3244
3358
|
}
|
|
3245
3359
|
|
|
3246
|
-
/* Title Bar -
|
|
3360
|
+
/* Title Bar - After navigation buttons */
|
|
3247
3361
|
.uvf-title-bar {
|
|
3248
|
-
flex:
|
|
3249
|
-
|
|
3362
|
+
flex: 1;
|
|
3363
|
+
min-width: 0; /* Allow shrinking */
|
|
3250
3364
|
}
|
|
3251
3365
|
|
|
3252
3366
|
/* Top Controls - Right side of top bar */
|
|
@@ -3261,33 +3375,112 @@ export class WebPlayer extends BasePlayer {
|
|
|
3261
3375
|
.uvf-title-content {
|
|
3262
3376
|
display: flex;
|
|
3263
3377
|
align-items: center;
|
|
3264
|
-
|
|
3378
|
+
width: 100%;
|
|
3379
|
+
min-width: 0; /* Allow shrinking */
|
|
3265
3380
|
}
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
border: 1px solid rgba(255,255,255,0.25);
|
|
3273
|
-
background: rgba(255,255,255,0.05);
|
|
3381
|
+
|
|
3382
|
+
.uvf-title-text {
|
|
3383
|
+
display: flex;
|
|
3384
|
+
flex-direction: column;
|
|
3385
|
+
min-width: 0; /* Allow shrinking */
|
|
3386
|
+
flex: 1;
|
|
3274
3387
|
}
|
|
3275
|
-
|
|
3388
|
+
|
|
3276
3389
|
.uvf-video-title {
|
|
3277
3390
|
color: var(--uvf-text-primary);
|
|
3278
|
-
font-size: 18px;
|
|
3391
|
+
font-size: clamp(14px, 2.5vw, 18px); /* Responsive font size */
|
|
3279
3392
|
font-weight: 600;
|
|
3280
3393
|
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
|
|
3394
|
+
line-height: 1.3;
|
|
3395
|
+
overflow: hidden;
|
|
3396
|
+
text-overflow: ellipsis;
|
|
3397
|
+
white-space: nowrap;
|
|
3398
|
+
max-width: 100%;
|
|
3399
|
+
cursor: pointer;
|
|
3400
|
+
transition: color 0.3s ease;
|
|
3401
|
+
position: relative;
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
.uvf-video-title:hover {
|
|
3405
|
+
color: var(--uvf-accent-1, #ff0000);
|
|
3281
3406
|
}
|
|
3282
3407
|
|
|
3283
3408
|
.uvf-video-subtitle {
|
|
3284
3409
|
color: var(--uvf-text-secondary);
|
|
3285
|
-
font-size: 13px;
|
|
3286
|
-
margin-top:
|
|
3287
|
-
max-width: min(70vw, 900px);
|
|
3410
|
+
font-size: clamp(11px, 1.8vw, 13px); /* Responsive font size */
|
|
3411
|
+
margin-top: 2px;
|
|
3288
3412
|
overflow: hidden;
|
|
3289
3413
|
text-overflow: ellipsis;
|
|
3290
3414
|
white-space: nowrap;
|
|
3415
|
+
max-width: 100%;
|
|
3416
|
+
opacity: 0.9;
|
|
3417
|
+
line-height: 1.4;
|
|
3418
|
+
cursor: pointer;
|
|
3419
|
+
transition: opacity 0.3s ease;
|
|
3420
|
+
position: relative;
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
.uvf-video-subtitle:hover {
|
|
3424
|
+
opacity: 1;
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
/* Tooltip for long text */
|
|
3428
|
+
.uvf-text-tooltip {
|
|
3429
|
+
position: absolute;
|
|
3430
|
+
bottom: 100%;
|
|
3431
|
+
left: 0;
|
|
3432
|
+
background: rgba(0, 0, 0, 0.9);
|
|
3433
|
+
color: white;
|
|
3434
|
+
padding: 8px 12px;
|
|
3435
|
+
border-radius: 6px;
|
|
3436
|
+
font-size: 13px;
|
|
3437
|
+
line-height: 1.4;
|
|
3438
|
+
max-width: 400px;
|
|
3439
|
+
word-wrap: break-word;
|
|
3440
|
+
white-space: normal;
|
|
3441
|
+
z-index: 1000;
|
|
3442
|
+
opacity: 0;
|
|
3443
|
+
visibility: hidden;
|
|
3444
|
+
transform: translateY(-5px);
|
|
3445
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
3446
|
+
pointer-events: none;
|
|
3447
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
3448
|
+
backdrop-filter: blur(8px);
|
|
3449
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
|
3450
|
+
}
|
|
3451
|
+
|
|
3452
|
+
.uvf-text-tooltip::before {
|
|
3453
|
+
content: '';
|
|
3454
|
+
position: absolute;
|
|
3455
|
+
top: 100%;
|
|
3456
|
+
left: 12px;
|
|
3457
|
+
border: 5px solid transparent;
|
|
3458
|
+
border-top-color: rgba(0, 0, 0, 0.9);
|
|
3459
|
+
}
|
|
3460
|
+
|
|
3461
|
+
.uvf-text-tooltip.show {
|
|
3462
|
+
opacity: 1;
|
|
3463
|
+
visibility: visible;
|
|
3464
|
+
transform: translateY(0);
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
/* Multi-line title option for desktop */
|
|
3468
|
+
.uvf-video-title.multiline {
|
|
3469
|
+
white-space: normal;
|
|
3470
|
+
display: -webkit-box;
|
|
3471
|
+
-webkit-line-clamp: 2;
|
|
3472
|
+
-webkit-box-orient: vertical;
|
|
3473
|
+
line-height: 1.2;
|
|
3474
|
+
max-height: 2.4em;
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
.uvf-video-subtitle.multiline {
|
|
3478
|
+
white-space: normal;
|
|
3479
|
+
display: -webkit-box;
|
|
3480
|
+
-webkit-line-clamp: 3;
|
|
3481
|
+
-webkit-box-orient: vertical;
|
|
3482
|
+
line-height: 1.3;
|
|
3483
|
+
max-height: 3.9em;
|
|
3291
3484
|
}
|
|
3292
3485
|
|
|
3293
3486
|
/* Above seekbar section with time and branding */
|
|
@@ -3366,7 +3559,21 @@ export class WebPlayer extends BasePlayer {
|
|
|
3366
3559
|
}
|
|
3367
3560
|
}
|
|
3368
3561
|
|
|
3562
|
+
/* Ultra small screens */
|
|
3369
3563
|
@media (max-width: 480px) {
|
|
3564
|
+
.uvf-video-title {
|
|
3565
|
+
font-size: clamp(11px, 3.5vw, 14px) !important;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
.uvf-video-subtitle {
|
|
3569
|
+
font-size: clamp(9px, 2.5vw, 11px) !important;
|
|
3570
|
+
-webkit-line-clamp: 1; /* Single line on very small screens */
|
|
3571
|
+
}
|
|
3572
|
+
|
|
3573
|
+
.uvf-left-side {
|
|
3574
|
+
max-width: 80%;
|
|
3575
|
+
}
|
|
3576
|
+
|
|
3370
3577
|
.uvf-above-seekbar-section {
|
|
3371
3578
|
margin-bottom: 5px;
|
|
3372
3579
|
}
|
|
@@ -3754,6 +3961,47 @@ export class WebPlayer extends BasePlayer {
|
|
|
3754
3961
|
}
|
|
3755
3962
|
|
|
3756
3963
|
|
|
3964
|
+
/* Mobile responsive styles for navigation buttons */
|
|
3965
|
+
@media screen and (max-width: 767px) {
|
|
3966
|
+
.uvf-nav-btn {
|
|
3967
|
+
width: 36px;
|
|
3968
|
+
height: 36px;
|
|
3969
|
+
min-width: 36px;
|
|
3970
|
+
min-height: 36px;
|
|
3971
|
+
}
|
|
3972
|
+
|
|
3973
|
+
.uvf-nav-btn svg {
|
|
3974
|
+
width: 18px;
|
|
3975
|
+
height: 18px;
|
|
3976
|
+
}
|
|
3977
|
+
|
|
3978
|
+
.uvf-navigation-controls {
|
|
3979
|
+
gap: 6px;
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
.uvf-left-side {
|
|
3983
|
+
gap: 8px;
|
|
3984
|
+
max-width: 75%;
|
|
3985
|
+
}
|
|
3986
|
+
|
|
3987
|
+
/* Mobile title adjustments */
|
|
3988
|
+
.uvf-video-title {
|
|
3989
|
+
font-size: clamp(12px, 3vw, 16px) !important;
|
|
3990
|
+
line-height: 1.2;
|
|
3991
|
+
}
|
|
3992
|
+
|
|
3993
|
+
.uvf-video-subtitle {
|
|
3994
|
+
font-size: clamp(10px, 2.2vw, 12px) !important;
|
|
3995
|
+
margin-top: 1px;
|
|
3996
|
+
/* Allow wrapping on mobile if needed */
|
|
3997
|
+
white-space: normal;
|
|
3998
|
+
display: -webkit-box;
|
|
3999
|
+
-webkit-line-clamp: 2;
|
|
4000
|
+
-webkit-box-orient: vertical;
|
|
4001
|
+
overflow: hidden;
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
|
|
3757
4005
|
/* Mobile portrait - hide skip buttons, ensure top bar visible */
|
|
3758
4006
|
@media screen and (max-width: 767px) and (orientation: portrait) {
|
|
3759
4007
|
#uvf-skip-back,
|
|
@@ -3921,6 +4169,31 @@ export class WebPlayer extends BasePlayer {
|
|
|
3921
4169
|
|
|
3922
4170
|
/* Tablet devices - Enhanced UX with desktop features */
|
|
3923
4171
|
@media screen and (min-width: 768px) and (max-width: 1023px) {
|
|
4172
|
+
/* Tablet navigation and title adjustments */
|
|
4173
|
+
.uvf-nav-btn {
|
|
4174
|
+
width: 38px;
|
|
4175
|
+
height: 38px;
|
|
4176
|
+
min-width: 38px;
|
|
4177
|
+
min-height: 38px;
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
.uvf-nav-btn svg {
|
|
4181
|
+
width: 19px;
|
|
4182
|
+
height: 19px;
|
|
4183
|
+
}
|
|
4184
|
+
|
|
4185
|
+
.uvf-left-side {
|
|
4186
|
+
max-width: 70%;
|
|
4187
|
+
}
|
|
4188
|
+
|
|
4189
|
+
.uvf-video-title {
|
|
4190
|
+
font-size: clamp(15px, 2.2vw, 17px) !important;
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
.uvf-video-subtitle {
|
|
4194
|
+
font-size: clamp(12px, 1.8vw, 13px) !important;
|
|
4195
|
+
}
|
|
4196
|
+
|
|
3924
4197
|
.uvf-controls-bar {
|
|
3925
4198
|
padding: 18px 16px;
|
|
3926
4199
|
background: linear-gradient(to top, var(--uvf-overlay-strong) 0%, var(--uvf-overlay-medium) 70%, var(--uvf-overlay-transparent) 100%);
|
|
@@ -4453,6 +4726,40 @@ export class WebPlayer extends BasePlayer {
|
|
|
4453
4726
|
}
|
|
4454
4727
|
}
|
|
4455
4728
|
|
|
4729
|
+
/* Desktop styles for title and navigation */
|
|
4730
|
+
@media screen and (min-width: 1024px) {
|
|
4731
|
+
.uvf-left-side {
|
|
4732
|
+
max-width: 65%; /* More space for title on desktop */
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
.uvf-video-title {
|
|
4736
|
+
font-size: clamp(16px, 1.8vw, 20px) !important;
|
|
4737
|
+
font-weight: 700; /* Bolder on desktop */
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
.uvf-video-subtitle {
|
|
4741
|
+
font-size: clamp(13px, 1.4vw, 15px) !important;
|
|
4742
|
+
margin-top: 3px;
|
|
4743
|
+
}
|
|
4744
|
+
|
|
4745
|
+
/* Allow hover effects on desktop */
|
|
4746
|
+
.uvf-title-bar:hover .uvf-video-title {
|
|
4747
|
+
color: var(--uvf-accent-1, #ff0000);
|
|
4748
|
+
transition: color 0.3s ease;
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
/* Ultra-wide screens */
|
|
4753
|
+
@media screen and (min-width: 1440px) {
|
|
4754
|
+
.uvf-video-title {
|
|
4755
|
+
font-size: clamp(18px, 1.6vw, 22px) !important;
|
|
4756
|
+
}
|
|
4757
|
+
|
|
4758
|
+
.uvf-video-subtitle {
|
|
4759
|
+
font-size: clamp(14px, 1.2vw, 16px) !important;
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
|
|
4456
4763
|
/* Paywall Desktop */
|
|
4457
4764
|
@media screen and (min-width: 1024px) {
|
|
4458
4765
|
.uvf-paywall-modal {
|
|
@@ -4511,6 +4818,100 @@ export class WebPlayer extends BasePlayer {
|
|
|
4511
4818
|
container.appendChild(brandingContainer);
|
|
4512
4819
|
this.debugLog('Framework branding added');
|
|
4513
4820
|
}
|
|
4821
|
+
createNavigationButtons(container) {
|
|
4822
|
+
const navigationConfig = this.config.navigation;
|
|
4823
|
+
if (!navigationConfig)
|
|
4824
|
+
return;
|
|
4825
|
+
const { backButton, closeButton } = navigationConfig;
|
|
4826
|
+
if (backButton?.enabled) {
|
|
4827
|
+
const backBtn = document.createElement('button');
|
|
4828
|
+
backBtn.className = 'uvf-control-btn uvf-nav-btn';
|
|
4829
|
+
backBtn.id = 'uvf-back-btn';
|
|
4830
|
+
backBtn.title = backButton.title || 'Back';
|
|
4831
|
+
backBtn.setAttribute('aria-label', backButton.ariaLabel || 'Go back');
|
|
4832
|
+
const backIcon = this.getNavigationIcon(backButton.icon || 'arrow', backButton.customIcon);
|
|
4833
|
+
backBtn.innerHTML = backIcon;
|
|
4834
|
+
backBtn.addEventListener('click', async (e) => {
|
|
4835
|
+
e.preventDefault();
|
|
4836
|
+
e.stopPropagation();
|
|
4837
|
+
if (backButton.onClick) {
|
|
4838
|
+
await backButton.onClick();
|
|
4839
|
+
}
|
|
4840
|
+
else if (backButton.href) {
|
|
4841
|
+
if (backButton.replace) {
|
|
4842
|
+
window.history.replaceState(null, '', backButton.href);
|
|
4843
|
+
}
|
|
4844
|
+
else {
|
|
4845
|
+
window.location.href = backButton.href;
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
else {
|
|
4849
|
+
window.history.back();
|
|
4850
|
+
}
|
|
4851
|
+
this.emit('navigationBackClicked');
|
|
4852
|
+
});
|
|
4853
|
+
container.appendChild(backBtn);
|
|
4854
|
+
}
|
|
4855
|
+
if (closeButton?.enabled) {
|
|
4856
|
+
const closeBtn = document.createElement('button');
|
|
4857
|
+
closeBtn.className = 'uvf-control-btn uvf-nav-btn';
|
|
4858
|
+
closeBtn.id = 'uvf-close-btn';
|
|
4859
|
+
closeBtn.title = closeButton.title || 'Close';
|
|
4860
|
+
closeBtn.setAttribute('aria-label', closeButton.ariaLabel || 'Close player');
|
|
4861
|
+
const closeIcon = this.getNavigationIcon(closeButton.icon || 'x', closeButton.customIcon);
|
|
4862
|
+
closeBtn.innerHTML = closeIcon;
|
|
4863
|
+
closeBtn.addEventListener('click', async (e) => {
|
|
4864
|
+
e.preventDefault();
|
|
4865
|
+
e.stopPropagation();
|
|
4866
|
+
if (closeButton.onClick) {
|
|
4867
|
+
await closeButton.onClick();
|
|
4868
|
+
}
|
|
4869
|
+
else {
|
|
4870
|
+
if (closeButton.exitFullscreen && this.isFullscreen()) {
|
|
4871
|
+
await this.exitFullscreen();
|
|
4872
|
+
}
|
|
4873
|
+
if (closeButton.closeModal) {
|
|
4874
|
+
const playerWrapper = this.container?.querySelector('.uvf-player-wrapper');
|
|
4875
|
+
if (playerWrapper) {
|
|
4876
|
+
playerWrapper.style.display = 'none';
|
|
4877
|
+
}
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4880
|
+
this.emit('navigationCloseClicked');
|
|
4881
|
+
});
|
|
4882
|
+
container.appendChild(closeBtn);
|
|
4883
|
+
}
|
|
4884
|
+
}
|
|
4885
|
+
getNavigationIcon(iconType, customIcon) {
|
|
4886
|
+
if (customIcon) {
|
|
4887
|
+
if (customIcon.startsWith('http') || customIcon.includes('.')) {
|
|
4888
|
+
return `<img src="${customIcon}" alt="" style="width: 20px; height: 20px;" />`;
|
|
4889
|
+
}
|
|
4890
|
+
return customIcon;
|
|
4891
|
+
}
|
|
4892
|
+
switch (iconType) {
|
|
4893
|
+
case 'arrow':
|
|
4894
|
+
return `<svg viewBox="0 0 24 24">
|
|
4895
|
+
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.42-1.41L7.83 13H20v-2z" fill="currentColor"/>
|
|
4896
|
+
</svg>`;
|
|
4897
|
+
case 'chevron':
|
|
4898
|
+
return `<svg viewBox="0 0 24 24">
|
|
4899
|
+
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" fill="currentColor"/>
|
|
4900
|
+
</svg>`;
|
|
4901
|
+
case 'x':
|
|
4902
|
+
return `<svg viewBox="0 0 24 24">
|
|
4903
|
+
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" fill="currentColor"/>
|
|
4904
|
+
</svg>`;
|
|
4905
|
+
case 'close':
|
|
4906
|
+
return `<svg viewBox="0 0 24 24">
|
|
4907
|
+
<path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z" fill="currentColor"/>
|
|
4908
|
+
</svg>`;
|
|
4909
|
+
default:
|
|
4910
|
+
return `<svg viewBox="0 0 24 24">
|
|
4911
|
+
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.42-1.41L7.83 13H20v-2z" fill="currentColor"/>
|
|
4912
|
+
</svg>`;
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4514
4915
|
createCustomControls(container) {
|
|
4515
4916
|
const topGradient = document.createElement('div');
|
|
4516
4917
|
topGradient.className = 'uvf-top-gradient';
|
|
@@ -4520,18 +4921,24 @@ export class WebPlayer extends BasePlayer {
|
|
|
4520
4921
|
container.appendChild(controlsGradient);
|
|
4521
4922
|
const topBar = document.createElement('div');
|
|
4522
4923
|
topBar.className = 'uvf-top-bar';
|
|
4924
|
+
const leftSide = document.createElement('div');
|
|
4925
|
+
leftSide.className = 'uvf-left-side';
|
|
4926
|
+
const navigationControls = document.createElement('div');
|
|
4927
|
+
navigationControls.className = 'uvf-navigation-controls';
|
|
4928
|
+
this.createNavigationButtons(navigationControls);
|
|
4929
|
+
leftSide.appendChild(navigationControls);
|
|
4523
4930
|
const titleBar = document.createElement('div');
|
|
4524
4931
|
titleBar.className = 'uvf-title-bar';
|
|
4525
4932
|
titleBar.innerHTML = `
|
|
4526
4933
|
<div class="uvf-title-content">
|
|
4527
|
-
<img class="uvf-video-thumb" id="uvf-video-thumb" alt="thumbnail" style="display:none;" />
|
|
4528
4934
|
<div class="uvf-title-text">
|
|
4529
4935
|
<div class=\"uvf-video-title\" id=\"uvf-video-title\" style=\"display:none;\"></div>
|
|
4530
4936
|
<div class=\"uvf-video-subtitle\" id=\"uvf-video-description\" style=\"display:none;\"></div>
|
|
4531
4937
|
</div>
|
|
4532
4938
|
</div>
|
|
4533
4939
|
`;
|
|
4534
|
-
|
|
4940
|
+
leftSide.appendChild(titleBar);
|
|
4941
|
+
topBar.appendChild(leftSide);
|
|
4535
4942
|
const topControls = document.createElement('div');
|
|
4536
4943
|
topControls.className = 'uvf-top-controls';
|
|
4537
4944
|
topControls.innerHTML = `
|
|
@@ -5192,11 +5599,13 @@ export class WebPlayer extends BasePlayer {
|
|
|
5192
5599
|
break;
|
|
5193
5600
|
case 'ArrowLeft':
|
|
5194
5601
|
e.preventDefault();
|
|
5602
|
+
e.stopImmediatePropagation();
|
|
5195
5603
|
this.seek(Math.max(0, this.video.currentTime - 10));
|
|
5196
5604
|
shortcutText = '-10s';
|
|
5197
5605
|
break;
|
|
5198
5606
|
case 'ArrowRight':
|
|
5199
5607
|
e.preventDefault();
|
|
5608
|
+
e.stopImmediatePropagation();
|
|
5200
5609
|
this.seek(Math.min(this.video.duration, this.video.currentTime + 10));
|
|
5201
5610
|
shortcutText = '+10s';
|
|
5202
5611
|
break;
|
|
@@ -6177,7 +6586,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
6177
6586
|
autoSkip: this.chapterConfig.userPreferences?.autoSkipIntro || false,
|
|
6178
6587
|
onChapterChange: (chapter) => {
|
|
6179
6588
|
this.debugLog('Core chapter changed:', chapter?.title || 'none');
|
|
6180
|
-
this.emit('
|
|
6589
|
+
this.emit('onChapterchange', chapter);
|
|
6181
6590
|
},
|
|
6182
6591
|
onSegmentEntered: (segment) => {
|
|
6183
6592
|
this.debugLog('Core segment entered:', segment.title);
|
|
@@ -7290,6 +7699,123 @@ export class WebPlayer extends BasePlayer {
|
|
|
7290
7699
|
this.showNotification('Share failed');
|
|
7291
7700
|
}
|
|
7292
7701
|
}
|
|
7702
|
+
isTextTruncated(element) {
|
|
7703
|
+
return element.scrollWidth > element.offsetWidth || element.scrollHeight > element.offsetHeight;
|
|
7704
|
+
}
|
|
7705
|
+
showTextTooltip(element, text) {
|
|
7706
|
+
const existingTooltip = element.querySelector('.uvf-text-tooltip');
|
|
7707
|
+
if (existingTooltip) {
|
|
7708
|
+
existingTooltip.remove();
|
|
7709
|
+
}
|
|
7710
|
+
const tooltip = document.createElement('div');
|
|
7711
|
+
tooltip.className = 'uvf-text-tooltip';
|
|
7712
|
+
tooltip.textContent = text;
|
|
7713
|
+
element.appendChild(tooltip);
|
|
7714
|
+
setTimeout(() => {
|
|
7715
|
+
tooltip.classList.add('show');
|
|
7716
|
+
}, 100);
|
|
7717
|
+
}
|
|
7718
|
+
hideTextTooltip(element) {
|
|
7719
|
+
const tooltip = element.querySelector('.uvf-text-tooltip');
|
|
7720
|
+
if (tooltip) {
|
|
7721
|
+
tooltip.classList.remove('show');
|
|
7722
|
+
setTimeout(() => {
|
|
7723
|
+
if (tooltip.parentElement) {
|
|
7724
|
+
tooltip.remove();
|
|
7725
|
+
}
|
|
7726
|
+
}, 300);
|
|
7727
|
+
}
|
|
7728
|
+
}
|
|
7729
|
+
setupTextTooltips() {
|
|
7730
|
+
const titleElement = document.getElementById('uvf-video-title');
|
|
7731
|
+
const descElement = document.getElementById('uvf-video-description');
|
|
7732
|
+
if (titleElement) {
|
|
7733
|
+
titleElement.addEventListener('mouseenter', () => {
|
|
7734
|
+
const titleText = (this.source?.metadata?.title || '').toString().trim();
|
|
7735
|
+
if (this.isTextTruncated(titleElement) && titleText) {
|
|
7736
|
+
this.showTextTooltip(titleElement, titleText);
|
|
7737
|
+
}
|
|
7738
|
+
});
|
|
7739
|
+
titleElement.addEventListener('mouseleave', () => {
|
|
7740
|
+
this.hideTextTooltip(titleElement);
|
|
7741
|
+
});
|
|
7742
|
+
titleElement.addEventListener('touchstart', () => {
|
|
7743
|
+
const titleText = (this.source?.metadata?.title || '').toString().trim();
|
|
7744
|
+
if (this.isTextTruncated(titleElement) && titleText) {
|
|
7745
|
+
this.showTextTooltip(titleElement, titleText);
|
|
7746
|
+
setTimeout(() => {
|
|
7747
|
+
this.hideTextTooltip(titleElement);
|
|
7748
|
+
}, 3000);
|
|
7749
|
+
}
|
|
7750
|
+
});
|
|
7751
|
+
}
|
|
7752
|
+
if (descElement) {
|
|
7753
|
+
descElement.addEventListener('mouseenter', () => {
|
|
7754
|
+
const descText = (this.source?.metadata?.description || '').toString().trim();
|
|
7755
|
+
if (this.isTextTruncated(descElement) && descText) {
|
|
7756
|
+
this.showTextTooltip(descElement, descText);
|
|
7757
|
+
}
|
|
7758
|
+
});
|
|
7759
|
+
descElement.addEventListener('mouseleave', () => {
|
|
7760
|
+
this.hideTextTooltip(descElement);
|
|
7761
|
+
});
|
|
7762
|
+
descElement.addEventListener('touchstart', () => {
|
|
7763
|
+
const descText = (this.source?.metadata?.description || '').toString().trim();
|
|
7764
|
+
if (this.isTextTruncated(descElement) && descText) {
|
|
7765
|
+
this.showTextTooltip(descElement, descText);
|
|
7766
|
+
setTimeout(() => {
|
|
7767
|
+
this.hideTextTooltip(descElement);
|
|
7768
|
+
}, 3000);
|
|
7769
|
+
}
|
|
7770
|
+
});
|
|
7771
|
+
}
|
|
7772
|
+
}
|
|
7773
|
+
smartTruncateText(text, maxWords = 12) {
|
|
7774
|
+
const words = text.split(' ');
|
|
7775
|
+
if (words.length <= maxWords) {
|
|
7776
|
+
return { truncated: text, needsTooltip: false };
|
|
7777
|
+
}
|
|
7778
|
+
const truncated = words.slice(0, maxWords).join(' ') + '...';
|
|
7779
|
+
return { truncated, needsTooltip: true };
|
|
7780
|
+
}
|
|
7781
|
+
applySmartTextDisplay(titleEl, descEl, titleText, descText) {
|
|
7782
|
+
const isDesktop = window.innerWidth >= 1024;
|
|
7783
|
+
const isMobile = window.innerWidth < 768;
|
|
7784
|
+
if (titleEl && titleText) {
|
|
7785
|
+
const wordCount = titleText.split(' ').length;
|
|
7786
|
+
if (isDesktop && wordCount > 8 && wordCount <= 15) {
|
|
7787
|
+
titleEl.classList.add('multiline');
|
|
7788
|
+
titleEl.textContent = titleText;
|
|
7789
|
+
}
|
|
7790
|
+
else if (wordCount > 12) {
|
|
7791
|
+
const maxWords = isMobile ? 8 : isDesktop ? 12 : 10;
|
|
7792
|
+
const { truncated } = this.smartTruncateText(titleText, maxWords);
|
|
7793
|
+
titleEl.textContent = truncated;
|
|
7794
|
+
titleEl.classList.remove('multiline');
|
|
7795
|
+
}
|
|
7796
|
+
else {
|
|
7797
|
+
titleEl.textContent = titleText;
|
|
7798
|
+
titleEl.classList.remove('multiline');
|
|
7799
|
+
}
|
|
7800
|
+
}
|
|
7801
|
+
if (descEl && descText) {
|
|
7802
|
+
const wordCount = descText.split(' ').length;
|
|
7803
|
+
if (isDesktop && wordCount > 15 && wordCount <= 25) {
|
|
7804
|
+
descEl.classList.add('multiline');
|
|
7805
|
+
descEl.textContent = descText;
|
|
7806
|
+
}
|
|
7807
|
+
else if (wordCount > 20) {
|
|
7808
|
+
const maxWords = isMobile ? 12 : isDesktop ? 18 : 15;
|
|
7809
|
+
const { truncated } = this.smartTruncateText(descText, maxWords);
|
|
7810
|
+
descEl.textContent = truncated;
|
|
7811
|
+
descEl.classList.remove('multiline');
|
|
7812
|
+
}
|
|
7813
|
+
else {
|
|
7814
|
+
descEl.textContent = descText;
|
|
7815
|
+
descEl.classList.remove('multiline');
|
|
7816
|
+
}
|
|
7817
|
+
}
|
|
7818
|
+
}
|
|
7293
7819
|
updateMetadataUI() {
|
|
7294
7820
|
try {
|
|
7295
7821
|
const md = this.source?.metadata || {};
|
|
@@ -7300,28 +7826,23 @@ export class WebPlayer extends BasePlayer {
|
|
|
7300
7826
|
const titleText = (md.title || '').toString().trim();
|
|
7301
7827
|
const descText = (md.description || '').toString().trim();
|
|
7302
7828
|
const thumbUrl = (md.thumbnailUrl || '').toString().trim();
|
|
7829
|
+
this.applySmartTextDisplay(titleEl, descEl, titleText, descText);
|
|
7303
7830
|
if (titleEl) {
|
|
7304
|
-
titleEl.textContent = titleText;
|
|
7305
7831
|
titleEl.style.display = titleText ? 'block' : 'none';
|
|
7306
7832
|
}
|
|
7307
7833
|
if (descEl) {
|
|
7308
|
-
descEl.textContent = descText;
|
|
7309
7834
|
descEl.style.display = descText ? 'block' : 'none';
|
|
7310
7835
|
}
|
|
7311
7836
|
if (thumbEl) {
|
|
7312
|
-
|
|
7313
|
-
thumbEl.src = thumbUrl;
|
|
7314
|
-
thumbEl.style.display = 'block';
|
|
7315
|
-
}
|
|
7316
|
-
else {
|
|
7317
|
-
thumbEl.removeAttribute('src');
|
|
7318
|
-
thumbEl.style.display = 'none';
|
|
7319
|
-
}
|
|
7837
|
+
thumbEl.style.display = 'none';
|
|
7320
7838
|
}
|
|
7321
|
-
const hasAny = !!(titleText || descText
|
|
7839
|
+
const hasAny = !!(titleText || descText);
|
|
7322
7840
|
if (titleBar) {
|
|
7323
7841
|
titleBar.style.display = hasAny ? '' : 'none';
|
|
7324
7842
|
}
|
|
7843
|
+
setTimeout(() => {
|
|
7844
|
+
this.setupTextTooltips();
|
|
7845
|
+
}, 100);
|
|
7325
7846
|
}
|
|
7326
7847
|
catch (_) { }
|
|
7327
7848
|
}
|