@livepeer-frameworks/player-svelte 0.1.3 → 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 (50) hide show
  1. package/dist/DevModePanel.svelte +14 -15
  2. package/dist/IdleScreen.svelte +12 -4
  3. package/dist/LoadingScreen.svelte +90 -50
  4. package/dist/LoadingScreen.svelte.bak +702 -0
  5. package/dist/Player.svelte +200 -53
  6. package/dist/Player.svelte.d.ts +6 -1
  7. package/dist/PlayerControls.svelte +109 -32
  8. package/dist/PlayerControls.svelte.d.ts +3 -0
  9. package/dist/StreamStateOverlay.svelte +17 -5
  10. package/dist/controls/FullscreenButton.svelte +26 -0
  11. package/dist/controls/FullscreenButton.svelte.d.ts +3 -0
  12. package/dist/controls/LiveBadge.svelte +23 -0
  13. package/dist/controls/LiveBadge.svelte.d.ts +3 -0
  14. package/dist/controls/PlayButton.svelte +26 -0
  15. package/dist/controls/PlayButton.svelte.d.ts +3 -0
  16. package/dist/controls/SettingsMenu.svelte +208 -0
  17. package/dist/controls/SettingsMenu.svelte.d.ts +28 -0
  18. package/dist/controls/SkipButton.svelte +33 -0
  19. package/dist/controls/SkipButton.svelte.d.ts +7 -0
  20. package/dist/controls/TimeDisplay.svelte +18 -0
  21. package/dist/controls/TimeDisplay.svelte.d.ts +3 -0
  22. package/dist/controls/VolumeControl.svelte +26 -0
  23. package/dist/controls/VolumeControl.svelte.d.ts +3 -0
  24. package/dist/controls/index.d.ts +7 -0
  25. package/dist/controls/index.js +7 -0
  26. package/dist/index.d.ts +3 -2
  27. package/dist/index.js +3 -1
  28. package/dist/stores/i18n.d.ts +3 -0
  29. package/dist/stores/i18n.js +4 -0
  30. package/dist/stores/index.d.ts +1 -0
  31. package/dist/stores/index.js +2 -0
  32. package/package.json +8 -8
  33. package/src/DevModePanel.svelte +14 -15
  34. package/src/IdleScreen.svelte +12 -4
  35. package/src/LoadingScreen.svelte +90 -50
  36. package/src/LoadingScreen.svelte.bak +702 -0
  37. package/src/Player.svelte +200 -53
  38. package/src/PlayerControls.svelte +109 -32
  39. package/src/StreamStateOverlay.svelte +17 -5
  40. package/src/controls/FullscreenButton.svelte +26 -0
  41. package/src/controls/LiveBadge.svelte +23 -0
  42. package/src/controls/PlayButton.svelte +26 -0
  43. package/src/controls/SettingsMenu.svelte +208 -0
  44. package/src/controls/SkipButton.svelte +33 -0
  45. package/src/controls/TimeDisplay.svelte +18 -0
  46. package/src/controls/VolumeControl.svelte +26 -0
  47. package/src/controls/index.ts +7 -0
  48. package/src/index.ts +10 -0
  49. package/src/stores/i18n.ts +7 -0
  50. package/src/stores/index.ts +3 -0
@@ -67,7 +67,7 @@
67
67
  let internalIsOpen = $state(false);
68
68
  let activeTab = $state<"config" | "stats">("config");
69
69
  let hoveredComboIndex = $state<number | null>(null);
70
- let tooltipAbove = $state(false);
70
+ let tooltipPos = $state<{ top: number; left: number } | null>(null);
71
71
  let showDisabledPlayers = $state(false);
72
72
  let comboListRef: HTMLDivElement | undefined = $state();
73
73
 
@@ -163,14 +163,12 @@
163
163
 
