@cinecrew/cinecrew-player 0.1.1 → 0.1.2

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.
@@ -1,5 +1,6 @@
1
1
  .cinecrew-player {
2
2
  position: relative;
3
+ container-type: size;
3
4
  display: flex;
4
5
  width: 100%;
5
6
  min-width: 0;
@@ -27,6 +28,11 @@
27
28
  background: #000;
28
29
  }
29
30
 
31
+ .cinecrew-player__video,
32
+ .cinecrew-player__youtube {
33
+ transition: width 180ms ease, height 180ms ease, top 180ms ease;
34
+ }
35
+
30
36
  .cinecrew-player__shade {
31
37
  position: absolute;
32
38
  inset: 0;
@@ -35,10 +41,10 @@
35
41
 
36
42
  .cinecrew-player__title {
37
43
  position: absolute;
38
- top: 18px;
44
+ top: 62px;
39
45
  left: 20px;
46
+ right: 20px;
40
47
  z-index: 2;
41
- max-width: min(65%, 680px);
42
48
  overflow: hidden;
43
49
  font-weight: 700;
44
50
  text-overflow: ellipsis;
@@ -50,6 +56,7 @@
50
56
  position: absolute;
51
57
  inset: 0;
52
58
  z-index: 3;
59
+ box-sizing: border-box;
53
60
  display: flex;
54
61
  flex-direction: column;
55
62
  justify-content: space-between;
@@ -73,12 +80,48 @@
73
80
  }
74
81
 
75
82
  .cinecrew-player__top-controls,
83
+ .cinecrew-player__bottom-actions,
84
+ .cinecrew-player__top-left-actions,
85
+ .cinecrew-player__top-right-actions,
86
+ .cinecrew-player__bottom-left-actions,
87
+ .cinecrew-player__bottom-right-actions {
88
+ display: flex;
89
+ align-items: center;
90
+ gap: 8px;
91
+ }
92
+
93
+ .cinecrew-player__top-controls {
94
+ width: 100%;
95
+ justify-content: space-between;
96
+ gap: 12px;
97
+ }
98
+
99
+ .cinecrew-player__top-left-actions,
100
+ .cinecrew-player__top-right-actions {
101
+ min-width: 0;
102
+ }
103
+
104
+ .cinecrew-player__top-right-actions {
105
+ justify-content: flex-end;
106
+ }
107
+
76
108
  .cinecrew-player__bottom-controls {
109
+ width: 100%;
110
+ flex-direction: column;
111
+ align-items: stretch;
112
+ gap: 8px;
113
+ }
114
+
115
+ .cinecrew-player__bottom-actions {
116
+ width: 100%;
117
+ justify-content: space-between;
77
118
  flex-wrap: wrap;
78
119
  }
79
120
 
80
- .cinecrew-player__bottom-controls {
81
- justify-content: flex-end;
121
+ .cinecrew-player__bottom-left-actions,
122
+ .cinecrew-player__bottom-right-actions {
123
+ min-width: 0;
124
+ flex-wrap: wrap;
82
125
  }
83
126
 
84
127
  .cinecrew-player__center-controls {
@@ -86,7 +129,8 @@
86
129
  }
87
130
 
88
131
  .cinecrew-player__seek {
89
- flex: 1 1 100%;
132
+ flex: 0 0 auto;
133
+ width: 100%;
90
134
  font-variant-numeric: tabular-nums;
91
135
  text-shadow: 0 1px 3px #000;
92
136
  }
@@ -94,6 +138,9 @@
94
138
  .cinecrew-player__seek input {
95
139
  flex: 1;
96
140
  min-width: 50px;
141
+ min-height: 24px;
142
+ touch-action: auto;
143
+ cursor: ew-resize;
97
144
  }
98
145
 
99
146
  .cinecrew-player__button {
@@ -225,6 +272,25 @@
225
272
  box-shadow: 0 8px 30px rgba(0,0,0,.4);
226
273
  }
227
274
 
275
+ .cinecrew-player__menu-wrap--aspect .cinecrew-player__menu {
276
+ right: auto;
277
+ left: 0;
278
+ box-sizing: border-box;
279
+ width: min(180px, calc(100vw - 32px));
280
+ min-width: 0;
281
+ max-width: calc(100vw - 32px);
282
+ max-height: min(220px, calc(100vh - 32px));
283
+ overflow-y: auto;
284
+ }
285
+
286
+ @supports (width: 1cqw) and (height: 1cqh) {
287
+ .cinecrew-player__menu-wrap--aspect .cinecrew-player__menu {
288
+ width: min(180px, max(0px, calc(100cqw - 28px)));
289
+ max-width: max(0px, calc(100cqw - 28px));
290
+ max-height: min(220px, max(80px, calc(100cqh - 28px)));
291
+ }
292
+ }
293
+
228
294
  .cinecrew-player__menu button,
229
295
  .cinecrew-player__panel-close {
230
296
  padding: 10px 13px;
@@ -236,9 +302,42 @@
236
302
  font: inherit;
237
303
  }
238
304
 
305
+ .cinecrew-player__menu-wrap--aspect .cinecrew-player__menu button {
306
+ padding-block: 6px;
307
+ }
308
+
309
+ .cinecrew-player__diagnostics {
310
+ display: flex;
311
+ flex-direction: column;
312
+ gap: 10px;
313
+ min-width: 220px;
314
+ }
315
+
316
+ .cinecrew-player__diagnostics > strong {
317
+ padding-bottom: 8px;
318
+ border-bottom: 1px solid rgba(255, 255, 255, .14);
319
+ }
320
+
321
+ .cinecrew-player__diagnostic-row {
322
+ display: flex;
323
+ justify-content: space-between;
324
+ gap: 16px;
325
+ font-variant-numeric: tabular-nums;
326
+ }
327
+
328
+ .cinecrew-player__diagnostic-row span:first-child {
329
+ opacity: .72;
330
+ }
331
+
332
+ .cinecrew-player__diagnostic-row span:last-child {
333
+ text-align: right;
334
+ overflow-wrap: anywhere;
335
+ }
336
+
239
337
  .cinecrew-player__panel-content {
240
338
  display: flex;
241
339
  flex-direction: column;
340
+ height: 100%;
242
341
  gap: 10px;
243
342
  min-height: 0;
244
343
  max-height: 100%;
@@ -283,6 +382,20 @@
283
382
  background: rgba(255, 255, 255, .06);
284
383
  }
285
384
 
385
+ .cinecrew-player__chat-message header {
386
+ display: flex;
387
+ align-items: baseline;
388
+ justify-content: space-between;
389
+ gap: 10px;
390
+ }
391
+
392
+ .cinecrew-player__chat-message time {
393
+ flex: 0 0 auto;
394
+ opacity: .65;
395
+ font-size: .78em;
396
+ font-variant-numeric: tabular-nums;
397
+ }
398
+
286
399
  .cinecrew-player__chat-message strong,
287
400
  .cinecrew-player__epg-item strong {
288
401
  color: var(--cinecrew-accent);
@@ -298,26 +411,201 @@
298
411
  }
299
412
 
300
413
  .cinecrew-player__chat-form {
414
+ position: relative;
415
+ padding-top: 10px;
416
+ border-top: 1px solid rgba(255,255,255,.12);
417
+ }
418
+
419
+ .cinecrew-player__chat-composer {
420
+ position: relative;
301
421
  display: flex;
422
+ align-items: center;
302
423
  gap: 8px;
424
+ padding: 6px;
425
+ border: 1px solid rgba(255, 255, 255, .2);
426
+ border-radius: 999px;
427
+ background: rgba(0, 0, 0, .2);
428
+ transition: border-color .16s ease, box-shadow .16s ease, background-color .16s ease;
303
429
  }
304
430
 
305
- .cinecrew-player__chat-form input {
431
+ .cinecrew-player__chat-composer:focus-within {
432
+ border-color: var(--cinecrew-accent);
433
+ background: rgba(0, 0, 0, .28);
434
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--cinecrew-accent) 18%, transparent);
435
+ }
436
+
437
+ .cinecrew-player__chat-composer input {
306
438
  flex: 1;
307
439
  min-width: 0;
308
- border: 1px solid rgba(255, 255, 255, .16);
309
- border-radius: 20px;
310
- padding: 10px 13px;
440
+ border: 0;
441
+ outline: 0;
442
+ padding: 8px 10px;
311
443
  color: inherit;
312
- background: rgba(0, 0, 0, .2);
444
+ background: transparent;
445
+ font: inherit;
446
+ }
447
+
448
+ .cinecrew-player__chat-composer button {
449
+ display: inline-grid;
450
+ min-width: 34px;
451
+ min-height: 34px;
452
+ place-items: center;
453
+ border: 0;
454
+ border-radius: 50%;
455
+ color: var(--cinecrew-accent);
456
+ background: rgba(255, 255, 255, .08);
457
+ cursor: pointer;
313
458
  font: inherit;
459
+ transition: background-color .16s ease, transform .16s ease;
460
+ }
461
+
462
+ .cinecrew-player__chat-composer button:hover:not(:disabled) {
463
+ background: rgba(255, 255, 255, .15);
464
+ }
465
+
466
+ .cinecrew-player__chat-composer button:active:not(:disabled) {
467
+ transform: scale(.96);
468
+ }
469
+
470
+ .cinecrew-player__chat-composer button[type="submit"] {
471
+ min-width: auto;
472
+ padding: 0 14px;
473
+ border-radius: 999px;
474
+ color: #07111e;
475
+ background: var(--cinecrew-accent);
476
+ font-weight: 700;
477
+ box-shadow: 0 2px 8px color-mix(in srgb, var(--cinecrew-accent) 24%, transparent);
314
478
  }
315
479
 
316
- .cinecrew-player__chat-form button:disabled {
480
+ .cinecrew-player__chat-composer button[type="submit"]:hover:not(:disabled) {
481
+ filter: brightness(1.08);
482
+ }
483
+
484
+ .cinecrew-player__chat-composer button:disabled {
317
485
  opacity: .5;
318
486
  cursor: not-allowed;
319
487
  }
320
488
 
489
+ .cinecrew-player__emoji-picker {
490
+ position: absolute;
491
+ right: 0;
492
+ bottom: calc(100% + 12px);
493
+ z-index: 2;
494
+ display: flex;
495
+ flex-direction: column;
496
+ gap: 8px;
497
+ width: min(340px, calc(100vw - 32px));
498
+ max-height: min(390px, 65vh);
499
+ padding: 10px;
500
+ border: 1px solid rgba(255, 255, 255, .18);
501
+ border-radius: 14px;
502
+ background: var(--cinecrew-surface);
503
+ box-shadow: 0 10px 30px rgba(0, 0, 0, .42);
504
+ }
505
+
506
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-search {
507
+ flex: 0 0 auto;
508
+ width: 100%;
509
+ box-sizing: border-box;
510
+ border: 1px solid rgba(255, 255, 255, .16);
511
+ border-radius: 10px;
512
+ outline: 0;
513
+ padding: 9px 11px;
514
+ color: inherit;
515
+ background: rgba(0, 0, 0, .2);
516
+ font: inherit;
517
+ font-size: 13px;
518
+ }
519
+
520
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-search:focus {
521
+ border-color: var(--cinecrew-accent);
522
+ }
523
+
524
+ .cinecrew-player__emoji-categories {
525
+ display: grid;
526
+ flex: 0 0 auto;
527
+ grid-template-columns: repeat(9, minmax(0, 1fr));
528
+ gap: 2px;
529
+ }
530
+
531
+ .cinecrew-player__emoji-picker button,
532
+ .cinecrew-player__load-more {
533
+ border: 1px solid rgba(255, 255, 255, .14);
534
+ border-radius: 9px;
535
+ color: inherit;
536
+ background: rgba(255, 255, 255, .07);
537
+ cursor: pointer;
538
+ font: inherit;
539
+ }
540
+
541
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-categories button {
542
+ display: grid;
543
+ min-width: 0;
544
+ min-height: 34px;
545
+ place-items: center;
546
+ border: 1px solid transparent;
547
+ border-radius: 8px;
548
+ padding: 0;
549
+ background: transparent;
550
+ font-size: 19px;
551
+ }
552
+
553
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-categories button:hover,
554
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-categories button.is-active {
555
+ border-color: var(--cinecrew-accent);
556
+ background: color-mix(in srgb, var(--cinecrew-accent) 14%, transparent);
557
+ }
558
+
559
+ .cinecrew-player__emoji-grid {
560
+ display: grid;
561
+ flex: 1 1 auto;
562
+ grid-template-columns: repeat(8, minmax(0, 1fr));
563
+ align-content: start;
564
+ gap: 3px;
565
+ min-height: 0;
566
+ overflow: auto;
567
+ overscroll-behavior: contain;
568
+ scrollbar-width: thin;
569
+ }
570
+
571
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-grid button {
572
+ display: grid;
573
+ width: 100%;
574
+ min-width: 0;
575
+ min-height: 34px;
576
+ place-items: center;
577
+ border: 0;
578
+ border-radius: 8px;
579
+ padding: 0;
580
+ background: transparent;
581
+ font-size: 19px;
582
+ }
583
+
584
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-grid button:hover {
585
+ background: rgba(255, 255, 255, .12);
586
+ }
587
+
588
+ .cinecrew-player__chat-composer .cinecrew-player__emoji-grid .cinecrew-player__emoji-load-more {
589
+ grid-column: 1 / -1;
590
+ min-height: 34px;
591
+ border: 1px solid rgba(255, 255, 255, .14);
592
+ color: var(--cinecrew-accent);
593
+ background: rgba(255, 255, 255, .06);
594
+ font-size: 12px;
595
+ }
596
+
597
+ .cinecrew-player__load-more {
598
+ flex: 0 0 auto;
599
+ align-self: center;
600
+ padding: 8px 14px;
601
+ color: var(--cinecrew-accent);
602
+ }
603
+
604
+ .cinecrew-player__load-more:disabled {
605
+ opacity: .6;
606
+ cursor: progress;
607
+ }
608
+
321
609
  .cinecrew-player__rate {
322
610
  max-width: 88px;
323
611
  border: 1px solid rgba(255, 255, 255, .18);
@@ -352,16 +640,25 @@
352
640
 
353
641
  .cinecrew-player__panel {
354
642
  position: absolute;
355
- inset: 8% 4% 8% auto;
643
+ inset: 0 0 0 auto;
356
644
  z-index: 6;
357
- width: min(380px, 92%);
645
+ box-sizing: border-box;
646
+ width: min(420px, 92%);
647
+ max-width: 92%;
358
648
  overflow: auto;
359
- padding: 18px;
360
- border: 1px solid rgba(255,255,255,.14);
361
- border-radius: 16px;
362
- box-shadow: 0 16px 48px rgba(0,0,0,.45);
649
+ padding: 16px;
650
+ border-left: 1px solid rgba(255,255,255,.2);
651
+ border-radius: 0;
652
+ background: rgba(13, 26, 44, .78);
653
+ backdrop-filter: blur(18px);
654
+ box-shadow: -12px 0 34px rgba(0,0,0,.34);
655
+ animation: cinecrew-drawer-in 180ms ease-out both;
363
656
  }
364
657
 
658
+ .cinecrew-player--drawer-resize .cinecrew-player__panel { width: min(420px, 36%); }
659
+
660
+ .cinecrew-player__panel.is-resizing { background: rgba(13, 26, 44, .88); }
661
+
365
662
  .cinecrew-player__panel-close {
366
663
  position: absolute;
367
664
  top: 4px;
@@ -373,6 +670,33 @@
373
670
  to { transform: rotate(360deg); }
374
671
  }
375
672
 
673
+ @keyframes cinecrew-drawer-in {
674
+ from { opacity: 0; transform: translateX(18px); }
675
+ to { opacity: 1; transform: translateX(0); }
676
+ }
677
+
376
678
  @media (hover: none) {
377
679
  .cinecrew-player__controls { opacity: 1; }
378
680
  }
681
+
682
+ @media (max-width: 640px) {
683
+ .cinecrew-player__controls { padding: 10px; }
684
+ .cinecrew-player__top-controls { align-items: flex-start; gap: 6px; }
685
+ .cinecrew-player__top-left-actions { gap: 4px; }
686
+ .cinecrew-player__top-right-actions {
687
+ max-width: calc(100% - 128px);
688
+ flex-wrap: wrap;
689
+ gap: 4px;
690
+ }
691
+ .cinecrew-player__top-left-actions .cinecrew-player__button,
692
+ .cinecrew-player__top-right-actions .cinecrew-player__button,
693
+ .cinecrew-player__bottom-actions .cinecrew-player__button {
694
+ min-width: 34px;
695
+ min-height: 34px;
696
+ padding: 6px 8px;
697
+ }
698
+ .cinecrew-player__title { top: 96px; left: 12px; right: 12px; }
699
+ .cinecrew-player__bottom-actions { align-items: flex-end; gap: 6px; }
700
+ .cinecrew-player__bottom-right-actions { max-width: 100%; flex-wrap: wrap; justify-content: flex-end; gap: 4px; }
701
+ .cinecrew-player__panel { width: min(380px, 92%); }
702
+ }
package/types/index.d.ts CHANGED
@@ -32,14 +32,16 @@ export interface PlayerControls {
32
32
  audioOnly?: boolean;
33
33
  audioTracks?: boolean;
34
34
  playbackRate?: boolean;
35
- minimize?: boolean;
36
35
  fullscreen?: boolean;
37
36
  recording?: boolean;
38
37
  liveChat?: boolean;
39
38
  epg?: boolean;
39
+ diagnostics?: boolean;
40
40
  seek?: boolean;
41
41
  }
42
42
 
43
+ export type PlayerDrawerMode = 'overlay' | 'resize';
44
+
43
45
  export interface PlayerApi {
44
46
  play(): void;
45
47
  pause(): void;
@@ -54,7 +56,6 @@ export interface PlayerApi {
54
56
  seekTo(seconds: number): void;
55
57
  seekBy(seconds: number): void;
56
58
  back(): void;
57
- minimize(): void;
58
59
  setPlaybackRate(rate: number): void;
59
60
  getVideoElement(): unknown | null;
60
61
  getAudioTracks(): AudioTrack[];
@@ -89,7 +90,6 @@ export interface PlayerActions {
89
90
  onVideoOnlyChange?: PlayerAction;
90
91
  onAudioOnlyChange?: PlayerAction;
91
92
  onAudioTrackChange?: PlayerAction;
92
- onMinimize?: PlayerAction;
93
93
  onPlaybackRateChange?: PlayerAction;
94
94
  onFullscreen?: PlayerAction;
95
95
  onRecordingStart?: PlayerAction;
@@ -125,8 +125,8 @@ export interface PlayerIconProps {
125
125
  export type PlayerIcon = string | React.ReactNode | React.ComponentType<PlayerIconProps>;
126
126
  export type PlayerIcons = Partial<Record<
127
127
  | 'play' | 'pause' | 'restart' | 'lock' | 'unlock' | 'mute' | 'unmute'
128
- | 'aspectRatio' | 'videoOnly' | 'audio' | 'minimize' | 'back'
129
- | 'recording' | 'stop' | 'liveChat' | 'epg' | 'fullscreen' | 'close'
128
+ | 'aspectRatio' | 'videoOnly' | 'audio' | 'back'
129
+ | 'recording' | 'stop' | 'liveChat' | 'epg' | 'diagnostics' | 'fullscreen' | 'close'
130
130
  | string,
131
131
  PlayerIcon
132
132
  >>;
@@ -137,9 +137,19 @@ export interface ChatMessage {
137
137
  comment?: string;
138
138
  message?: string;
139
139
  createdAt?: string | number;
140
+ timestamp?: string | number;
140
141
  [key: string]: unknown;
141
142
  }
142
143
 
144
+ export interface ChatMessagePage {
145
+ messages?: ChatMessage[];
146
+ items?: ChatMessage[];
147
+ comments?: ChatMessage[];
148
+ data?: ChatMessage[];
149
+ hasMore?: boolean;
150
+ pagination?: { hasMore?: boolean };
151
+ }
152
+
143
153
  export interface EpgListing {
144
154
  title?: string;
145
155
  description?: string;
@@ -152,7 +162,7 @@ export interface PlayerIntegrations {
152
162
  user?: { id?: string | number; username?: string };
153
163
  getUser?: () => Promise<{ id?: string | number; username?: string } | null>;
154
164
  liveChat?: {
155
- loadMessages?: (args: { channelId: string; limit: number }) => Promise<ChatMessage[]>;
165
+ loadMessages?: (args: { channelId: string; limit: number; offset?: number }) => Promise<ChatMessage[] | ChatMessagePage>;
156
166
  sendMessage?: (args: { channelId: string; userId?: string | number; username?: string; comment: string }) => Promise<unknown>;
157
167
  pollIntervalMs?: number;
158
168
  render?: (context: { title: string; source: PlayerSource; onClose: () => void }) => React.ReactNode;
@@ -195,6 +205,12 @@ export interface CineCrewPlayerProps {
195
205
  volume?: number;
196
206
  playbackRate?: number;
197
207
  controls?: PlayerControls;
208
+ /** Web/Electron chat and EPG drawer behavior. Overlay keeps the video full-size; resize shrinks it to make room. */
209
+ drawerMode?: PlayerDrawerMode;
210
+ /** Web CSS or React Native view-style overrides for the chat, EPG, and diagnostics drawer. */
211
+ drawerStyle?: React.CSSProperties | import('react-native').ViewStyle;
212
+ /** Number of chat messages fetched per page; older pages load from the drawer's See more button. Defaults to 50. */
213
+ messagePageSize?: number;
198
214
  features?: { diagnostics?: boolean; [key: string]: boolean | undefined };
199
215
  actions?: PlayerActions;
200
216
  integrations?: PlayerIntegrations;
@@ -219,7 +235,6 @@ export interface CineCrewPlayerProps {
219
235
  shuffle?: boolean;
220
236
  onClose?: () => void;
221
237
  onBack?: () => void;
222
- onMinimize?: () => void;
223
238
  onFullscreen?: (state: { isFullscreen: boolean }) => void;
224
239
  onPlayerHostRef?: (node: unknown | null) => void;
225
240
  onInlinePreviewWheel?: (deltaY: number) => void;