@livepeer-frameworks/player-svelte 0.1.2 → 0.2.1

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.
Files changed (56) hide show
  1. package/LICENSE.md +24 -0
  2. package/README.md +6 -2
  3. package/dist/DevModePanel.svelte +53 -16
  4. package/dist/IdleScreen.svelte +36 -28
  5. package/dist/LoadingScreen.svelte +107 -67
  6. package/dist/LoadingScreen.svelte.bak +702 -0
  7. package/dist/Player.svelte +200 -53
  8. package/dist/Player.svelte.d.ts +6 -1
  9. package/dist/PlayerControls.svelte +114 -32
  10. package/dist/PlayerControls.svelte.d.ts +3 -0
  11. package/dist/StreamStateOverlay.svelte +33 -21
  12. package/dist/SubtitleRenderer.svelte +2 -2
  13. package/dist/controls/FullscreenButton.svelte +26 -0
  14. package/dist/controls/FullscreenButton.svelte.d.ts +3 -0
  15. package/dist/controls/LiveBadge.svelte +23 -0
  16. package/dist/controls/LiveBadge.svelte.d.ts +3 -0
  17. package/dist/controls/PlayButton.svelte +26 -0
  18. package/dist/controls/PlayButton.svelte.d.ts +3 -0
  19. package/dist/controls/SettingsMenu.svelte +208 -0
  20. package/dist/controls/SettingsMenu.svelte.d.ts +28 -0
  21. package/dist/controls/SkipButton.svelte +33 -0
  22. package/dist/controls/SkipButton.svelte.d.ts +7 -0
  23. package/dist/controls/TimeDisplay.svelte +18 -0
  24. package/dist/controls/TimeDisplay.svelte.d.ts +3 -0
  25. package/dist/controls/VolumeControl.svelte +26 -0
  26. package/dist/controls/VolumeControl.svelte.d.ts +3 -0
  27. package/dist/controls/index.d.ts +7 -0
  28. package/dist/controls/index.js +7 -0
  29. package/dist/index.d.ts +3 -2
  30. package/dist/index.js +3 -1
  31. package/dist/stores/i18n.d.ts +3 -0
  32. package/dist/stores/i18n.js +4 -0
  33. package/dist/stores/index.d.ts +1 -0
  34. package/dist/stores/index.js +2 -0
  35. package/dist/stores/playerController.d.ts +2 -0
  36. package/dist/stores/playerController.js +4 -0
  37. package/package.json +19 -19
  38. package/src/DevModePanel.svelte +53 -16
  39. package/src/IdleScreen.svelte +12 -4
  40. package/src/LoadingScreen.svelte +90 -50
  41. package/src/LoadingScreen.svelte.bak +702 -0
  42. package/src/Player.svelte +200 -53
  43. package/src/PlayerControls.svelte +114 -32
  44. package/src/StreamStateOverlay.svelte +17 -5
  45. package/src/controls/FullscreenButton.svelte +26 -0
  46. package/src/controls/LiveBadge.svelte +23 -0
  47. package/src/controls/PlayButton.svelte +26 -0
  48. package/src/controls/SettingsMenu.svelte +208 -0
  49. package/src/controls/SkipButton.svelte +33 -0
  50. package/src/controls/TimeDisplay.svelte +18 -0
  51. package/src/controls/VolumeControl.svelte +26 -0
  52. package/src/controls/index.ts +7 -0
  53. package/src/index.ts +10 -0
  54. package/src/stores/i18n.ts +7 -0
  55. package/src/stores/index.ts +3 -0
  56. package/src/stores/playerController.ts +7 -0
@@ -13,7 +13,9 @@
13
13
  - Status overlay at bottom
14
14
  -->
15
15
  <script lang="ts">
16
- import { onMount, onDestroy } from "svelte";
16
+ import { onMount, onDestroy, getContext } from "svelte";
17
+ import type { Readable } from "svelte/store";
18
+ import { createTranslator, type TranslateFn } from "@livepeer-frameworks/player-core";
17
19
  import type { StreamStatus } from "@livepeer-frameworks/player-core";
18
20
  import DvdLogo from "./DvdLogo.svelte";
19
21
  import logomarkAsset from "./assets/logomark.svg";
@@ -26,14 +28,20 @@
26
28
  onRetry?: () => void;
27
29
  }
28
30
 