164
164
  function handleComboHover(index: number, e: MouseEvent) {
165
165
  hoveredComboIndex = index;
166
- if (comboListRef) {
167
- const container = comboListRef;
168
- const row = e.currentTarget as HTMLElement;
169
- const containerRect = container.getBoundingClientRect();
170
- const rowRect = row.getBoundingClientRect();
171
- const relativePosition = (rowRect.top - containerRect.top) / containerRect.height;
172
- tooltipAbove = relativePosition > 0.6;
173
- }
166
+ const row = e.currentTarget as HTMLElement;
167
+ const rowRect = row.getBoundingClientRect();
168
+ tooltipPos = {
169
+ top: Math.max(8, Math.min(rowRect.top, window.innerHeight - 200)),
170
+ left: Math.max(8, rowRect.left - 228),
171
+ };
174
172
  }
175
173
 
176
174
  // Quality monitoring
@@ -387,7 +385,10 @@
387
385
  class="fw-dev-combo"
388
386
  role="listitem"
389
387
  onmouseenter={(e) => handleComboHover(index, e)}
390
- onmouseleave={() => (hoveredComboIndex = null)}
388
+ onmouseleave={() => {
389
+ hoveredComboIndex = null;
390
+ tooltipPos = null;
391
+ }}
391
392
  >
392
393
  <button
393
394
  type="button"
@@ -446,12 +447,10 @@
446
447
  </button>
447
448
 
448
449
  <!-- Tooltip -->
