@streamscloud/embeddable 11.0.0 → 12.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 (174) hide show
  1. package/dist/ads/ad-card/cmp.ad-card.svelte +4 -4
  2. package/dist/ads/ad-card/cmp.ad-card.svelte.d.ts +2 -0
  3. package/dist/content-player/cmp.content-player.svelte +63 -128
  4. package/dist/content-player/content-player-config.svelte.d.ts +3 -10
  5. package/dist/content-player/content-player-config.svelte.js +3 -21
  6. package/dist/content-player/content-player-settings.d.ts +7 -21
  7. package/dist/content-player/content-player-settings.js +0 -4
  8. package/dist/content-player/controls-and-attachments.svelte +39 -5
  9. package/dist/content-player/overview-panel.svelte +14 -6
  10. package/dist/content-player/overview-panel.svelte.d.ts +5 -1
  11. package/dist/content-player/ui-manager.svelte.d.ts +0 -2
  12. package/dist/content-player/ui-manager.svelte.js +0 -2
  13. package/dist/media-center/config/internal-media-center-config.d.ts +7 -3
  14. package/dist/media-center/config/internal-media-center-config.js +27 -24
  15. package/dist/media-center/config/operations.generated.d.ts +10 -3
  16. package/dist/media-center/config/operations.generated.js +17 -6
  17. package/dist/media-center/config/operations.graphql +11 -4
  18. package/dist/media-center/config/types.d.ts +5 -2
  19. package/dist/media-center/media-center/cmp.media-center.svelte +195 -149
  20. package/dist/media-center/media-center/cmp.media-center.svelte.d.ts +2 -19
  21. package/dist/media-center/media-center/discover/data-loading.d.ts +8 -0
  22. package/dist/media-center/media-center/discover/data-loading.js +35 -0
  23. package/dist/media-center/media-center/discover/discover-header-localization.d.ts +6 -0
  24. package/dist/media-center/media-center/discover/discover-header-localization.js +15 -0
  25. package/dist/media-center/media-center/discover/discover-header.svelte +214 -0
  26. package/dist/media-center/media-center/discover/discover-header.svelte.d.ts +9 -0
  27. package/dist/media-center/media-center/discover/discover-view-handler.svelte.d.ts +28 -0
  28. package/dist/media-center/media-center/discover/discover-view-handler.svelte.js +101 -0
  29. package/dist/media-center/media-center/discover/discover-view-localization.d.ts +6 -0
  30. package/dist/media-center/media-center/discover/discover-view-localization.js +15 -0
  31. package/dist/media-center/media-center/discover/discover-view.svelte +238 -0
  32. package/dist/media-center/media-center/discover/{discover-panel.svelte.d.ts → discover-view.svelte.d.ts} +4 -4
  33. package/dist/media-center/media-center/discover/index.d.ts +2 -2
  34. package/dist/media-center/media-center/discover/index.js +2 -2
  35. package/dist/media-center/media-center/discover/types.svelte.d.ts +20 -0
  36. package/dist/media-center/media-center/discover/types.svelte.js +20 -0
  37. package/dist/media-center/media-center/feed/feed-handler.svelte.d.ts +50 -0
  38. package/dist/media-center/media-center/feed/feed-handler.svelte.js +84 -0
  39. package/dist/media-center/media-center/feed/feed-providers-generator.d.ts +11 -0
  40. package/dist/media-center/media-center/feed/feed-providers-generator.js +79 -0
  41. package/dist/media-center/media-center/feed/index.d.ts +1 -0
  42. package/dist/media-center/media-center/feed/index.js +1 -0
  43. package/dist/media-center/media-center/feed/types.d.ts +12 -0
  44. package/dist/media-center/media-center/handlers/categories-handler.svelte.d.ts +9 -3
  45. package/dist/media-center/media-center/handlers/categories-handler.svelte.js +7 -4
  46. package/dist/media-center/media-center/handlers/index.d.ts +1 -1
  47. package/dist/media-center/media-center/handlers/index.js +1 -1
  48. package/dist/media-center/media-center/handlers/media-center-settings-handler.svelte.d.ts +19 -0
  49. package/dist/media-center/media-center/handlers/media-center-settings-handler.svelte.js +26 -0
  50. package/dist/media-center/media-center/header-footer/media-center-footer.svelte +3 -7
  51. package/dist/media-center/media-center/header-footer/media-center-header-localization.d.ts +1 -0
  52. package/dist/media-center/media-center/header-footer/media-center-header-localization.js +6 -0
  53. package/dist/media-center/media-center/header-footer/media-center-header-mobile.svelte +25 -36
  54. package/dist/media-center/media-center/header-footer/media-center-header-mobile.svelte.d.ts +2 -1
  55. package/dist/media-center/media-center/header-footer/media-center-header.svelte +14 -11
  56. package/dist/media-center/media-center/header-footer/media-center-header.svelte.d.ts +1 -2
  57. package/dist/media-center/media-center/media-center-context.svelte.d.ts +31 -13
  58. package/dist/media-center/media-center/media-center-context.svelte.js +71 -35
  59. package/dist/media-center/media-center/menu/menu-localization.d.ts +2 -11
  60. package/dist/media-center/media-center/menu/menu-localization.js +6 -45
  61. package/dist/media-center/media-center/menu/menu.svelte +31 -23
  62. package/dist/media-center/media-center/menu/menu.svelte.d.ts +1 -1
  63. package/dist/media-center/media-center/menu/popular-streams-panel-handler.svelte.d.ts +1 -1
  64. package/dist/media-center/media-center/menu/popular-streams-panel-handler.svelte.js +0 -3
  65. package/dist/media-center/media-center/moments/cmp.moments-circle.svelte +41 -0
  66. package/dist/media-center/media-center/moments/cmp.moments-circle.svelte.d.ts +7 -0
  67. package/dist/media-center/media-center/moments/index.d.ts +1 -0
  68. package/dist/media-center/media-center/moments/index.js +1 -0
  69. package/dist/media-center/media-center/streams-in-category/streams-in-category-panel-handler.svelte.d.ts +1 -1
  70. package/dist/media-center/media-center/streams-in-category/streams-in-category-panel-handler.svelte.js +1 -1
  71. package/dist/media-center/media-center/types.d.ts +44 -1
  72. package/dist/media-page/index.d.ts +121 -0
  73. package/dist/media-page/index.js +43 -0
  74. package/dist/posts/attachments/cmp.attachments.svelte +1 -0
  75. package/dist/posts/controls/cmp.controls.svelte +50 -13
  76. package/dist/posts/data-loaders/operations.generated.d.ts +4 -0
  77. package/dist/posts/data-loaders/operations.generated.js +6 -2
  78. package/dist/posts/model/types.d.ts +2 -0
  79. package/dist/posts/post-viewer/cmp.post-viewer.svelte +26 -18
  80. package/dist/posts/post-viewer/mapper.js +2 -0
  81. package/dist/posts/post-viewer/operations.generated.d.ts +2 -0
  82. package/dist/posts/post-viewer/operations.generated.js +3 -1
  83. package/dist/posts/post-viewer/operations.graphql +2 -0
  84. package/dist/posts/post-viewer/post-texts.svelte +3 -3
  85. package/dist/posts/posts-player/cmp.posts-player.svelte +20 -6
  86. package/dist/posts/posts-player/cmp.posts-player.svelte.d.ts +18 -2
  87. package/dist/posts/posts-player/index.d.ts +18 -3
  88. package/dist/posts/posts-player/index.js +42 -89
  89. package/dist/posts/posts-player/posts-player-proxy.svelte +19 -0
  90. package/dist/posts/posts-player/posts-player-proxy.svelte.d.ts +22 -0
  91. package/dist/posts/posts-player/posts-player-view.svelte +20 -34
  92. package/dist/posts/posts-player/posts-player-view.svelte.d.ts +2 -6
  93. package/dist/posts/posts-player/types.d.ts +19 -6
  94. package/dist/products/product-card/cmp.product-card.svelte +5 -5
  95. package/dist/products/product-card/cmp.product-card.svelte.d.ts +1 -1
  96. package/dist/short-videos/short-video-card/cmp.short-video-card.svelte +160 -19
  97. package/dist/short-videos/short-video-card/cmp.short-video-card.svelte.d.ts +2 -1
  98. package/dist/short-videos/short-video-card/localization.d.ts +5 -0
  99. package/dist/short-videos/short-video-card/localization.js +13 -0
  100. package/dist/short-videos/short-video-card/types.d.ts +4 -0
  101. package/dist/short-videos/short-videos-player/index.js +26 -33
  102. package/dist/streams/layout/element-views/cmp.stream-element.svelte +2 -2
  103. package/dist/streams/layout/element-views/cmp.text-ref-stream-element.svelte +7 -3
  104. package/dist/streams/layout/element-views/cmp.text-ref-stream-element.svelte.d.ts +2 -0
  105. package/dist/streams/layout/element-views/cmp.text-stream-element.svelte +7 -3
  106. package/dist/streams/layout/element-views/cmp.text-stream-element.svelte.d.ts +2 -0
  107. package/dist/streams/layout/element-views/price-element-view.svelte +2 -2
  108. package/dist/streams/layout/element-views/price-stream-element-localization.d.ts +1 -1
  109. package/dist/streams/layout/element-views/price-stream-element-localization.js +2 -2
  110. package/dist/streams/layout/models/mapper.js +2 -0
  111. package/dist/streams/streams-player/index.d.ts +21 -2
  112. package/dist/streams/streams-player/index.js +49 -24
  113. package/dist/streams/streams-player/stream-overview.svelte +1 -1
  114. package/dist/streams/streams-player/streams-player-buffer.svelte.d.ts +1 -3
  115. package/dist/streams/streams-player/streams-player-buffer.svelte.js +2 -2
  116. package/dist/streams/streams-player/streams-player-view.svelte +25 -21
  117. package/dist/streams/streams-player/streams-player-view.svelte.d.ts +1 -5
  118. package/dist/streams/streams-player/types.d.ts +18 -4
  119. package/dist/ui/line-clamp/cmp.line-clamp-auto.svelte +119 -0
  120. package/dist/ui/line-clamp/cmp.line-clamp-auto.svelte.d.ts +10 -0
  121. package/dist/ui/line-clamp/cmp.line-clamp.svelte +44 -72
  122. package/dist/ui/line-clamp/cmp.line-clamp.svelte.d.ts +3 -4
  123. package/dist/ui/line-clamp/index.d.ts +1 -0
  124. package/dist/ui/line-clamp/index.js +1 -0
  125. package/dist/ui/player/button/cmp.mobile-player-buttons-group.svelte +44 -0
  126. package/dist/ui/player/button/cmp.mobile-player-buttons-group.svelte.d.ts +7 -0
  127. package/dist/ui/player/button/cmp.player-button.svelte +0 -1
  128. package/dist/ui/player/button/cmp.player-buttons-group.svelte +15 -11
  129. package/dist/ui/player/button/cmp.player-buttons-group.svelte.d.ts +1 -1
  130. package/dist/ui/player/button/index.d.ts +1 -0
  131. package/dist/ui/player/button/index.js +1 -0
  132. package/dist/ui/player/button/types.d.ts +0 -2
  133. package/dist/ui/player/close-orchestrator/close-orchestrator.svelte.d.ts +18 -0
  134. package/dist/ui/player/close-orchestrator/close-orchestrator.svelte.js +58 -0
  135. package/dist/ui/player/close-orchestrator/index.d.ts +2 -0
  136. package/dist/ui/player/close-orchestrator/index.js +1 -0
  137. package/dist/ui/player/close-orchestrator/types.d.ts +9 -0
  138. package/dist/ui/player/close-orchestrator/types.js +1 -0
  139. package/dist/ui/player/colors/index.d.ts +1 -0
  140. package/dist/ui/player/colors/index.js +1 -0
  141. package/dist/ui/player/colors/player-colors.d.ts +11 -0
  142. package/dist/ui/player/colors/player-colors.js +1 -0
  143. package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.d.ts +2 -6
  144. package/dist/ui/player/providers/chunks-player-buffer/player-chunks-manager.svelte.js +11 -11
  145. package/dist/ui/player/providers/default-chunks-player-buffer.svelte.d.ts +2 -3
  146. package/dist/ui/player/providers/default-chunks-player-buffer.svelte.js +5 -5
  147. package/dist/ui/player/providers/default-feed-player-buffer.svelte.d.ts +3 -4
  148. package/dist/ui/player/providers/default-feed-player-buffer.svelte.js +16 -9
  149. package/dist/ui/player/providers/service.d.ts +2 -0
  150. package/dist/ui/player/providers/service.js +13 -0
  151. package/dist/ui/player/providers/types.d.ts +1 -0
  152. package/dist/ui/with-background/cmp.with-background.svelte +86 -0
  153. package/dist/ui/with-background/cmp.with-background.svelte.d.ts +10 -0
  154. package/dist/ui/with-background/index.d.ts +1 -0
  155. package/dist/ui/with-background/index.js +1 -0
  156. package/package.json +5 -1
  157. package/dist/content-player/fade-mixins.scss +0 -12
  158. package/dist/content-player/header.svelte +0 -15
  159. package/dist/content-player/header.svelte.d.ts +0 -28
  160. package/dist/media-center/media-center/discover/discover-panel-handler.svelte.d.ts +0 -31
  161. package/dist/media-center/media-center/discover/discover-panel-handler.svelte.js +0 -94
  162. package/dist/media-center/media-center/discover/discover-panel-localization.d.ts +0 -19
  163. package/dist/media-center/media-center/discover/discover-panel-localization.js +0 -78
  164. package/dist/media-center/media-center/discover/discover-panel.svelte +0 -142
  165. package/dist/media-center/media-center/handlers/feed-handler.svelte.d.ts +0 -6
  166. package/dist/media-center/media-center/handlers/feed-handler.svelte.js +0 -12
  167. package/dist/media-center/media-center/providers/index.d.ts +0 -2
  168. package/dist/media-center/media-center/providers/index.js +0 -2
  169. package/dist/media-center/media-center/providers/post-player-provider-generator.d.ts +0 -8
  170. package/dist/media-center/media-center/providers/post-player-provider-generator.js +0 -32
  171. package/dist/media-center/media-center/providers/streams-player-provider-generator.d.ts +0 -8
  172. package/dist/media-center/media-center/providers/streams-player-provider-generator.js +0 -36
  173. package/dist/media-center/model/types.d.ts +0 -17
  174. /package/dist/media-center/{model → media-center/feed}/types.js +0 -0
