@streamscloud/embeddable 3.4.2 → 5.0.0

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 (112) hide show
  1. package/dist/ads/ad-card/cmp.ad-card.svelte +220 -0
  2. package/dist/{short-videos/short-video-viewer/cmp.ad.svelte.d.ts → ads/ad-card/cmp.ad-card.svelte.d.ts} +3 -2
  3. package/dist/ads/ad-card/index.d.ts +3 -0
  4. package/dist/ads/ad-card/index.js +2 -0
  5. package/dist/ads/ad-card/mapper.d.ts +3 -0
  6. package/dist/ads/ad-card/mapper.js +14 -0
  7. package/dist/ads/ad-card/operations.generated.d.ts +24 -0
  8. package/dist/ads/ad-card/operations.generated.js +48 -0
  9. package/dist/ads/ad-card/operations.graphql +21 -0
  10. package/dist/ads/ad-card/types.d.ts +18 -0
  11. package/dist/ads/ad-card/types.js +1 -0
  12. package/dist/core/locale.d.ts +3 -0
  13. package/dist/products/price-helper.d.ts +18 -3
  14. package/dist/products/price-helper.js +9 -6
  15. package/dist/products/product-card/cmp.product-card.svelte +219 -0
  16. package/dist/products/product-card/cmp.product-card.svelte.d.ts +15 -0
  17. package/dist/products/product-card/index.d.ts +4 -0
  18. package/dist/products/product-card/index.js +2 -0
  19. package/dist/products/product-card/mapper.d.ts +3 -0
  20. package/dist/products/product-card/mapper.js +22 -0
  21. package/dist/products/product-card/operations.generated.d.ts +26 -0
  22. package/dist/products/product-card/operations.generated.js +59 -0
  23. package/dist/products/product-card/operations.graphql +23 -0
  24. package/dist/products/product-card/product-card-localization.d.ts +8 -0
  25. package/dist/{short-videos/short-video-viewer/short-video-product-localization.js → products/product-card/product-card-localization.js} +1 -1
  26. package/dist/products/product-card/types.d.ts +12 -0
  27. package/dist/products/product-card/types.js +1 -0
  28. package/dist/short-videos/short-video-viewer/cmp.attachments.svelte +12 -40
  29. package/dist/short-videos/short-video-viewer/cmp.attachments.svelte.d.ts +1 -1
  30. package/dist/short-videos/short-video-viewer/cmp.short-video-controls.svelte +145 -0
  31. package/dist/short-videos/short-video-viewer/cmp.short-video-controls.svelte.d.ts +19 -0
  32. package/dist/short-videos/short-video-viewer/cmp.short-video-viewer.svelte +46 -20
  33. package/dist/short-videos/short-video-viewer/cmp.short-video-viewer.svelte.d.ts +4 -2
  34. package/dist/short-videos/short-video-viewer/index.d.ts +3 -7
  35. package/dist/short-videos/short-video-viewer/index.js +2 -5
  36. package/dist/short-videos/short-video-viewer/mapper.d.ts +1 -1
  37. package/dist/short-videos/short-video-viewer/mapper.js +25 -22
  38. package/dist/short-videos/short-video-viewer/operations.generated.d.ts +6 -8
  39. package/dist/short-videos/short-video-viewer/operations.generated.js +10 -17
  40. package/dist/short-videos/short-video-viewer/operations.graphql +8 -10
  41. package/dist/short-videos/short-video-viewer/short-video-attachments-localization.d.ts +3 -7
  42. package/dist/short-videos/short-video-viewer/short-video-attachments-localization.js +0 -14
  43. package/dist/short-videos/short-video-viewer/short-video-viewer-localization.d.ts +3 -3
  44. package/dist/short-videos/short-video-viewer/types.d.ts +23 -13
  45. package/dist/short-videos/short-video-viewer/ui-manager.svelte.d.ts +5 -0
  46. package/dist/short-videos/short-video-viewer/ui-manager.svelte.js +15 -2
  47. package/dist/short-videos/short-videos-player/cmp.short-videos-player.svelte +25 -163
  48. package/dist/short-videos/short-videos-player/cmp.short-videos-player.svelte.d.ts +7 -2
  49. package/dist/short-videos/short-videos-player/controls.svelte +125 -125
  50. package/dist/short-videos/short-videos-player/controls.svelte.d.ts +4 -2
  51. package/dist/short-videos/short-videos-player/index.d.ts +2 -0
  52. package/dist/short-videos/short-videos-player/index.js +12 -3
  53. package/dist/short-videos/short-videos-player/operations.generated.d.ts +6 -8
  54. package/dist/short-videos/short-videos-player/operations.generated.js +10 -17
  55. package/dist/short-videos/short-videos-player/short-videos-player-localization.d.ts +1 -3
  56. package/dist/short-videos/short-videos-player/short-videos-player-localization.js +0 -2
  57. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte +211 -0
  58. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte.d.ts +18 -0
  59. package/dist/short-videos/short-videos-player/types.d.ts +10 -8
  60. package/dist/short-videos/short-videos-player/ui-manager.svelte.d.ts +4 -3
  61. package/dist/short-videos/short-videos-player/ui-manager.svelte.js +9 -8
  62. package/dist/streams/layout/element-views/price-element-view.svelte +5 -4
  63. package/dist/streams/layout/models/mapper.js +10 -18
  64. package/dist/streams/layout/models/stream-layout-short-video-model.d.ts +1 -0
  65. package/dist/streams/stream-player/cmp.stream-player.svelte +23 -8
  66. package/dist/streams/stream-player/cmp.stream-player.svelte.d.ts +3 -1
  67. package/dist/streams/stream-player/controls.svelte +87 -74
  68. package/dist/streams/stream-player/controls.svelte.d.ts +2 -0
  69. package/dist/streams/stream-player/index.d.ts +2 -0
  70. package/dist/streams/stream-player/index.js +4 -3
  71. package/dist/streams/stream-player/mapper.d.ts +1 -1
  72. package/dist/streams/stream-player/mapper.js +1 -1
  73. package/dist/streams/stream-player/stream-overview.svelte +12 -1
  74. package/dist/streams/stream-player/stream-overview.svelte.d.ts +1 -0
  75. package/dist/streams/stream-player/stream-player-localization.d.ts +1 -3
  76. package/dist/streams/stream-player/stream-player-localization.js +0 -2
  77. package/dist/streams/stream-player/ui-manager.svelte.d.ts +4 -2
  78. package/dist/streams/stream-player/ui-manager.svelte.js +10 -5
  79. package/dist/ui/button/resources/button-theme.svelte +1 -0
  80. package/dist/ui/line-clamp/cmp.line-clamp.svelte +35 -13
  81. package/dist/ui/player/cmp.player-slider.svelte +74 -9
  82. package/dist/ui/progress/cmp.progress.svelte +4 -1
  83. package/dist/ui/seek-bar/cmp.seek-bar.svelte +112 -28
  84. package/dist/ui/seek-bar/cmp.seek-bar.svelte.d.ts +3 -0
  85. package/dist/ui/shadow-dom/index.d.ts +2 -1
  86. package/dist/ui/shadow-dom/index.js +2 -1
  87. package/dist/ui/shadow-dom/{shadow-host.d.ts → modal-shadow-host.d.ts} +1 -1
  88. package/dist/ui/shadow-dom/modal-shadow-host.js +21 -0
  89. package/dist/ui/shadow-dom/shadow-root-service.d.ts +1 -0
  90. package/dist/ui/shadow-dom/shadow-root-service.js +23 -0
  91. package/dist/ui/video/cmp.video.svelte +46 -38
  92. package/dist/ui/video/cmp.video.svelte.d.ts +3 -0
  93. package/dist/ui/video/index.d.ts +1 -0
  94. package/dist/ui/video/index.js +1 -0
  95. package/dist/ui/video/types.d.ts +4 -0
  96. package/dist/ui/video/types.js +5 -0
  97. package/package.json +5 -1
  98. package/dist/short-videos/short-video-viewer/cmp.ad.svelte +0 -140
  99. package/dist/short-videos/short-video-viewer/cmp.product.svelte +0 -168
  100. package/dist/short-videos/short-video-viewer/cmp.product.svelte.d.ts +0 -14
  101. package/dist/short-videos/short-video-viewer/cmp.short-video-details.svelte +0 -125
  102. package/dist/short-videos/short-video-viewer/cmp.short-video-details.svelte.d.ts +0 -14
  103. package/dist/short-videos/short-video-viewer/cmp.social-interactions.svelte +0 -69
  104. package/dist/short-videos/short-video-viewer/cmp.social-interactions.svelte.d.ts +0 -10
  105. package/dist/short-videos/short-video-viewer/description.svelte +0 -53
  106. package/dist/short-videos/short-video-viewer/description.svelte.d.ts +0 -9
  107. package/dist/short-videos/short-video-viewer/short-video-details-localization.d.ts +0 -14
  108. package/dist/short-videos/short-video-viewer/short-video-details-localization.js +0 -17
  109. package/dist/short-videos/short-video-viewer/short-video-product-localization.d.ts +0 -8
  110. package/dist/short-videos/short-videos-player/action-button.svelte +0 -38
  111. package/dist/short-videos/short-videos-player/action-button.svelte.d.ts +0 -10
  112. package/dist/ui/shadow-dom/shadow-host.js +0 -32