449
- {#if hoveredComboIndex === index}
450
+ {#if hoveredComboIndex === index && tooltipPos}
450
451
  <div
451
- class={cn(
452
- "fw-dev-tooltip",
453
- tooltipAbove ? "fw-dev-tooltip--above" : "fw-dev-tooltip--below"
454
- )}
452
+ class="fw-dev-tooltip"
453
+ style="top: {tooltipPos.top}px; left: {tooltipPos.left}px;"
455
454
  >
456
455
  <div class="fw-dev-tooltip-header">
457
456
  <div class="fw-dev-tooltip-title">{combo.playerName}</div>
@@ -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;
@@ -584,6 +562,56 @@
584
562
  user-select: none;
585
563
  }
586
564
 
565
+ .particle:nth-child(8n + 1) {
566
+ background: hsl(var(--fw-accent, 218 79% 73%));
567
+ }
568
+ .particle:nth-child(8n + 2) {
569
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%));
570
+ }
571
+ .particle:nth-child(8n + 3) {
572
+ background: hsl(var(--fw-success, 97 52% 51%));
573
+ }
574
+ .particle:nth-child(8n + 4) {
575
+ background: hsl(var(--fw-info, 197 95% 74%));
576
+ }
577
+ .particle:nth-child(8n + 5) {
578
+ background: hsl(var(--fw-danger, 352 86% 71%));
579
+ }
580
+ .particle:nth-child(8n + 6) {
581
+ background: hsl(var(--fw-warning, 33 81% 64%));
582
+ }
583
+ .particle:nth-child(8n + 7) {
584
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.8);
585
+ }
586
+ .particle:nth-child(8n + 8) {
587
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.8);
588
+ }
589
+
590
+ .bubble:nth-child(8n + 1) {
591
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.2);
592
+ }
593
+ .bubble:nth-child(8n + 2) {
594
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.2);
595
+ }
596
+ .bubble:nth-child(8n + 3) {
597
+ background: hsl(var(--fw-success, 97 52% 51%) / 0.2);
598
+ }
599
+ .bubble:nth-child(8n + 4) {
600
+ background: hsl(var(--fw-info, 197 95% 74%) / 0.2);
601
+ }
602
+ .bubble:nth-child(8n + 5) {
603
+ background: hsl(var(--fw-danger, 352 86% 71%) / 0.2);
604
+ }
605
+ .bubble:nth-child(8n + 6) {
606
+ background: hsl(var(--fw-warning, 33 81% 64%) / 0.2);
607
+ }
608
+ .bubble:nth-child(8n + 7) {
609
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.15);
610
+ }
611
+ .bubble:nth-child(8n + 8) {
612
+ background: hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.15);
613
+ }
614
+
587
615
  .center-logo {
588
616
  position: absolute;
589
617
  top: 50%;
@@ -601,7 +629,7 @@
601
629
  .logo-pulse {
602
630
  position: absolute;
603
631
  border-radius: 50%;
604
- background: rgba(122, 162, 247, 0.15);
632
+ background: hsl(var(--fw-accent, 218 79% 73%) / 0.15);
605
633
  animation: logoPulse 3s ease-in-out infinite;
606
634
  -webkit-user-select: none;
607
635
  -moz-user-select: none;
@@ -624,7 +652,7 @@
624
652
  .logo-image {
625
653
  position: relative;
626
654
  z-index: 1;
627
- filter: drop-shadow(0 4px 8px rgba(36, 40, 59, 0.3));
655
+ filter: drop-shadow(0 4px 8px hsl(var(--fw-surface-deep, 235 21% 11%) / 0.3));
628
656
  transition: all 0.3s ease-out;
629
657
  -webkit-user-select: none;
630
658
  -moz-user-select: none;
@@ -634,7 +662,7 @@
634
662
  }
635
663
 
636
664
  .logo-image.hovered {
637
- filter: drop-shadow(0 6px 12px rgba(36, 40, 59, 0.4)) brightness(1.1);
665
+ filter: drop-shadow(0 6px 12px hsl(var(--fw-surface-deep, 235 21% 11%) / 0.4)) brightness(1.1);
638
666
  transform: scale(1.1);
639
667
  cursor: pointer;
640
668
  }
@@ -644,12 +672,12 @@
644
672
  bottom: 20%;
645
673
  left: 50%;
646
674
  transform: translateX(-50%);
647
- color: #a9b1d6;
675
+ color: hsl(var(--fw-text-muted, 227 24% 74%));
648
676
  font-size: 16px;
649
677
  font-weight: 500;
650
678
  text-align: center;
651
679
  animation: fadeInOut 2s ease-in-out infinite;
652
- text-shadow: 0 2px 4px rgba(36, 40, 59, 0.5);
680
+ text-shadow: 0 2px 4px hsl(var(--fw-surface-deep, 235 21% 11%) / 0.5);
653
681
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
654
682
  -webkit-user-select: none;
655
683
  -moz-user-select: none;
@@ -664,9 +692,21 @@
664
692
  right: 0;
665
693
  bottom: 0;
666
694
  background:
667
- radial-gradient(circle at 20% 80%, rgba(122, 162, 247, 0.03) 0%, transparent 50%),
668
- radial-gradient(circle at 80% 20%, rgba(187, 154, 247, 0.03) 0%, transparent 50%),
669
- radial-gradient(circle at 40% 40%, rgba(158, 206, 106, 0.02) 0%, transparent 50%);
695
+ radial-gradient(
696
+ circle at 20% 80%,
697
+ hsl(var(--fw-accent, 218 79% 73%) / 0.03) 0%,
698
+ transparent 50%
699
+ ),
700
+ radial-gradient(
701
+ circle at 80% 20%,
702
+ hsl(var(--fw-accent-secondary, 268 75% 76%) / 0.03) 0%,
703
+ transparent 50%
704
+ ),
705
+ radial-gradient(
706
+ circle at 40% 40%,
707
+ hsl(var(--fw-success, 97 52% 51%) / 0.02) 0%,
708
+ transparent 50%
709
+ );
670
710
  pointer-events: none;
671
711
  -webkit-user-select: none;
672
712
  -moz-user-select: none;
@@ -686,8 +726,8 @@
686
726
  position: absolute;
687
727
  width: 12px;
688
728
  height: 3px;
689
- background-color: #ffffff;
690
- box-shadow: 0 0 8px rgba(255, 255, 255, 0.8);
729
+ background-color: hsl(var(--fw-text-bright, 220 13% 91%));
730
+ box-shadow: 0 0 8px hsl(var(--fw-text-bright, 220 13% 91%) / 0.8);
691
731
  border-radius: 1px;
692
732
  }
693
733