@@ -1,104 +1,57 @@
1
1
  import {} from '../../media-center/config/types';
2
2
  import { MediaCenter } from '../../media-center/media-center';
3
+ import { CloseOrchestrator } from '../../ui/player/close-orchestrator';
3
4
  import { ModalShadowHost } from '../../ui/shadow-dom';
4
5
  import { default as PostsPlayer } from './cmp.posts-player.svelte';
6
+ import { default as PostsPlayerProxy } from './posts-player-proxy.svelte';
5
7
  import { mount, unmount } from 'svelte';
6
8
  export { PostsPlayer };
7
9
  export { mapToPostPlayerModel } from '../data-loaders/mapper';
8
- /**
9
- * Opens the posts player modal.
10
- *
11
- * @param init Configuration options.
12
- *
13
- * Data provider (required)
14
- * @param init.postsProvider
15
- * Provider that supplies post items to the player.
16
- *
17
- * Media center (optional)
18
- * @param {IMediaCenterConfig} [init.mediaCenterConfig]
19
- * Optional media-center config passed to MediaCenter.
20
- *
21
- * Analytics (optional)
22
- * @param {IPostAnalyticsHandler} [init.analyticsHandler]
23
- * Custom analytics handler for posts player events.
24
- *
25
- * Social interactions (optional)
26
- * @param {IPostSocialInteractionsHandler} [init.socialInteractionsHandler]
27
- * Handler for social interactions (like, share, etc.).
28
- *
29
- * Player settings
30
- * @param {PostPlayerSettings} [init.playerSettings]
31
- * Player UI and behavior settings.
32
- * Fields of PostPlayerSettings:
33
- * - {boolean} [disableBackground]
34
- * If true, hides the player's background image.
35
- * - {boolean} [hideCloseButton]
36
- * If true, hides the close button.
37
- * - {'en'|'no'} [locale='en']
38
- * Localization for the player UI. Default is 'en'; use 'no' for Norwegian.
39
- * - {boolean} [showStreamsCloudWatermark]
40
- * If true, shows the StreamsCloud watermark.
41
- *
42
- * Events
43
- * @param {{ playerClosed?: () => void; postActivated?: (id: string) => void }} [init.on]
44
- * Optional event handlers.
45
- * @param {() => void} [init.on.playerClosed]
46
- * Called after the player is fully closed (after unmount and removal from the DOM).
47
- * @param {(id: string) => void} [init.on.postActivated]
48
- * Called when a post becomes active (receives the post's id).
49
- *
50
- * @returns {void}
51
- *
52
- * @example
53
- * ```ts
54
- * import { openPostsPlayer } from '@streamscloud/embeddable/posts-player';
55
- *
56
- * openPostsPlayer({
57
- * postsProvider: myPostsProvider,
58
- * mediaCenterConfig: myMediaCenterConfig,
59
- * analyticsHandler: myAnalyticsHandler,
60
- * socialInteractionsHandler: mySocialHandler,
61
- * playerSettings: {
62
- * // Default locale is 'en'; set 'no' to switch to Norwegian:
63
- * locale: 'no',
64
- * disableBackground: false,
65
- * hideCloseButton: false,
66
- * showStreamsCloudWatermark: true,
67
- * },
68
- * on: {
69
- * playerClosed: () => console.log('Player closed'),
70
- * postActivated: (id) => console.log('Activated post', id),
71
- * },
72
- * });
73
- * ```
74
- */
75
10
  export function openPostsPlayer(init) {
76
11
  const { postsProvider: dataProvider, mediaCenterConfig, analyticsHandler, socialInteractionsHandler, playerSettings, on } = init;
77
12
  const shadowHost = new ModalShadowHost();
78
- const mounted = mount(MediaCenter, {
79
- target: shadowHost.shadowRoot,
80
- props: {
81
- config: mediaCenterConfig || null,
82
- playerProps: {
83
- mode: 'posts',
84
- props: {
85
- dataProvider,
86
- socialInteractionsHandler,
87
- analyticsHandler,
88
- playerSettings,
89
- on: {
90
- playerClosed: async () => {
91
- await unmount(mounted);
92
- shadowHost.remove();
93
- if (on?.playerClosed) {
94
- on.playerClosed();
95
- }
96
- },
97
- postActivated: on?.postActivated
13
+ let mounted;
14
+ const makeCloseOrchestrator = () => new CloseOrchestrator({
15
+ closeFn: async () => {
16
+ await unmount(mounted);
17
+ shadowHost.remove();
18
+ if (on?.playerClosed) {
19
+ on.playerClosed();
20
+ }
21
+ },
22
+ canClose: !playerSettings?.hideCloseButton
23
+ });
24
+ if (mediaCenterConfig) {
25
+ mounted = mount(MediaCenter, {
26
+ target: shadowHost.shadowRoot,
27
+ props: {
28
+ config: mediaCenterConfig,
29
+ settings: playerSettings,
30
+ modeProps: {
31
+ mode: 'posts',
32
+ props: {
33
+ dataProvider,
34
+ onPostActivated: on?.postActivated
98
35
  }
36
+ },
37
+ closeOrchestrator: makeCloseOrchestrator()
38
+ }
39
+ });
40
+ }
41
+ else {
42
+ mounted = mount(PostsPlayerProxy, {
43
+ target: shadowHost.shadowRoot,
44
+ props: {
45
+ dataProvider,
46
+ socialInteractionsHandler,
47
+ analyticsHandler,
48
+ playerSettings,
49
+ closeOrchestrator: makeCloseOrchestrator(),
50
+ on: {
51
+ postActivated: on?.postActivated
99
52
  }
100
53
  }
101
- }
102
- });
54
+ });
55
+ }
103
56
  shadowHost.attachToBody();
104
57
  }
@@ -0,0 +1,19 @@
1
+ <script lang="ts">import {} from '../../ui/player/close-orchestrator';
2
+ import { WithBackground } from '../../ui/with-background';
3
+ import { default as PostsPlayerView } from './posts-player-view.svelte';
4
+ let { dataProvider, socialInteractionsHandler, closeOrchestrator, playerSettings, analyticsHandler, on } = $props();
5
+ let backgroundImageUrl = $state(null);
6
+ const handleBackgroundImagedLoaded = (url) => {
7
+ backgroundImageUrl = url;
8
+ };
9
+ </script>
10
+
11
+ <WithBackground backgroundDisabled={playerSettings?.disableBackground === true} backgroundImageUrl={backgroundImageUrl}>
12
+ <PostsPlayerView
13
+ dataProvider={{ type: 'provider', provider: dataProvider }}
14
+ socialInteractionsHandler={socialInteractionsHandler}
15
+ playerSettings={playerSettings}
16
+ analyticsHandler={analyticsHandler}
17
+ closeOrchestrator={closeOrchestrator}
18
+ on={{ postActivated: on?.postActivated, backgroundImageLoaded: playerSettings?.disableBackground === true ? undefined : handleBackgroundImagedLoaded }} />
19
+ </WithBackground>
@@ -0,0 +1,22 @@
1
+ import type { Locale } from '../../core/locale';
2
+ import type { IPostSocialInteractionsHandler } from '..';
3
+ import { type ICloseOrchestrator } from '../../ui/player/close-orchestrator';
4
+ import type { IPlayerDataProvider } from '../../ui/player/providers';
5
+ import type { IPostAnalyticsHandler, PostPlayerModel } from './types';
6
+ type Props = {
7
+ dataProvider: IPlayerDataProvider<PostPlayerModel>;
8
+ socialInteractionsHandler?: IPostSocialInteractionsHandler;
9
+ analyticsHandler?: IPostAnalyticsHandler;
10
+ closeOrchestrator: ICloseOrchestrator;
11
+ playerSettings?: {
12
+ locale?: Locale;
13
+ showStreamsCloudWatermark?: boolean;
14
+ disableBackground?: boolean;
15
+ };
16
+ on?: {
17
+ postActivated?: (id: string) => void;
18
+ };
19
+ };
20
+ declare const PostsPlayerProxy: import("svelte").Component<Props, {}, "">;
21
+ type PostsPlayerProxy = ReturnType<typeof PostsPlayerProxy>;
22
+ export default PostsPlayerProxy;
@@ -11,11 +11,11 @@ import { PostType } from '../..';
11
11
  import { ContentPlayer, ContentPlayerConfig } from '../../content-player';
12
12
  import { ContentPlayerSettings } from '../../content-player/content-player-settings';
13
13
  import { preloadImage } from '../../core/image-preloader';
14
- import { Utils } from '../../core/utils';
15
14
  import { getPostCoverImage } from '../model';
16
- import { DefaultChunksPlayerBuffer, DefaultFeedPlayerBuffer } from '../../ui/player/providers';
15
+ import {} from '../../ui/player/providers';
16
+ import { initBufferFromProvider } from '../../ui/player/providers/service';
17
17
  import { untrack } from 'svelte';
18
- let { dataProvider, socialInteractionsHandler, playerSettings, analyticsHandler, on, mediaCenterData } = $props();
18
+ let { dataProvider, socialInteractionsHandler, playerSettings, analyticsHandler, closeOrchestrator, on } = $props();
19
19
  $effect(() => {
20
20
  void dataProvider;
21
21
  untrack(() => {
@@ -23,36 +23,21 @@ $effect(() => {
23
23
  initBuffer(dataProvider);
24
24
  });
25
25
  });
26
- $effect(() => contentPlayerConfig.updateMediaCenterData(mediaCenterData));
27
26
  const initBuffer = (dataProvider) => __awaiter(void 0, void 0, void 0, function* () {
28
- switch (dataProvider.kind) {
29
- case 'feed':
30
- new DefaultFeedPlayerBuffer(dataProvider, {
31
- preloaded: (instance) => __awaiter(void 0, void 0, void 0, function* () {
32
- if (instance.loaded.length) {
33
- const coverUrl = getPostCoverImage(instance.loaded[0]);
34
- yield preloadImage(coverUrl);
35
- contentPlayerConfig.setBackgroundImageUrl(coverUrl);
36
- }
37
- contentPlayerConfig.playerBuffer = instance;
38
- })
39
- });
40
- break;
41
- case 'chunks':
42
- new DefaultChunksPlayerBuffer(dataProvider, {
43
- preloaded: (instance) => __awaiter(void 0, void 0, void 0, function* () {
44
- if (instance.loaded.length) {
45
- const coverUrl = getPostCoverImage(instance.loaded[0]);
46
- yield preloadImage(coverUrl);
47
- contentPlayerConfig.setBackgroundImageUrl(coverUrl);
48
- }
49
- contentPlayerConfig.playerBuffer = instance;
50
- })
51
- });
52
- break;
53
- default:
54
- Utils.assertUnreachable(dataProvider);
27
+ let newBuffer;
28
+ if (dataProvider.type === 'buffer') {
29
+ newBuffer = dataProvider.buffer;
55
30
  }
31
+ else {
32
+ newBuffer = initBufferFromProvider(dataProvider.provider);
33
+ }
34
+ yield newBuffer.ensureWarmedUp();
35
+ if (newBuffer.loaded.length && (on === null || on === void 0 ? void 0 : on.backgroundImageLoaded)) {
36
+ const coverUrl = getPostCoverImage(newBuffer.loaded[0]);
37
+ yield preloadImage(coverUrl);
38
+ on.backgroundImageLoaded(coverUrl);
39
+ }
40
+ contentPlayerConfig.playerBuffer = newBuffer;
56
41
  });
57
42
  const getLoadedItemById = (id) => {
58
43
  if (!contentPlayerConfig.playerBuffer) {
@@ -66,10 +51,9 @@ const contentPlayerConfig = new ContentPlayerConfig({
66
51
  postModelFromCurrentItem: (item) => item
67
52
  },
68
53
  socialInteractionsHandler,
69
- mediaCenterData,
70
54
  settings: new ContentPlayerSettings(playerSettings),
55
+ closeOrchestrator,
71
56
  callbacks: {
72
- close: on === null || on === void 0 ? void 0 : on.playerClosed,
73
57
  productClick: (id, postId) => {
74
58
  var _a;
75
59
  if (((_a = getLoadedItemById(postId)) === null || _a === void 0 ? void 0 : _a.postType) === PostType.ShortVideo) {
@@ -96,7 +80,9 @@ const contentPlayerConfig = new ContentPlayerConfig({
96
80
  if (!post) {
97
81
  return;
98
82
  }
99
- contentPlayerConfig.setBackgroundImageUrl(getPostCoverImage(post));
83
+ if (on === null || on === void 0 ? void 0 : on.backgroundImageLoaded) {
84
+ on.backgroundImageLoaded(getPostCoverImage(post));
85
+ }
100
86
  if (post.analyticsOrganizationId) {
101
87
  analyticsHandler === null || analyticsHandler === void 0 ? void 0 : analyticsHandler.setOrganizationId(post.analyticsOrganizationId);
102
88
  }
@@ -1,8 +1,4 @@
1
- import type { MediaCenterData } from '../../media-center/model/types';
2
- import type { PostPlayerProps } from './types';
3
- type $$ComponentProps = PostPlayerProps & {
4
- mediaCenterData?: MediaCenterData;
5
- };
6
- declare const PostsPlayerView: import("svelte").Component<$$ComponentProps, {}, "">;
1
+ import type { PostsPlayerProps } from './types';
2
+ declare const PostsPlayerView: import("svelte").Component<PostsPlayerProps, {}, "">;
7
3
  type PostsPlayerView = ReturnType<typeof PostsPlayerView>;
8
4
  export default PostsPlayerView;
@@ -1,7 +1,9 @@
1
- import type { IContentPlayerSettingsInitializer } from '../../content-player/content-player-settings';
1
+ import type { Locale } from '../../core/locale';
2
2
  import type { IPostModel } from '..';
3
3
  import type { IPostSocialInteractionsHandler } from '../social-interactions';
4
- import type { IPlayerDataProvider } from '../../ui/player/providers';
4
+ import type { ICloseOrchestrator } from '../../ui/player/close-orchestrator';
5
+ import type { PlayerColors } from '../../ui/player/colors';
6
+ import type { IPlayerBuffer, IPlayerDataProvider } from '../../ui/player/providers';
5
7
  export interface IPostAnalyticsHandler {
6
8
  setOrganizationId: (organizationId: string) => void;
7
9
  trackPostOpened: (postId: string, ownerId: string) => void;
@@ -14,14 +16,25 @@ export interface IPostAnalyticsHandler {
14
16
  export type PostPlayerModel = IPostModel & {
15
17
  analyticsOrganizationId: string | null;
16
18
  };
17
- export type PostPlayerProps = {
18
- dataProvider: IPlayerDataProvider<PostPlayerModel>;
19
+ export type PostsPlayerProps = {
20
+ dataProvider: {
21
+ type: 'buffer';
22
+ buffer: IPlayerBuffer<PostPlayerModel>;
23
+ } | {
24
+ type: 'provider';
25
+ provider: IPlayerDataProvider<PostPlayerModel>;
26
+ };
19
27
  socialInteractionsHandler?: IPostSocialInteractionsHandler;
20
28
  analyticsHandler?: IPostAnalyticsHandler;
21
29
  playerSettings?: PostPlayerSettings;
30
+ closeOrchestrator: ICloseOrchestrator;
22
31
  on?: {
23
- playerClosed?: () => void;
24
32
  postActivated?: (id: string) => void;
33
+ backgroundImageLoaded?: (imageUrl: string | null) => void;
25
34
  };
26
35
  };
27
- export type PostPlayerSettings = IContentPlayerSettingsInitializer;
36
+ export type PostPlayerSettings = {
37
+ locale?: Locale;
38
+ showStreamsCloudWatermark?: boolean;
39
+ playerColors?: PlayerColors;
40
+ };
@@ -4,7 +4,7 @@ import { Image } from '../../ui/image';
4
4
  import { LineClamp } from '../../ui/line-clamp';
5
5
  import { ProportionalContainer } from '../../ui/proportional-container';
6
6
  import { ProductCardLocalization } from './product-card-localization';
7
- let { product, colors, includeBeforeNowPrefix, trackingParams, inert = false, locale = 'en', on } = $props();
7
+ let { product, colors, includeBeforeNowPrefix, trackingParams, inert = false, locale, on } = $props();
8
8
  const localization = $derived(new ProductCardLocalization(locale));
9
9
  const shortDescriptionPresented = $derived(product.shortDescription && product.shortDescription.length > 0);
10
10
  const trackImpression = (node) => {
@@ -58,13 +58,13 @@ const styles = $derived.by(() => {
58
58
  </ProportionalContainer>
59
59
 
60
60
  <div class="product-card__info">
61
- <LineClamp maxLines={1}>
61
+ <LineClamp maxLines={1} locale={locale}>
62
62
  <div class="product-card__brand">{product.brandName}</div>
63
63
  </LineClamp>
64
- <LineClamp value={product.shortDescription} maxLines={shortDescriptionPresented ? 1 : 2}>
64
+ <LineClamp maxLines={shortDescriptionPresented ? 1 : 2} locale={locale}>
65
65
  <div class="product-card__title" class:two-lines={!shortDescriptionPresented}>{product.title}</div>
66
66
  </LineClamp>
67
- <LineClamp value={product.shortDescription} maxLines={2}>
67
+ <LineClamp maxLines={2} locale={locale}>
68
68
  <div class="product-card__description" class:two-lines={shortDescriptionPresented}>{product.shortDescription}</div>
69
69
  </LineClamp>
70
70
  <div class="product-price">
@@ -110,7 +110,7 @@ const styles = $derived.by(() => {
110
110
  --product-price-color: var(--_product-card--price-color);
111
111
  --product-price--sale--color: var(--_product-card--sale-price-color);
112
112
  --image--border-radius: 0.25rem;
113
- --image--object-fit: contain;
113
+ --image--object-fit: cover;
114
114
  --image--width: auto;
115
115
  --image--height: auto;
116
116
  width: 100%;
@@ -8,7 +8,7 @@ type Props = {
8
8
  price?: string | null;
9
9
  salePrice?: string | null;
10
10
  };
11
- locale?: Locale;
11
+ locale: Locale;
12
12
  includeBeforeNowPrefix?: boolean;
13
13
  inert?: boolean;
14
14
  trackingParams: TrackingParams;
@@ -1,27 +1,112 @@
1
- <script lang="ts">import { Icon } from '../../ui/icon';
1
+ <script lang="ts">import { toPriceRepresentation } from '../../products/price-helper';
2
+ import { Icon } from '../../ui/icon';
2
3
  import { ImageRounded } from '../../ui/image';
3
4
  import { LineClamp } from '../../ui/line-clamp';
4
5
  import { ProportionalContainer } from '../../ui/proportional-container';
6
+ import { TimeAgo } from '../../ui/time-ago';
7
+ import { ShortVideoCardLocalization } from './localization';
5
8
  import IconPhone from '@fluentui/svg-icons/icons/phone_20_regular.svg?raw';
6
- let { shortVideo, aspectRatio = 9 / 16, on } = $props();
9
+ import IconShoppingBag from '@fluentui/svg-icons/icons/shopping_bag_20_regular.svg?raw';
10
+ const ADJUST_TEXT_SIZE = false;
11
+ let { shortVideo, locale, on } = $props();
12
+ const localization = new ShortVideoCardLocalization(locale);
13
+ const adjustTextSize = (node) => {
14
+ if (!ADJUST_TEXT_SIZE) {
15
+ return;
16
+ }
17
+ const isOverflown = ({ clientHeight, scrollHeight }) => scrollHeight > clientHeight;
18
+ const resizeObserver = new ResizeObserver(() => {
19
+ node.style.fontSize = '';
20
+ const { fontSize } = window.getComputedStyle(node);
21
+ const originalFontSize = parseFloat(fontSize);
22
+ const maxSize = originalFontSize * 2;
23
+ let i = originalFontSize;
24
+ let overflow = false;
25
+ while (!overflow && i < maxSize) {
26
+ node.style.fontSize = `${i}px`;
27
+ overflow = isOverflown(node);
28
+ if (!overflow) {
29
+ i += 1;
30
+ }
31
+ }
32
+ node.style.fontSize = `${i - 1}px`;
33
+ });
34
+ resizeObserver.observe(node);
35
+ return {
36
+ destroy() {
37
+ resizeObserver.disconnect();
38
+ }
39
+ };
40
+ };
7
41
  </script>
8
42
 
9
43
  <div class="short-video-card">
10
44
  <div class="short-video-card__media">
11
- <ProportionalContainer ratio={aspectRatio}>
45
+ <ProportionalContainer ratio={2 / 3}>
12
46
  <ImageRounded src={shortVideo.cover} alt="" noBorders={true} />
13
47
  </ProportionalContainer>
14
48
 
15
49
  <div class="short-video-card__media-icons">
16
- <Icon src={IconPhone}></Icon>
50
+ <Icon src={shortVideo.products.length ? IconShoppingBag : IconPhone}></Icon>
17
51
  </div>
18
52
  </div>
19
53
 
20
- {#if shortVideo.text}
21
- <div class="short-video-card__text">
22
- <LineClamp value={shortVideo.text} maxLines={2} enableShowMore={false} />
54
+ <div class="short-video-card__info">
55
+ <div class="short-video-card__meta">
56
+ <span><TimeAgo date={shortVideo.displayDate} locale={locale} /></span>
57
+ {#if shortVideo.viewsCount}
58
+ <span>&middot;</span>
59
+ <span>{localization.viewsLabel(shortVideo.viewsCount)}</span>
60
+ {/if}
23
61
  </div>
24
- {/if}
62
+
63
+ <div class="short-video-card__text" use:adjustTextSize>
64
+ {#if shortVideo.text}
65
+ {shortVideo.text}
66
+ {/if}
67
+ </div>
68
+
69
+ <div class="short-video-card__products">
70
+ {#snippet productView(product: IPostProductCardModel)}
71
+ <div class="product-card">
72
+ <ProportionalContainer ratio={4 / 5}>
73
+ <ImageRounded src={product.image} alt={product.title} noBorders={true} />
74
+ </ProportionalContainer>
75
+
76
+ <div class="product-card__info">
77
+ <div class="product-card__title">
78
+ <LineClamp maxLines={1} enableShowMore={false} locale={locale}>{product.title}</LineClamp>
79
+ </div>
80
+ <div class="product-card__price">
81
+ <LineClamp maxLines={1} locale={locale}>
82
+ <span>
83
+ {toPriceRepresentation({
84
+ amount: product.salePrice || product.price,
85
+ currency: product.currency,
86
+ options: { currencyMode: 'none' }
87
+ })}
88
+ </span>
89
+ {#if product.salePrice}
90
+ &nbsp;
91
+ <span
92
+ >{toPriceRepresentation({
93
+ amount: product.price,
94
+ currency: product.currency,
95
+ options: { currencyMode: 'none' }
96
+ })}
97
+ </span>
98
+ {/if}
99
+ </LineClamp>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ {/snippet}
104
+
105
+ {#each shortVideo.products as product (product.id)}
106
+ {@render productView(product)}
107
+ {/each}
108
+ </div>
109
+ </div>
25
110
 
26
111
  {#if on?.click}
27
112
  <button type="button" onclick={on.click} class="short-video-card__link" aria-label="none">&nbsp;</button>
@@ -44,13 +129,12 @@ let { shortVideo, aspectRatio = 9 / 16, on } = $props();
44
129
  overflow: hidden;
45
130
  container-type: inline-size;
46
131
  width: 100%;
47
- border-radius: 0.375rem;
48
132
  }
49
133
  .short-video-card__media {
50
134
  display: flex;
51
135
  align-items: center;
52
136
  justify-content: center;
53
- --image--rounded--outer--border-radius: 1%;
137
+ --image--rounded--outer--border-radius: 0.5rem;
54
138
  }
55
139
  .short-video-card__media-icons {
56
140
  position: absolute;
@@ -63,17 +147,45 @@ let { shortVideo, aspectRatio = 9 / 16, on } = $props();
63
147
  --icon--color: #ffffff;
64
148
  --icon--filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.2));
65
149
  }
150
+ .short-video-card__info {
151
+ margin-top: clamp(0.4375rem, 3.6cqi, 0.625rem);
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: clamp(0.4375rem, 3.6cqi, 0.625rem);
155
+ }
156
+ .short-video-card__meta {
157
+ font-size: clamp(0.625rem, 4.3cqi, 0.75rem);
158
+ font-weight: 500;
159
+ color: #999999;
160
+ display: flex;
161
+ align-items: center;
162
+ gap: 0.25rem;
163
+ }
66
164
  .short-video-card__text {
67
- position: absolute;
68
- bottom: 0;
69
- left: 0;
70
- right: 0;
71
- background: linear-gradient(0deg, rgba(0, 0, 0, 0.9) 30%, rgba(0, 0, 0, 0.01) 100%);
72
165
  color: #ffffff;
73
- font-size: 0.75rem;
74
- font-weight: 400;
75
- padding: 0.75rem 0.75rem;
76
- padding-top: 2.5rem;
166
+ --min-font: 0.75rem;
167
+ --max-font: 0.9375rem;
168
+ --line-height: 1.2;
169
+ font-size: clamp(var(--min-font), 5.4cqi, var(--max-font));
170
+ line-height: var(--line-height);
171
+ font-weight: 500;
172
+ height: clamp(var(--min-font) * var(--line-height) * 2 - 1px, 5.4cqi * var(--line-height) * 2 - 1px, var(--max-font) * var(--line-height) * 2 - 1px);
173
+ white-space: pre-line;
174
+ word-break: break-word;
175
+ display: -webkit-box;
176
+ overflow: hidden;
177
+ -webkit-box-orient: vertical;
178
+ line-clamp: 2;
179
+ -webkit-line-clamp: 2;
180
+ text-overflow: ellipsis;
181
+ }
182
+ .short-video-card__products {
183
+ display: grid;
184
+ grid-template-columns: repeat(3, minmax(0, 1fr));
185
+ gap: clamp(0.625rem, 5cqi, 0.875rem);
186
+ }
187
+ .short-video-card__products > :nth-child(n+4) {
188
+ display: none;
77
189
  }
78
190
  .short-video-card__link {
79
191
  position: absolute;
@@ -81,4 +193,33 @@ let { shortVideo, aspectRatio = 9 / 16, on } = $props();
81
193
  left: 0;
82
194
  width: 100%;
83
195
  height: 100%;
196
+ }
197
+
198
+ .product-card {
199
+ --image--rounded--outer--border-radius: 0.375rem;
200
+ container-type: inline-size;
201
+ }
202
+ .product-card__info {
203
+ display: flex;
204
+ flex-direction: column;
205
+ color: #ffffff;
206
+ font-size: clamp(0.5rem, 2.9cqi, 0.5rem);
207
+ line-height: clamp(0.75rem, 4.3cqi, 0.75rem);
208
+ font-weight: 500;
209
+ /* Set 'container-type: inline-size;' to reference container*/
210
+ }
211
+ @container (width < 60px) {
212
+ .product-card__info {
213
+ display: none;
214
+ }
215
+ }
216
+ .product-card__title {
217
+ font-weight: 500;
218
+ }
219
+ .product-card__price {
220
+ font-weight: 600;
221
+ }
222
+ .product-card__price span:nth-child(2) {
223
+ color: #999999;
224
+ text-decoration: line-through;
84
225
  }</style>
@@ -1,7 +1,8 @@
1
+ import type { Locale } from '../../core/locale';
1
2
  import type { ShortVideoCardModel } from './types';
2
3
  type Props = {
3
4
  shortVideo: ShortVideoCardModel;
4
- aspectRatio?: number;
5
+ locale: Locale;
5
6
  on?: {
6
7
  click?: () => void;
7
8
  };
@@ -0,0 +1,5 @@
1
+ import { type Locale } from '../../core/locale';
2
+ export declare class ShortVideoCardLocalization {
3
+ viewsLabel: (count: number) => string;
4
+ constructor(locale: Locale);
5
+ }
@@ -0,0 +1,13 @@
1
+ import {} from '../../core/locale';
2
+ export class ShortVideoCardLocalization {
3
+ viewsLabel;
4
+ constructor(locale) {
5
+ this.viewsLabel = loc.viewsLabel[locale];
6
+ }
7
+ }
8
+ const loc = {
9
+ viewsLabel: {
10
+ en: (count) => `${count} view${count !== 1 ? 's' : ''}`,
11
+ no: (count) => `${count} visning${count !== 1 ? 'er' : ''}`
12
+ }
13
+ };
@@ -1,5 +1,9 @@
1
+ import type { IPostProductCardModel } from '../../posts/model';
1
2
  export type ShortVideoCardModel = {
2
3
  id: string;
3
4
  text: string | null;
4
5
  cover: string;
6
+ displayDate: string;
7
+ viewsCount: number;
8
+ products: IPostProductCardModel[];
5
9
  };