@@ -1,30 +1,104 @@
1
- <script lang="ts">let { value, on } = $props();
1
+ <script lang="ts">let { value, listenParentClicks = false, on } = $props();
2
+ let seekBarRef;
2
3
  let progressRef;
3
- let valueRef;
4
+ let isDragging = $state(false);
5
+ const cssValue = $derived(`${100 * (value <= 1 ? value : 1)}%`);
4
6
  const handleSeek = (e) => {
7
+ if (!progressRef) {
8
+ return;
9
+ }
5
10
  e.stopPropagation();
6
11
  const { left, width } = progressRef.getBoundingClientRect();
7
12
  const x = e.clientX - left;
8
- const percent = x / width;
9
- value = percent;
10
- valueRef.style.transition = 'none';
11
- valueRef.style.width = `${100 * percent}%`;
12
- setTimeout(() => {
13
- valueRef.style.transition = '';
14
- }, 0);
13
+ const percent = Math.max(0, Math.min(1, x / width));
15
14
  on === null || on === void 0 ? void 0 : on.seek(percent);
16
15
  };
16
+ const handleParentClick = (e) => {
17
+ e.preventDefault();
18
+ e.stopPropagation();
19
+ if (!progressRef || !seekBarRef || isDragging) {
20
+ return;
21
+ }
22
+ const seekBarRect = progressRef.getBoundingClientRect();
23
+ if (e.clientX >= seekBarRect.left && e.clientX <= seekBarRect.right) {
24
+ const x = e.clientX - seekBarRect.left;
25
+ const percent = Math.max(0, Math.min(1, x / seekBarRect.width));
26
+ on === null || on === void 0 ? void 0 : on.seek(percent);
27
+ }
28
+ };
29
+ const onMouseMove = (e) => {
30
+ if (isDragging) {
31
+ handleSeek(e);
32
+ }
33
+ };
34
+ const onMouseUp = () => {
35
+ var _a;
36
+ isDragging = false;
37
+ window.removeEventListener('mousemove', onMouseMove);
38
+ window.removeEventListener('mouseup', onMouseUp);
39
+ (_a = on === null || on === void 0 ? void 0 : on.dragEnd) === null || _a === void 0 ? void 0 : _a.call(on);
40
+ };
41
+ const onMouseDown = (e) => {
42
+ var _a;
43
+ isDragging = true;
44
+ (_a = on === null || on === void 0 ? void 0 : on.dragStart) === null || _a === void 0 ? void 0 : _a.call(on);
45
+ handleSeek(e);
46
+ window.addEventListener('mousemove', onMouseMove);
47
+ window.addEventListener('mouseup', onMouseUp);
48
+ };
49
+ const handleScrubberKeyDown = (event) => {
50
+ const step = 0.05;
51
+ let newValue;
52
+ if (event.key === 'ArrowLeft') {
53
+ newValue = Math.max(0, value - step);
54
+ }
55
+ else if (event.key === 'ArrowRight') {
56
+ newValue = Math.min(1, value + step);
57
+ }
58
+ else if (event.key === 'Home') {
59
+ newValue = 0;
60
+ }
61
+ else if (event.key === 'End') {
62
+ newValue = 1;
63
+ }
64
+ if (newValue !== undefined) {
65
+ event.preventDefault();
66
+ on === null || on === void 0 ? void 0 : on.seek(newValue);
67
+ }
68
+ };
69
+ $effect(() => {
70
+ if (listenParentClicks && seekBarRef) {
71
+ const parent = seekBarRef.parentElement;
72
+ if (parent) {
73
+ parent.addEventListener('click', handleParentClick);
74
+ return () => {
75
+ parent.removeEventListener('click', handleParentClick);
76
+ };
77
+ }
78
+ }
79
+ });
80
+ $effect(() => {
81
+ return () => {
82
+ window.removeEventListener('mousemove', onMouseMove);
83
+ window.removeEventListener('mouseup', onMouseUp);
84
+ };
85
+ });
17
86
  </script>