31
+ const translatorCtx = getContext<Readable<TranslateFn> | undefined>("fw-translator");
32
+ const fallbackT = createTranslator({ locale: "en" });
33
+ let t: TranslateFn = $derived(translatorCtx ? $translatorCtx : fallbackT);
34
+
29
35
  let {
30
36
  status = "OFFLINE",
31
- message = "Waiting for stream...",
37
+ message = undefined,
32
38
  percentage = undefined,
33
39
  error = undefined,
34
40
  onRetry = undefined,
35
41
  }: Props = $props();
36
42
 
43
+ let effectiveMessage = $derived(message ?? t("waitingForStream"));
44
+
37
45
  // Container ref for mouse tracking
38
46
  let containerRef: HTMLDivElement | undefined = $state();
39
47
 
@@ -316,7 +324,7 @@
316
324
  let _statusLabel = $derived(getStatusLabel(status));
317
325
  let showRetry = $derived((status === "ERROR" || status === "INVALID") && onRetry);
318
326
  let showProgress = $derived(status === "INITIALIZING" && percentage !== undefined);
319
- let displayMessage = $derived(error || message);
327
+ let displayMessage = $derived(error || effectiveMessage);
320
328
  let isLoading = $derived(
321
329
  status === "INITIALIZING" || status === "BOOTING" || status === "WAITING_FOR_DATA" || !status
322
330
  );
@@ -522,7 +530,7 @@
522
530
 
523
531
  <!-- Retry button -->
