unified-video-framework 1.4.209 → 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 +520 -32
- 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 +611 -37
- package/packages/web/src/react/components/EPGOverlay-improved-positioning.tsx +0 -8
- package/packages/web/src/react/components/EPGOverlay.tsx +0 -8
|
@@ -3253,7 +3253,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
3253
3253
|
margin-left: 10px;
|
|
3254
3254
|
}
|
|
3255
3255
|
|
|
3256
|
-
/* Top Bar Container - Contains Title (left) and Controls (right) */
|
|
3256
|
+
/* Top Bar Container - Contains Navigation + Title (left) and Controls (right) */
|
|
3257
3257
|
.uvf-top-bar {
|
|
3258
3258
|
position: absolute;
|
|
3259
3259
|
top: 0;
|
|
@@ -3270,16 +3270,97 @@ export class WebPlayer extends BasePlayer {
|
|
|
3270
3270
|
transition: all 0.3s ease;
|
|
3271
3271
|
}
|
|
3272
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
|
+
|
|
3273
3354
|
.uvf-player-wrapper:hover .uvf-top-bar,
|
|
3274
3355
|
.uvf-player-wrapper.controls-visible .uvf-top-bar {
|
|
3275
3356
|
opacity: 1;
|
|
3276
3357
|
transform: translateY(0);
|
|
3277
3358
|
}
|
|
3278
3359
|
|
|
3279
|
-
/* Title Bar -
|
|
3360
|
+
/* Title Bar - After navigation buttons */
|
|
3280
3361
|
.uvf-title-bar {
|
|
3281
|
-
flex:
|
|
3282
|
-
|
|
3362
|
+
flex: 1;
|
|
3363
|
+
min-width: 0; /* Allow shrinking */
|
|
3283
3364
|
}
|
|
3284
3365
|
|
|
3285
3366
|
/* Top Controls - Right side of top bar */
|
|
@@ -3294,33 +3375,112 @@ export class WebPlayer extends BasePlayer {
|
|
|
3294
3375
|
.uvf-title-content {
|
|
3295
3376
|
display: flex;
|
|
3296
3377
|
align-items: center;
|
|
3297
|
-
|
|
3378
|
+
width: 100%;
|
|
3379
|
+
min-width: 0; /* Allow shrinking */
|
|
3298
3380
|
}
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
border: 1px solid rgba(255,255,255,0.25);
|
|
3306
|
-
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;
|
|
3307
3387
|
}
|
|
3308
|
-
|
|
3388
|
+
|
|
3309
3389
|
.uvf-video-title {
|
|
3310
3390
|
color: var(--uvf-text-primary);
|
|
3311
|
-
font-size: 18px;
|
|
3391
|
+
font-size: clamp(14px, 2.5vw, 18px); /* Responsive font size */
|
|
3312
3392
|
font-weight: 600;
|
|
3313
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);
|
|
3314
3406
|
}
|
|
3315
3407
|
|
|
3316
3408
|
.uvf-video-subtitle {
|
|
3317
3409
|
color: var(--uvf-text-secondary);
|
|
3318
|
-
font-size: 13px;
|
|
3319
|
-
margin-top:
|
|
3320
|
-
max-width: min(70vw, 900px);
|
|
3410
|
+
font-size: clamp(11px, 1.8vw, 13px); /* Responsive font size */
|
|
3411
|
+
margin-top: 2px;
|
|
3321
3412
|
overflow: hidden;
|
|
3322
3413
|
text-overflow: ellipsis;
|
|
3323
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;
|
|
3324
3484
|
}
|
|
3325
3485
|
|
|
3326
3486
|
/* Above seekbar section with time and branding */
|
|
@@ -3399,7 +3559,21 @@ export class WebPlayer extends BasePlayer {
|
|
|
3399
3559
|
}
|
|
3400
3560
|
}
|
|
3401
3561
|
|
|
3562
|
+
/* Ultra small screens */
|
|
3402
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
|
+
|
|
3403
3577
|
.uvf-above-seekbar-section {
|
|
3404
3578
|
margin-bottom: 5px;
|
|
3405
3579
|
}
|
|
@@ -3787,6 +3961,47 @@ export class WebPlayer extends BasePlayer {
|
|
|
3787
3961
|
}
|
|
3788
3962
|
|
|
3789
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
|
+
|
|
3790
4005
|
/* Mobile portrait - hide skip buttons, ensure top bar visible */
|
|
3791
4006
|
@media screen and (max-width: 767px) and (orientation: portrait) {
|
|
3792
4007
|
#uvf-skip-back,
|
|
@@ -3954,6 +4169,31 @@ export class WebPlayer extends BasePlayer {
|
|
|
3954
4169
|
|
|
3955
4170
|
/* Tablet devices - Enhanced UX with desktop features */
|
|
3956
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
|
+
|
|
3957
4197
|
.uvf-controls-bar {
|
|
3958
4198
|
padding: 18px 16px;
|
|
3959
4199
|
background: linear-gradient(to top, var(--uvf-overlay-strong) 0%, var(--uvf-overlay-medium) 70%, var(--uvf-overlay-transparent) 100%);
|
|
@@ -4486,6 +4726,40 @@ export class WebPlayer extends BasePlayer {
|
|
|
4486
4726
|
}
|
|
4487
4727
|
}
|
|
4488
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
|
+
|
|
4489
4763
|
/* Paywall Desktop */
|
|
4490
4764
|
@media screen and (min-width: 1024px) {
|
|
4491
4765
|
.uvf-paywall-modal {
|
|
@@ -4544,6 +4818,100 @@ export class WebPlayer extends BasePlayer {
|
|
|
4544
4818
|
container.appendChild(brandingContainer);
|
|
4545
4819
|
this.debugLog('Framework branding added');
|
|
4546
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
|
+
}
|
|
4547
4915
|
createCustomControls(container) {
|
|
4548
4916
|
const topGradient = document.createElement('div');
|
|
4549
4917
|
topGradient.className = 'uvf-top-gradient';
|
|
@@ -4553,18 +4921,24 @@ export class WebPlayer extends BasePlayer {
|
|
|
4553
4921
|
container.appendChild(controlsGradient);
|
|
4554
4922
|
const topBar = document.createElement('div');
|
|
4555
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);
|
|
4556
4930
|
const titleBar = document.createElement('div');
|
|
4557
4931
|
titleBar.className = 'uvf-title-bar';
|
|
4558
4932
|
titleBar.innerHTML = `
|
|
4559
4933
|
<div class="uvf-title-content">
|
|
4560
|
-
<img class="uvf-video-thumb" id="uvf-video-thumb" alt="thumbnail" style="display:none;" />
|
|
4561
4934
|
<div class="uvf-title-text">
|
|
4562
4935
|
<div class=\"uvf-video-title\" id=\"uvf-video-title\" style=\"display:none;\"></div>
|
|
4563
4936
|
<div class=\"uvf-video-subtitle\" id=\"uvf-video-description\" style=\"display:none;\"></div>
|
|
4564
4937
|
</div>
|
|
4565
4938
|
</div>
|
|
4566
4939
|
`;
|
|
4567
|
-
|
|
4940
|
+
leftSide.appendChild(titleBar);
|
|
4941
|
+
topBar.appendChild(leftSide);
|
|
4568
4942
|
const topControls = document.createElement('div');
|
|
4569
4943
|
topControls.className = 'uvf-top-controls';
|
|
4570
4944
|
topControls.innerHTML = `
|
|
@@ -5225,11 +5599,13 @@ export class WebPlayer extends BasePlayer {
|
|
|
5225
5599
|
break;
|
|
5226
5600
|
case 'ArrowLeft':
|
|
5227
5601
|
e.preventDefault();
|
|
5602
|
+
e.stopImmediatePropagation();
|
|
5228
5603
|
this.seek(Math.max(0, this.video.currentTime - 10));
|
|
5229
5604
|
shortcutText = '-10s';
|
|
5230
5605
|
break;
|
|
5231
5606
|
case 'ArrowRight':
|
|
5232
5607
|
e.preventDefault();
|
|
5608
|
+
e.stopImmediatePropagation();
|
|
5233
5609
|
this.seek(Math.min(this.video.duration, this.video.currentTime + 10));
|
|
5234
5610
|
shortcutText = '+10s';
|
|
5235
5611
|
break;
|
|
@@ -6210,7 +6586,7 @@ export class WebPlayer extends BasePlayer {
|
|
|
6210
6586
|
autoSkip: this.chapterConfig.userPreferences?.autoSkipIntro || false,
|
|
6211
6587
|
onChapterChange: (chapter) => {
|
|
6212
6588
|
this.debugLog('Core chapter changed:', chapter?.title || 'none');
|
|
6213
|
-
this.emit('
|
|
6589
|
+
this.emit('onChapterchange', chapter);
|
|
6214
6590
|
},
|
|
6215
6591
|
onSegmentEntered: (segment) => {
|
|
6216
6592
|
this.debugLog('Core segment entered:', segment.title);
|
|
@@ -7323,6 +7699,123 @@ export class WebPlayer extends BasePlayer {
|
|
|
7323
7699
|
this.showNotification('Share failed');
|
|
7324
7700
|
}
|
|
7325
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
|
+
}
|
|
7326
7819
|
updateMetadataUI() {
|
|
7327
7820
|
try {
|
|
7328
7821
|
const md = this.source?.metadata || {};
|
|
@@ -7333,28 +7826,23 @@ export class WebPlayer extends BasePlayer {
|
|
|
7333
7826
|
const titleText = (md.title || '').toString().trim();
|
|
7334
7827
|
const descText = (md.description || '').toString().trim();
|
|
7335
7828
|
const thumbUrl = (md.thumbnailUrl || '').toString().trim();
|
|
7829
|
+
this.applySmartTextDisplay(titleEl, descEl, titleText, descText);
|
|
7336
7830
|
if (titleEl) {
|
|
7337
|
-
titleEl.textContent = titleText;
|
|
7338
7831
|
titleEl.style.display = titleText ? 'block' : 'none';
|
|
7339
7832
|
}
|
|
7340
7833
|
if (descEl) {
|
|
7341
|
-
descEl.textContent = descText;
|
|
7342
7834
|
descEl.style.display = descText ? 'block' : 'none';
|
|
7343
7835
|
}
|
|
7344
7836
|
if (thumbEl) {
|
|
7345
|
-
|
|
7346
|
-
thumbEl.src = thumbUrl;
|
|
7347
|
-
thumbEl.style.display = 'block';
|
|
7348
|
-
}
|
|
7349
|
-
else {
|
|
7350
|
-
thumbEl.removeAttribute('src');
|
|
7351
|
-
thumbEl.style.display = 'none';
|
|
7352
|
-
}
|
|
7837
|
+
thumbEl.style.display = 'none';
|
|
7353
7838
|
}
|
|
7354
|
-
const hasAny = !!(titleText || descText
|
|
7839
|
+
const hasAny = !!(titleText || descText);
|
|
7355
7840
|
if (titleBar) {
|
|
7356
7841
|
titleBar.style.display = hasAny ? '' : 'none';
|
|
7357
7842
|
}
|
|
7843
|
+
setTimeout(() => {
|
|
7844
|
+
this.setupTextTooltips();
|
|
7845
|
+
}, 100);
|
|
7358
7846
|
}
|
|
7359
7847
|
catch (_) { }
|
|
7360
7848
|
}
|