18
87
 
19
- <div class="seek-bar" onclick={handleSeek} onkeydown={() => ({})} role="none">
88
+ <div class="seek-bar" onmousedown={onMouseDown} onkeydown={() => ({})} role="none" bind:this={seekBarRef}>
20
89
  <div class="seek-bar__container" bind:this={progressRef}>
21
- <span
22
- class="seek-bar__value"
23
- class:seek-bar__value--animate={value > 0.001 && value < 0.96}
24
- style="width: {`${100 * (value <= 1 ? value : 1)}%`}"
25
- bind:this={valueRef}>
26
- &nbsp;
27
- </span>
90
+ <span class="seek-bar__value" style="width: {cssValue}"> &nbsp; </span>
91
+ <div
92
+ class="seek-bar__scrubber"
93
+ style="left: {cssValue}"
94
+ role="slider"
95
+ tabindex="0"
96
+ aria-valuemin="0"
97
+ aria-valuemax="1"
98
+ aria-valuenow={value}
99
+ aria-label="Media position slider"
100
+ onkeydown={handleScrubberKeyDown}>
101
+ </div>
28
102
  </div>
29
103
  </div>
30
104
 
@@ -40,24 +114,34 @@ const handleSeek = (e) => {
40
114
  }
41
115
  }
42
116
  .seek-bar {
43
- --_seek-bar--height: var(--seek-bar--height, 0.25em);
44
- --_seek-bar--back-color: var(--seek-bar--back-color, #b0b0b0);
45
- --_seek-bar--front-color: var(--seek-bar--front-color, #ffffff);
46
117
  cursor: pointer;
118
+ position: relative;
119
+ --_seek-bar--container-color: var(--seek-bar--container-color, #b0b0b0);
120
+ --_seek-bar--value-color: var(--seek-bar--value-color, #fff);
121
+ --_seek-bar--scrubber-color: var(--seek-bar--scrubber-color, #fff);
47
122
  }
48
123
  .seek-bar__container {
49
124
  width: 100%;
50
- background: var(--_seek-bar--back-color);
51
- height: var(--_seek-bar--height);
52
- box-shadow: 0 2px 3px rgba(0, 0, 0, 0.25) inset;
53
- border-radius: calc(var(--_seek-bar--height) / 2);
54
- overflow: hidden;
125
+ background: var(--_seek-bar--container-color);
126
+ height: 0.3125rem;
127
+ position: relative;
55
128
  }
56
129
  .seek-bar__value {
57
- background: var(--_seek-bar--front-color);
130
+ background: var(--_seek-bar--value-color);
131
+ border-color: var(--_seek-bar--container-color);
132
+ border-width: 0.0625rem;
58
133
  display: inline-block;
59
134
  height: 100%;
60
135
  }
61
- .seek-bar__value--animate {
62
- transition: width 500ms;
136
+ .seek-bar__scrubber {
137
+ position: absolute;
138
+ top: 50%;
139
+ width: 0.75rem;
140
+ height: 0.75rem;
141
+ background: var(--_seek-bar--scrubber-color);
142
+ border-color: var(--_seek-bar--container-color);
143
+ border-width: 0.0625rem;
144
+ border-radius: 50%;
145
+ transform: translate(-50%, -50%);
146
+ z-index: 1;
63
147
  }</style>
@@ -3,8 +3,11 @@ type Props = {
3
3
  * 0-1
4
4
  * */
5
5
  value: number;
6
+ listenParentClicks?: boolean;
6
7
  on: {
7
8
  seek: (e: number) => void;
9
+ dragStart?: () => void;
10
+ dragEnd?: () => void;
8
11
  };
9
12
  };
10
13
  declare const Cmp: import("svelte").Component<Props, {}, "">;
@@ -1 +1,2 @@
1
- export { ShadowHost } from './shadow-host';
1
+ export { ModalShadowHost } from './modal-shadow-host';
2
+ export { createShadowRoot } from './shadow-root-service';
@@ -1 +1,2 @@
1
- export { ShadowHost } from './shadow-host';
1
+ export { ModalShadowHost } from './modal-shadow-host';
2
+ export { createShadowRoot } from './shadow-root-service';
@@ -1,4 +1,4 @@
1
- export declare class ShadowHost {
1
+ export declare class ModalShadowHost {
2
2
  shadowRoot: ShadowRoot;
3
3
  private host;
4
4
  constructor();
@@ -0,0 +1,21 @@
1
+ import { createShadowRoot } from './shadow-root-service';
2
+ export class ModalShadowHost {
3
+ shadowRoot;
4
+ host;
5
+ constructor() {
6
+ const host = document.createElement('div');
7
+ this.host = host;
8
+ this.shadowRoot = createShadowRoot(host);
9
+ host.style.position = 'fixed';
10
+ host.style.inset = '0';
11
+ host.style.zIndex = '9999';
12
+ }
13
+ attachToBody() {
14
+ document.getElementsByTagName('html')[0].style.overflow = 'hidden';
15
+ document.body.appendChild(this.host);
16
+ }
17
+ remove() {
18
+ this.host.remove();
19
+ document.getElementsByTagName('html')[0].style.overflow = '';
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ export declare const createShadowRoot: (host: HTMLElement) => ShadowRoot;
@@ -0,0 +1,23 @@
1
+ import normalize from './_normalize.scss?raw';
2
+ import reset from './_reset.scss?raw';
3
+ export const createShadowRoot = (host) => {
4
+ prepareShadowRootHost(host);
5
+ const shadowRoot = host.attachShadow({ mode: 'open' });
6
+ const link = document.createElement('link');
7
+ link.rel = 'stylesheet';
8
+ link.href = 'https://fonts.googleapis.com/css2?family=Inter:wght@300..700&display=swap';
9
+ shadowRoot.appendChild(link);
10
+ const styleElement = document.createElement('style');
11
+ styleElement.textContent = normalize + reset;
12
+ shadowRoot.appendChild(styleElement);
13
+ return shadowRoot;
14
+ };
15
+ const prepareShadowRootHost = (host) => {
16
+ host.style.all = 'unset';
17
+ host.style.lineHeight = '1.15';
18
+ host.style.font = '16px Inter, sans-serif, arial';
19
+ host.style.fontWeight = '400';
20
+ host.style.margin = '0';
21
+ host.style.boxSizing = 'border-box';
22
+ host.style.textAlign = 'initial';
23
+ };
@@ -12,13 +12,14 @@ import { Icon, IconColor } from '../icon';
12
12
  import { MediaVolumeManager, PlaybackManager } from '../media-playback';
13
13
  import { Progress } from '../progress';
14
14
  import { SeekBar } from '../seek-bar';
15
+ import { ScrubberPosition } from './types';
15
16
  import IconPause from '@fluentui/svg-icons/icons/pause_20_regular.svg?raw';
16
17
  import IconPlay from '@fluentui/svg-icons/icons/play_20_regular.svg?raw';
17
18
  import IconSpeaker from '@fluentui/svg-icons/icons/speaker_2_20_regular.svg?raw';
18
19
  import IconSpeakerMute from '@fluentui/svg-icons/icons/speaker_mute_20_regular.svg?raw';
19
20
  import { onDestroy, onMount, untrack } from 'svelte';
20
- import { slide } from 'svelte/transition';
21
- let { src, poster, id = randomNanoid(), controls = true, autoplay = false, loop = false, inert = false, intersectionContainer, on } = $props();
21
+ import { fade } from 'svelte/transition';
22
+ let { src, poster, id = randomNanoid(), controls = true, autoplay = false, loop = false, inert = false, hideSpeaker = false, intersectionContainer, scrubberPosition = ScrubberPosition.Bottom, on } = $props();
22
23
  onMount(() => {
23
24
  var _a;
24
25
  PlaybackManager.registerMountedPlayer(id, {
@@ -29,12 +30,10 @@ onMount(() => {
29
30
  pause();
30
31
  },
31
32
  onStop: (inRespectToNewlyActivatedVideo) => {
32
- if (inRespectToNewlyActivatedVideo && autoplay === 'on-appearance') {
33
- pause();
34
- }
35
- else {
36
- stop();
33
+ if (autoplay === 'on-appearance' && inRespectToNewlyActivatedVideo) {
34
+ return;
37
35
  }
36
+ stop();
38
37
  },
39
38
  onToggle: () => {
40
39
  togglePlay();
@@ -50,8 +49,8 @@ onMount(() => {
50
49
  }
51
50
  });
52
51
  (_a = on === null || on === void 0 ? void 0 : on.loaded) === null || _a === void 0 ? void 0 : _a.call(on, { id, src });
53
- if (video) {
54
- intersectionObserver.observe(video);
52
+ if (videoContainerRef) {
53
+ intersectionObserver.observe(videoContainerRef);
55
54
  }
56
55
  });
57
56
  onDestroy(() => {
@@ -64,8 +63,8 @@ onDestroy(() => {
64
63
  }
65
64
  });
66
65
  let video = $state.raw(undefined);
66
+ let videoContainerRef = $state.raw(undefined);
67
67
  let showControlsOnHover = $state(false);
68
- let needShowProgress = $state(false);
69
68
  let isVideoPaused = $state(true);
70
69
  let percentageCompleted = $state(0);
71
70
  let everActivated = $state(false);
@@ -187,9 +186,7 @@ const onTimeUpdate = (e) => {
187
186
  percentageCompleted = video.currentTime / video.duration || 0;
188
187
  notifyProgress();
189
188
  };
190
- const onLoaded = (e) => __awaiter(void 0, void 0, void 0, function* () {
191
- const video = e.target;
192
- needShowProgress = video.duration >= 8;
189
+ const onLoaded = () => __awaiter(void 0, void 0, void 0, function* () {
193
190
  setVolume(MediaVolumeManager.volumeLevel);
194
191
  setMuted(MediaVolumeManager.isMuted);
195
192
  });
@@ -233,11 +230,13 @@ const notifyProgress = () => {
233
230
  const handleSeek = (percent) => {
234
231
  if (video) {
235
232
  video.currentTime = video.duration * percent;
233
+ percentageCompleted = percent;
234
+ notifyProgress();
236
235
  }
237
236
  };
238
237
  </script>
239
238
 
240
- <div class="video" onmouseenter={() => setShowControlsOnHover(true)} onmouseleave={() => setShowControlsOnHover(false)} role="none" inert={inert}>
239
+ <div class="video" role="none" inert={inert} bind:this={videoContainerRef}>
241
240
  <video
242
241
  class="video__video"
243
242
  class:video__video--not-activated={!everActivated}
@@ -270,7 +269,7 @@ const handleSeek = (percent) => {
270
269
  <Icon src={IconPause} color={IconColor.White} />
271
270
  </button>
272
271
  {/if}
273
- {#if showControlsOnHover || MediaVolumeManager.isMuted}
272
+ {#if (showControlsOnHover || MediaVolumeManager.isMuted) && !hideSpeaker}
274
273
  <button type="button" aria-label={MediaVolumeManager.isMuted ? 'mute' : 'unmute'} class="video__mute-button" onclick={toggleMute}>
275
274
  {#if MediaVolumeManager.isMuted}
276
275
  <Icon src={IconSpeakerMute} color={IconColor.White} />
@@ -281,18 +280,24 @@ const handleSeek = (percent) => {
281
280
  {/if}
282
281
 
283
282
  {#if everActivated}
284
- <div class="video__progress-container">
285
- {#if needShowProgress}
286
- {#if showControlsOnHover}
287
- <div class="video__seek-bar" onclick={(e) => e.stopPropagation()} onkeydown={() => ({})} role="none" transition:slide>
288
- <SeekBar value={percentageCompleted} on={{ seek: handleSeek }} />
289
- </div>
290
- {/if}
291
- {#if !showControlsOnHover}
292
- <div class="video__progress" in:slide>
293
- <Progress value={percentageCompleted} />
294
- </div>
295
- {/if}
283
+ <div
284
+ class="video__progress-container"
285
+ class:video__progress-container--top={scrubberPosition === ScrubberPosition.Top}
286
+ class:video__progress-container--bottom={scrubberPosition === ScrubberPosition.Bottom}
287
+ onmouseenter={() => setShowControlsOnHover(true)}
288
+ onmouseleave={() => setShowControlsOnHover(false)}
289
+ onclick={(e) => e.stopPropagation()}
290
+ onkeydown={() => ({})}
291
+ role="none">
292
+ {#if !showControlsOnHover && isVideoPaused}
293
+ <div class="video__progress">
294
+ <Progress value={percentageCompleted} />
295
+ </div>
296
+ {/if}
297
+ {#if showControlsOnHover}
298
+ <div class="video__progress" transition:fade={{ duration: isVideoPaused ? 0 : 300 }}>
299
+ <SeekBar value={percentageCompleted} listenParentClicks={true} on={{ seek: handleSeek }} />
300
+ </div>
296
301
  {/if}
297
302
  </div>
298
303
  {/if}
@@ -316,7 +321,7 @@ const handleSeek = (percent) => {
316
321
  --_video--border-radius: var(--video--border-radius, 0);
317
322
  --_video--media-fit: var(--video--media-fit, contain);
318
323
  --_video--poster--media-fit: var(--video--poster--media-fit, cover);
319
- --_video--progress--background-color: var(--video--progress--background-color, hsla(0, 0%, 0%, 0.5));
324
+ --_video--progress--background-color: var(--video--progress--background-color, transparent);
320
325
  --_video--progress--back-color: var(--video--progress--back-color);
321
326
  --_video--progress--front-color: var(--video--progress--front-color);
322
327
  height: 100%;
@@ -382,20 +387,23 @@ const handleSeek = (percent) => {
382
387
  }
383
388
  .video__progress-container {
384
389
  position: absolute;
385
- bottom: 0;
386
390
  left: 0;
387
391
  right: 0;
392
+ z-index: 1;
393
+ min-height: 1.5625rem;
394
+ padding: 0 0.25rem;
395
+ }
396
+ .video__progress-container--top {
397
+ top: 0.5625rem;
398
+ bottom: auto;
399
+ }
400
+ .video__progress-container--bottom {
401
+ top: auto;
402
+ bottom: 0;
388
403
  }
389
404
  .video__progress {
390
- margin-bottom: 1px;
391
- --progress--height: 0.125em;
405
+ --progress--height: 0.3125em;
392
406
  --progress--back-color: var(--_video--progress--back-color);
393
407
  --progress--front-color: var(--_video--progress--front-color);
394
- }
395
- .video__seek-bar {
396
- padding: 0.625em 0.5em;
397
- background: var(--_video--progress--background-color);
398
- cursor: default;
399
- --seek-bar--back-color: var(--_video--progress--back-color);
400
- --seek-bar--front-color: var(--_video--progress--front-color);
408
+ padding: 0.625rem 0;
401
409
  }</style>
@@ -1,3 +1,4 @@
1
+ import { ScrubberPosition } from './types';
1
2
  type Props = {
2
3
  src: string;
3
4
  poster: string | null;
@@ -7,6 +8,8 @@ type Props = {
7
8
  loop?: boolean;
8
9
  intersectionContainer?: HTMLElement;
9
10
  inert?: boolean;
11
+ hideSpeaker?: boolean;
12
+ scrubberPosition?: ScrubberPosition;
10
13
  on?: {
11
14
  loaded?: (data: {
12
15
  id: string;
@@ -1 +1,2 @@
1
1
  export { default as Video } from './cmp.video.svelte';
2
+ export { ScrubberPosition } from './types';
@@ -1 +1,2 @@
1
1
  export { default as Video } from './cmp.video.svelte';
2
+ export { ScrubberPosition } from './types';
@@ -0,0 +1,4 @@
1
+ export declare enum ScrubberPosition {
2
+ Top = 0,
3
+ Bottom = 1
4
+ }
@@ -0,0 +1,5 @@
1
+ export var ScrubberPosition;
2
+ (function (ScrubberPosition) {
3
+ ScrubberPosition[ScrubberPosition["Top"] = 0] = "Top";
4
+ ScrubberPosition[ScrubberPosition["Bottom"] = 1] = "Bottom";
5
+ })(ScrubberPosition || (ScrubberPosition = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/embeddable",
3
- "version": "3.4.2",
3
+ "version": "5.0.0",
4
4
  "author": "StreamsCloud",
5
5
  "repository": "https://github.com/StreamsCloud/streamscloud-frontend-packages.git",
6
6
  "type": "module",
@@ -36,6 +36,10 @@
36
36
  "types": "./dist/short-videos/short-videos-player/index.d.ts",
37
37
  "svelte": "./dist/short-videos/short-videos-player/index.js"
38
38
  },
39
+ "./short-video-viewer": {
40
+ "types": "./dist/short-videos/short-video-viewer/index.d.ts",
41
+ "svelte": "./dist/short-videos/short-video-viewer/index.js"
42
+ },
39
43
  "./stream-layout": {
40
44
  "types": "./dist/streams/layout/index.d.ts",
41
45
  "import": "./dist/streams/layout/index.js",
@@ -1,140 +0,0 @@
1
- <script lang="ts">import { Image } from '../../ui/image';
2
- import { LineClamp } from '../../ui/line-clamp';
3
- import { ProportionalContainer } from '../../ui/proportional-container';
4
- let { ad } = $props();
5
- </script>
6
-
7
- <div class="ad">
8
- <ProportionalContainer ratio={234 / 277}>
9
- <Image src={ad.image} alt={ad.title} />
10
- </ProportionalContainer>
11
- <div class="ad__info">
12
- {#if ad.title}
13
- <div class="ad__title">{ad.title}</div>
14
- {/if}
15
- {#if ad.description}
16
- <div class="ad__description">
17
- <LineClamp value={ad.description} maxLines={2} />
18
- </div>
19
- {/if}
20
- {#if ad.price && ad.currency}
21
- <div class="ad__price">{ad.currency} {ad.price}</div>
22
- {/if}
23
- {#if ad.ctaButton}
24
- <div class="ad__button">
25
- <a
26
- href={ad.ctaButton.url}
27
- target="_blank"
28
- class="short-video-ad-viewer__link"
29
- style="background-color: {ad.ctaButton.background}; color: {ad.ctaButton.textColor}; border: {ad.ctaButton
30
- .border}; text-decoration: none; padding: 0.5em 1em; border-radius: 0.25em; display: inline-block;">
31
- {ad.ctaButton.text}
32
- </a>
33
- </div>
34
- {/if}
35
- </div>
36
- </div>
37
-
38
- <style>@keyframes fadeIn {
39
- 0% {
40
- opacity: 1;
41
- }
42
- 50% {
43
- opacity: 0.4;
44
- }
45
- 100% {
46
- opacity: 1;
47
- }
48
- }
49
- .ad {
50
- --image--border-radius: 0.25rem;
51
- --image--object-fit: fit;
52
- --image--width: auto;
53
- --image--height: auto;
54
- width: 100%;
55
- height: max-content;
56
- display: flex;
57
- flex-direction: column;
58
- position: relative;
59
- container-type: inline-size;
60
- aspect-ratio: 9/16;
61
- background-color: #fafafa;
62
- border: 0.038125rem solid #999999;
63
- border-radius: 0.5rem;
64
- padding: 0.75rem 0.75rem 1.125rem;
65
- justify-content: space-between;
66
- /* Set 'container-type: inline-size;' to reference container*/
67
- }
68
- @container (width < 230px) {
69
- .ad {
70
- padding: 0.5rem 0.5rem 0.75rem;
71
- }
72
- }
73
- .ad__info {
74
- display: flex;
75
- flex-direction: column;
76
- gap: 0.375rem;
77
- margin-top: 0.1875rem;
78
- /* Set 'container-type: inline-size;' to reference container*/
79
- }
80
- @container (width < 230px) {
81
- .ad__info {
82
- gap: 0.25rem;
83
- margin-top: 0.125rem;
84
- }
85
- }
86
- .ad__title {
87
- font-weight: 700;
88
- font-size: 1.125rem;
89
- line-height: 1.375rem;
90
- min-height: 1.375rem;
91
- color: #000000;
92
- /* Set 'container-type: inline-size;' to reference container*/
93
- }
94
- @container (width < 230px) {
95
- .ad__title {
96
- font-size: 0.75rem;
97
- line-height: 0.875rem;
98
- min-height: 0.875rem;
99
- }
100
- }
101
- .ad__description {
102
- font-weight: 400;
103
- color: #6b7280;
104
- font-size: 0.9375rem;
105
- line-height: 1.375rem;
106
- min-height: 1.375rem;
107
- /* Set 'container-type: inline-size;' to reference container*/
108
- }
109
- @container (width < 230px) {
110
- .ad__description {
111
- font-size: 0.625rem;
112
- line-height: 0.875rem;
113
- min-height: 0.875rem;
114
- }
115
- }
116
- .ad__price {
117
- font-size: 1.875rem;
118
- font-weight: 700;
119
- text-align: right;
120
- min-height: 3.53125rem;
121
- color: #000000;
122
- /* Set 'container-type: inline-size;' to reference container*/
123
- }
124
- @container (width < 230px) {
125
- .ad__price {
126
- font-size: 1.25rem;
127
- min-height: 2.40625rem;
128
- }
129
- }
130
- .ad__button {
131
- display: flex;
132
- justify-content: center;
133
- margin-top: auto;
134
- width: 100%;
135
- }
136
- :global([data-theme="dark"]) .ad {
137
- background-color: #121212;
138
- color: #ffffff;
139
- border-color: #1e1e1e;
140
- }</style>