524
532
  {#if showRetry}
525
- <button type="button" class="retry-button" onclick={onRetry}> Retry </button>
533
+ <button type="button" class="retry-button" onclick={onRetry}> {t("retry")} </button>
526
534
  {/if}
527
535
  </div>
528
536
 
@@ -12,16 +12,23 @@
12
12
  - Animated background gradient shifts
13
13
  -->
14
14
  <script lang="ts">
15
- import { onMount, onDestroy } from "svelte";
15
+ import { onMount, onDestroy, getContext } from "svelte";
16
+ import type { Readable } from "svelte/store";
17
+ import { createTranslator, type TranslateFn } from "@livepeer-frameworks/player-core";
16
18
  import DvdLogo from "./DvdLogo.svelte";
17
19
  import logomarkAsset from "./assets/logomark.svg";
18
20
 
21
+ const translatorCtx = getContext<Readable<TranslateFn> | undefined>("fw-translator");
22
+ const fallbackT = createTranslator({ locale: "en" });
23
+ let t: TranslateFn = $derived(translatorCtx ? $translatorCtx : fallbackT);
24
+
19
25
  interface Props {
20
26
  message?: string;
21
27
  logoSrc?: string;
22
28
  }
23
29
 
24
- let { message = "Waiting for source...", logoSrc }: Props = $props();
30
+ let { message = undefined, logoSrc }: Props = $props();
31
+ let effectiveMessage = $derived(message ?? t("waitingForSource"));
25
32
 
26
33
  // Use imported asset as default if logoSrc not provided
27
34
  let effectiveLogoSrc = $derived(logoSrc || logomarkAsset);
@@ -42,35 +49,10 @@
42
49
  let offset = $state({ x: 0, y: 0 });
43
50
  let isHovered = $state(false);
44
51
 
45
- // Tokyo Night inspired pastel colors for bubbles
46
- const bubbleColors = [
47
- "rgba(122, 162, 247, 0.2)", // Terminal Blue
48
- "rgba(187, 154, 247, 0.2)", // Terminal Magenta
49
- "rgba(158, 206, 106, 0.2)", // Strings/CSS classes
50
- "rgba(115, 218, 202, 0.2)", // Terminal Green
51
- "rgba(125, 207, 255, 0.2)", // Terminal Cyan
52
- "rgba(247, 118, 142, 0.2)", // Keywords/Terminal Red
53
- "rgba(224, 175, 104, 0.2)", // Terminal Yellow
54
- "rgba(42, 195, 222, 0.2)", // Language functions
55
- ];
56
-
57
- // Particle colors
58
- const particleColors = [
59
- "#7aa2f7", // Terminal Blue
60
- "#bb9af7", // Terminal Magenta
61
- "#9ece6a", // Strings/CSS classes
62
- "#73daca", // Terminal Green
63
- "#7dcfff", // Terminal Cyan
64
- "#f7768e", // Keywords/Terminal Red
65
- "#e0af68", // Terminal Yellow
66
- "#2ac3de", // Language functions
67
- ];
68
-
69
52
  // Generate random particles
70
- const particles = Array.from({ length: 12 }, (_, i) => ({
53
+ const particles = Array.from({ length: 12 }, () => ({
71
54
  left: Math.random() * 100,
72
55
  size: Math.random() * 4 + 2,
73
- color: particleColors[i % 8],
74
56
  duration: 8 + Math.random() * 4,
75
57
  delay: Math.random() * 8,
76
58
  }));
@@ -80,16 +62,14 @@
80
62
  position: { top: number; left: number };
81
63
  size: number;
82
64
  opacity: number;
83
- color: string;
84
65
  timeoutId: ReturnType<typeof setTimeout> | null;
85
66
  }
86
67
 
87
68
  let bubbles = $state<BubbleState[]>(
88
- Array.from({ length: 8 }, (_, i) => ({
69
+ Array.from({ length: 8 }, () => ({
89
70
  position: { top: Math.random() * 80 + 10, left: Math.random() * 80 + 10 },
90
71
  size: Math.random() * 60 + 30,
91
72
  opacity: 0,
92
- color: bubbleColors[i % bubbleColors.length],
93
73
  timeoutId: null,
94
74
  }))
95
75
  );
@@ -361,7 +341,7 @@
361
341
  bind:this={containerRef}
362
342
  class="loading-container fw-player-root"
363
343
  role="status"
364
- aria-label="Loading"
344
+ aria-label={t("loading")}
365
345
  onmousemove={handleMouseMove}
366
346
  onmouseleave={handleMouseLeave}
367
347
  >
@@ -383,7 +363,6 @@
383
363
  left: {particle.left}%;
384
364
  width: {particle.size}px;
385
365
  height: {particle.size}px;
386
- background: {particle.color};
387
366
  animation-duration: {particle.duration}s;
388
367
  animation-delay: {particle.delay}s;
389
368
  "
@@ -399,7 +378,6 @@
399
378
  left: {bubble.position.left}%;
400
379
  width: {bubble.size}px;
401
380
  height: {bubble.size}px;
402
- background: {bubble.color};
403
381
  opacity: {bubble.opacity};
404
382
  "
405
383
  ></div>
@@ -435,7 +413,7 @@
435
413
 
436
414
  <!-- Message -->
437
415
  <div class="message">
438
- {message}
416
+ {effectiveMessage}
439
417
  </div>
440
418
 
441
419
  <!-- Subtle overlay texture -->
@@ -544,11 +522,11 @@
544
522
  min-height: 300px;
545
523
  background: linear-gradient(
546
524
  135deg,
547
- hsl(var(--tn-bg-dark, 235 21% 11%)) 0%,
548
- hsl(var(--tn-bg, 233 23% 17%)) 25%,
549
- hsl(var(--tn-bg-dark, 235 21% 11%)) 50%,
550
- hsl(var(--tn-bg, 233 23% 17%)) 75%,
551
- hsl(var(--tn-bg-dark, 235 21% 11%)) 100%
525
+ hsl(var(--fw-surface-deep, 235 21% 11%)) 0%,
526
+ hsl(var(--fw-surface, 233 23% 17%)) 25%,
527
+ hsl(var(--fw-surface-deep, 235 21% 11%)) 50%,
528
+ hsl(var(--fw-surface, 233 23% 17%)) 75%,
529
+ hsl(var(--fw-surface-deep, 235 21% 11%)) 100%
552
530
  );
553
531
  background-size: 400% 400%;
554
532
  animation: gradientShift 16s ease-in-out infinite;
@@ -579,6 +557,56 @@
579
557
  user-select: none;
580
558
  }
581
559
 
560
+ .particle:nth-child(8n + 1) {
561
+ background: hsl(var(--fw-accent, 218 79% 73%));
562
+ }
563
+ .particle:nth-child(8n + 2) {
564
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%));
565
+ }
566
+ .particle:nth-child(8n + 3) {
567
+ background: hsl(var(--fw-success, 97 52% 51%));
568
+ }
569
+ .particle:nth-child(8n + 4) {
570
+ background: hsl(var(--fw-info, 197 95% 74%));
571
+ }
572
+ .particle:nth-child(8n + 5) {
573
+ background: hsl(var(--fw-danger, 352 86% 71%));
574
+ }
575
+ .particle:nth-child(8n + 6) {
576
+ background: hsl(var(--fw-warning, 33 81% 64%));
577
+ }
578
+ .particle:nth-child(8n + 7) {
579
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.8);
580
+ }
581
+ .particle:nth-child(8n + 8) {
582
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.8);
583
+ }
584
+
585
+ .bubble:nth-child(8n + 1) {
586
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.2);
587
+ }
588
+ .bubble:nth-child(8n + 2) {
589
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.2);
590
+ }
591
+ .bubble:nth-child(8n + 3) {
592
+ background: hsl(var(--fw-success, 97 52% 51%) / 0.2);
593
+ }
594
+ .bubble:nth-child(8n + 4) {
595
+ background: hsl(var(--fw-info, 197 95% 74%) / 0.2);
596
+ }
597
+ .bubble:nth-child(8n + 5) {
598
+ background: hsl(var(--fw-danger, 352 86% 71%) / 0.2);
599
+ }
600
+ .bubble:nth-child(8n + 6) {
601
+ background: hsl(var(--fw-warning, 33 81% 64%) / 0.2);
602
+ }
603
+ .bubble:nth-child(8n + 7) {
604
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.15);
605
+ }
606
+ .bubble:nth-child(8n + 8) {
607
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.15);
608
+ }
609
+
582
610
  .center-logo {
583
611
  position: absolute;
584
612
  top: 50%;
@@ -594,7 +622,7 @@
594
622
  .logo-pulse {
595
623
  position: absolute;
596
624
  border-radius: 50%;
597
- background: rgba(122, 162, 247, 0.15);
625
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.15);
598
626
  animation: logoPulse 3s ease-in-out infinite;
599
627
  user-select: none;
600
628
  pointer-events: none;
@@ -615,7 +643,7 @@
615
643
  .logo-image {
616
644
  position: relative;
617
645
  z-index: 1;
618
- filter: drop-shadow(0 4px 8px rgba(36, 40, 59, 0.3));
646
+ filter: drop-shadow(0 4px 8px hsl(var(--fw-surface-deep, 235 21% 11%) / 0.3));
619
647
  transition: all 0.3s ease-out;
620
648
  user-select: none;
621
649
  -webkit-user-drag: none;
@@ -623,7 +651,7 @@
623
651
  }
624
652
 
625
653
  .logo-image.hovered {
626
- filter: drop-shadow(0 6px 12px rgba(36, 40, 59, 0.4)) brightness(1.1);
654
+ filter: drop-shadow(0 6px 12px hsl(var(--fw-surface-deep, 235 21% 11%) / 0.4)) brightness(1.1);
627
655
  transform: scale(1.1);
628
656
  cursor: pointer;
629
657
  }
@@ -633,12 +661,12 @@
633
661
  bottom: 20%;
634
662
  left: 50%;
635
663
  transform: translateX(-50%);
636
- color: #a9b1d6;
664
+ color: hsl(var(--fw-text-muted, 227 24% 74%));
637
665
  font-size: 16px;
638
666
  font-weight: 500;
639
667
  text-align: center;
640
668
  animation: fadeInOut 2s ease-in-out infinite;
641
- text-shadow: 0 2px 4px rgba(36, 40, 59, 0.5);
669
+ text-shadow: 0 2px 4px hsl(var(--fw-surface-deep, 235 21% 11%) / 0.5);
642
670
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
643
671
  user-select: none;
644
672
  pointer-events: none;
@@ -651,9 +679,21 @@
651
679
  right: 0;
652
680
  bottom: 0;
653
681
  background:
654
- radial-gradient(circle at 20% 80%, rgba(122, 162, 247, 0.03) 0%, transparent 50%),
655
- radial-gradient(circle at 80% 20%, rgba(187, 154, 247, 0.03) 0%, transparent 50%),
656
- radial-gradient(circle at 40% 40%, rgba(158, 206, 106, 0.02) 0%, transparent 50%);
682
+ radial-gradient(
683
+ circle at 20% 80%,
684
+ hsl(var(--fw-accent, 218 79% 73%) / 0.03) 0%,
685
+ transparent 50%
686
+ ),
687
+ radial-gradient(
688
+ circle at 80% 20%,
689
+ hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.03) 0%,
690
+ transparent 50%
691
+ ),
692
+ radial-gradient(
693
+ circle at 40% 40%,
694
+ hsl(var(--fw-success, 97 52% 51%) / 0.02) 0%,
695
+ transparent 50%
696
+ );
657
697
  pointer-events: none;
658
698
  user-select: none;
659
699
  }
@@ -671,8 +711,8 @@
671
711
  position: absolute;
672
712
  width: 12px;
673
713
  height: 3px;
674
- background-color: #ffffff;
675
- box-shadow: 0 0 8px rgba(255, 255, 255, 0.8);
714
+ background-color: hsl(var(--fw-text-bright, 220 13% 91%));
715
+ box-shadow: 0 0 8px hsl(var(--fw-text-bright, 220 13% 91%) / 0.8);
676
716
  border-radius: 1px;
677
717
  }
678
718