@streamscloud/embeddable 7.0.0 → 7.0.2-1759149696160

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 (133) hide show
  1. package/dist/ads/ad-card/cmp.ad-card.svelte +13 -12
  2. package/dist/ads/ad-card/cmp.ad-card.svelte.d.ts +2 -2
  3. package/dist/content-player/cmp.content-player.svelte +224 -0
  4. package/dist/content-player/cmp.content-player.svelte.d.ts +33 -0
  5. package/dist/content-player/content-player-config.svelte.d.ts +49 -0
  6. package/dist/content-player/content-player-config.svelte.js +43 -0
  7. package/dist/content-player/controls-and-attachments.svelte +275 -0
  8. package/dist/content-player/controls-and-attachments.svelte.d.ts +28 -0
  9. package/dist/content-player/fade-mixins.scss +12 -0
  10. package/dist/content-player/index.d.ts +2 -0
  11. package/dist/content-player/index.js +2 -0
  12. package/dist/content-player/overview-panel.svelte +85 -0
  13. package/dist/content-player/overview-panel.svelte.d.ts +10 -0
  14. package/dist/{streams/stream-player → content-player}/ui-manager.svelte.d.ts +10 -9
  15. package/dist/content-player/ui-manager.svelte.js +68 -0
  16. package/dist/index.d.ts +0 -1
  17. package/dist/index.js +0 -1
  18. package/dist/media-center/config/internal-media-center-config.js +2 -1
  19. package/dist/media-center/config/types.d.ts +1 -1
  20. package/dist/media-center/media-center/cmp.media-center.svelte +13 -9
  21. package/dist/media-center/media-center/overview.svelte +3 -2
  22. package/dist/media-center/media-center/short-video-resources-generator.d.ts +1 -1
  23. package/dist/media-center/model/types.d.ts +12 -0
  24. package/dist/posts/attachments/cmp.attachments.svelte +50 -0
  25. package/dist/{short-videos/short-video-viewer → posts/attachments}/cmp.attachments.svelte.d.ts +3 -3
  26. package/dist/posts/attachments/index.d.ts +1 -0
  27. package/dist/posts/attachments/index.js +1 -0
  28. package/dist/{short-videos/short-video-viewer/cmp.short-video-controls.svelte → posts/controls/cmp.controls.svelte} +21 -26
  29. package/dist/posts/controls/cmp.controls.svelte.d.ts +11 -0
  30. package/dist/posts/controls/index.d.ts +1 -0
  31. package/dist/posts/controls/index.js +1 -0
  32. package/dist/posts/index.d.ts +4 -0
  33. package/dist/posts/index.js +2 -0
  34. package/dist/posts/model/types.d.ts +13 -0
  35. package/dist/posts/model/types.js +1 -0
  36. package/dist/{short-videos/short-video-viewer/cmp.attachments-horizontal.svelte → posts/post-viewer/attachments-horizontal.svelte} +2 -3
  37. package/dist/posts/post-viewer/attachments-horizontal.svelte.d.ts +13 -0
  38. package/dist/posts/post-viewer/cmp.post-viewer.svelte +120 -0
  39. package/dist/{short-videos/short-video-viewer/cmp.short-video-viewer.svelte.d.ts → posts/post-viewer/cmp.post-viewer.svelte.d.ts} +3 -2
  40. package/dist/posts/post-viewer/heading.svelte +76 -0
  41. package/dist/posts/post-viewer/heading.svelte.d.ts +9 -0
  42. package/dist/posts/post-viewer/index.d.ts +4 -0
  43. package/dist/posts/post-viewer/index.js +3 -0
  44. package/dist/posts/post-viewer/mapper.d.ts +3 -0
  45. package/dist/{short-videos/short-video-viewer → posts/post-viewer}/mapper.js +33 -17
  46. package/dist/{short-videos/short-video-viewer → posts/post-viewer}/operations.generated.d.ts +2 -2
  47. package/dist/{short-videos/short-video-viewer → posts/post-viewer}/operations.generated.js +2 -2
  48. package/dist/{short-videos/short-video-viewer → posts/post-viewer}/operations.graphql +1 -1
  49. package/dist/posts/post-viewer/post-media.svelte +20 -0
  50. package/dist/posts/post-viewer/post-media.svelte.d.ts +12 -0
  51. package/dist/{short-videos/short-video-viewer/short-video-viewer-localization.d.ts → posts/post-viewer/post-viewer-localization.d.ts} +2 -3
  52. package/dist/{short-videos/short-video-viewer/short-video-viewer-localization.js → posts/post-viewer/post-viewer-localization.js} +3 -5
  53. package/dist/{short-videos/short-video-viewer → posts/post-viewer}/types.d.ts +24 -25
  54. package/dist/{short-videos/short-video-viewer → posts/post-viewer}/ui-manager.svelte.d.ts +5 -3
  55. package/dist/{short-videos/short-video-viewer → posts/post-viewer}/ui-manager.svelte.js +11 -4
  56. package/dist/posts/post-viewer/utils.d.ts +2 -0
  57. package/dist/posts/post-viewer/utils.js +13 -0
  58. package/dist/posts/social-interactions/index.d.ts +1 -0
  59. package/dist/posts/social-interactions/index.js +1 -0
  60. package/dist/posts/social-interactions/types.d.ts +9 -0
  61. package/dist/posts/social-interactions/types.js +1 -0
  62. package/dist/products/product-card/cmp.product-card.svelte +27 -8
  63. package/dist/products/product-card/cmp.product-card.svelte.d.ts +2 -1
  64. package/dist/short-videos/short-videos-player/cmp.short-videos-player.svelte +11 -17
  65. package/dist/short-videos/short-videos-player/cmp.short-videos-player.svelte.d.ts +1 -5
  66. package/dist/short-videos/short-videos-player/index.d.ts +20 -5
  67. package/dist/short-videos/short-videos-player/internal-short-video-analytics-handler.d.ts +1 -1
  68. package/dist/short-videos/short-videos-player/internal-short-video-analytics-handler.js +1 -1
  69. package/dist/short-videos/short-videos-player/internal-short-video-player-provider.d.ts +1 -1
  70. package/dist/short-videos/short-videos-player/mapper.js +2 -2
  71. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte +50 -216
  72. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte.d.ts +2 -9
  73. package/dist/short-videos/short-videos-player/types.d.ts +6 -7
  74. package/dist/streams/layout/element-views/cmp.short-video-stream-element.svelte +3 -3
  75. package/dist/streams/layout/models/index.d.ts +1 -1
  76. package/dist/streams/layout/models/index.js +1 -1
  77. package/dist/streams/layout/models/mapper.d.ts +2 -2
  78. package/dist/streams/layout/models/mapper.js +6 -6
  79. package/dist/streams/stream-player/index.d.ts +25 -4
  80. package/dist/streams/stream-player/internal-stream-analytics-handler.d.ts +2 -0
  81. package/dist/streams/stream-player/internal-stream-analytics-handler.js +2 -0
  82. package/dist/streams/stream-player/stream-overview.svelte +47 -122
  83. package/dist/streams/stream-player/stream-overview.svelte.d.ts +1 -4
  84. package/dist/streams/stream-player/stream-player-buffer.svelte.d.ts +1 -1
  85. package/dist/streams/stream-player/stream-player-localization.d.ts +1 -5
  86. package/dist/streams/stream-player/stream-player-localization.js +2 -10
  87. package/dist/streams/stream-player/stream-player-view.svelte +229 -0
  88. package/dist/streams/stream-player/stream-player-view.svelte.d.ts +8 -0
  89. package/dist/streams/stream-player/types.d.ts +4 -4
  90. package/dist/ui/{player → player-slider}/cmp.player-slider.svelte.d.ts +2 -10
  91. package/dist/ui/{player → player-slider}/types.d.ts +9 -0
  92. package/dist/ui/player-slider/types.js +1 -0
  93. package/package.json +1 -1
  94. package/dist/short-videos/short-video-viewer/cmp.attachments-horizontal.svelte.d.ts +0 -13
  95. package/dist/short-videos/short-video-viewer/cmp.attachments.svelte +0 -52
  96. package/dist/short-videos/short-video-viewer/cmp.short-video-controls.svelte.d.ts +0 -19
  97. package/dist/short-videos/short-video-viewer/cmp.short-video-heading.svelte +0 -89
  98. package/dist/short-videos/short-video-viewer/cmp.short-video-heading.svelte.d.ts +0 -9
  99. package/dist/short-videos/short-video-viewer/cmp.short-video-product-card.svelte +0 -26
  100. package/dist/short-videos/short-video-viewer/cmp.short-video-product-card.svelte.d.ts +0 -16
  101. package/dist/short-videos/short-video-viewer/cmp.short-video-viewer.svelte +0 -146
  102. package/dist/short-videos/short-video-viewer/index.d.ts +0 -5
  103. package/dist/short-videos/short-video-viewer/index.js +0 -4
  104. package/dist/short-videos/short-video-viewer/mapper.d.ts +0 -3
  105. package/dist/short-videos/short-video-viewer/short-video-attachments-localization.d.ts +0 -5
  106. package/dist/short-videos/short-video-viewer/short-video-attachments-localization.js +0 -7
  107. package/dist/short-videos/short-videos-player/controls.svelte +0 -261
  108. package/dist/short-videos/short-videos-player/controls.svelte.d.ts +0 -22
  109. package/dist/short-videos/short-videos-player/fade-mixins.scss +0 -12
  110. package/dist/short-videos/short-videos-player/short-videos-player-localization.d.ts +0 -7
  111. package/dist/short-videos/short-videos-player/short-videos-player-localization.js +0 -11
  112. package/dist/short-videos/short-videos-player/ui-manager.svelte.d.ts +0 -24
  113. package/dist/short-videos/short-videos-player/ui-manager.svelte.js +0 -47
  114. package/dist/streams/cmp.stream-product-card.svelte +0 -25
  115. package/dist/streams/cmp.stream-product-card.svelte.d.ts +0 -16
  116. package/dist/streams/stream-player/controls.svelte +0 -301
  117. package/dist/streams/stream-player/controls.svelte.d.ts +0 -20
  118. package/dist/streams/stream-player/fade-mixins.scss +0 -12
  119. package/dist/streams/stream-player/stream-player.svelte +0 -393
  120. package/dist/streams/stream-player/stream-player.svelte.d.ts +0 -16
  121. package/dist/streams/stream-player/ui-manager.svelte.js +0 -63
  122. /package/dist/{streams/stream-player → content-player}/button-mixins.scss +0 -0
  123. /package/dist/{ui/player → media-center/model}/types.js +0 -0
  124. /package/dist/{short-videos/short-video-viewer → posts/post-viewer}/types.js +0 -0
  125. /package/dist/ui/{player → player-slider}/cmp.player-slider.svelte +0 -0
  126. /package/dist/ui/{player → player-slider}/index.d.ts +0 -0
  127. /package/dist/ui/{player → player-slider}/index.js +0 -0
  128. /package/dist/ui/{player → player-slider}/player-buffer.svelte.d.ts +0 -0
  129. /package/dist/ui/{player → player-slider}/player-buffer.svelte.js +0 -0
  130. /package/dist/ui/{player → player-slider}/prevent-slider-scroll.d.ts +0 -0
  131. /package/dist/ui/{player → player-slider}/prevent-slider-scroll.js +0 -0
  132. /package/dist/ui/{player → player-slider}/wheel-gestures-adapter.d.ts +0 -0
  133. /package/dist/ui/{player → player-slider}/wheel-gestures-adapter.js +0 -0
@@ -0,0 +1,120 @@
1
+ <script lang="ts">import { PostControls } from '..';
2
+ import { LineClamp } from '../../ui/line-clamp';
3
+ import { default as AttachmentsHorizontal } from './attachments-horizontal.svelte';
4
+ import { default as Heading } from './heading.svelte';
5
+ import { default as PostMedia } from './post-media.svelte';
6
+ import { PostViewerLocalization } from './post-viewer-localization';
7
+ import { PostViewerUiManager } from './ui-manager.svelte';
8
+ let { model, socialInteractionsHandler, showAttachments = true, showControls = true, autoplay = 'on-appearance', locale = 'en', on } = $props();
9
+ const localization = $derived(new PostViewerLocalization(locale));
10
+ const uiManager = new PostViewerUiManager();
11
+ $effect(() => {
12
+ uiManager.setCanShowAttachments(showAttachments);
13
+ uiManager.setCanShowControls(showControls);
14
+ });
15
+ const trackControlsPanelSize = (node) => {
16
+ const resizeObserver = new ResizeObserver(([entry]) => {
17
+ const width = entry.contentRect.width;
18
+ uiManager.setControlsPanelWidth(width);
19
+ });
20
+ resizeObserver.observe(node);
21
+ return {
22
+ destroy() {
23
+ resizeObserver.unobserve(node);
24
+ }
25
+ };
26
+ };
27
+ </script>
28
+
29
+ <div class="post-viewer" style={uiManager.globalCssVariables}>
30
+ <PostMedia id={model.id} media={model.media} autoplay={autoplay} on={{ progress: on?.progress }} />
31
+ <div class="post-viewer__information">
32
+ {#if model.heading}
33
+ <Heading model={model.heading} localization={localization} />
34
+ {/if}
35
+ <div class="post-viewer__text">
36
+ {#if model.text}
37
+ <LineClamp value={model.text} maxLines={2} enableShowMore={true} />
38
+ {/if}
39
+ </div>
40
+ {#if uiManager.showAttachments && (model.ads.length || model.products.length)}
41
+ <div class="post-viewer__attachments">
42
+ <AttachmentsHorizontal
43
+ model={model}
44
+ on={{
45
+ productClick: on?.productClick,
46
+ productImpression: on?.productImpression,
47
+ adClick: on?.adClick,
48
+ adImpression: on?.adImpression
49
+ }} />
50
+ </div>
51
+ {/if}
52
+ </div>
53
+
54
+ <div class="post-viewer__controls-panel" use:trackControlsPanelSize>
55
+ {#if uiManager.showControls}
56
+ <PostControls model={model} socialInteractionsHandler={socialInteractionsHandler} on={{ attachmentsClicked: uiManager.toggleEnableAttachments }} />
57
+ {/if}
58
+ </div>
59
+ </div>
60
+
61
+ <style>@keyframes fadeIn {
62
+ 0% {
63
+ opacity: 1;
64
+ }
65
+ 50% {
66
+ opacity: 0.4;
67
+ }
68
+ 100% {
69
+ opacity: 1;
70
+ }
71
+ }
72
+ .post-viewer {
73
+ --video--media-fit: cover;
74
+ width: 100%;
75
+ min-width: 100%;
76
+ max-width: 100%;
77
+ height: 100%;
78
+ min-height: 100%;
79
+ max-height: 100%;
80
+ border-radius: 0.375rem;
81
+ overflow: hidden;
82
+ position: relative;
83
+ /* Set 'container-type: inline-size;' to reference container*/
84
+ }
85
+ @container (width < 576px) {
86
+ .post-viewer {
87
+ border-radius: 0;
88
+ position: relative;
89
+ }
90
+ }
91
+ .post-viewer__controls-panel {
92
+ position: absolute;
93
+ left: auto;
94
+ right: 0.625rem;
95
+ top: 5rem;
96
+ bottom: 6.25rem;
97
+ gap: 2.5rem;
98
+ display: flex;
99
+ flex-direction: column;
100
+ justify-content: flex-end;
101
+ align-items: flex-end;
102
+ }
103
+ .post-viewer__information {
104
+ position: absolute;
105
+ bottom: 0;
106
+ left: 0;
107
+ right: 0;
108
+ padding: 1.875rem 0;
109
+ background: linear-gradient(0deg, #000 0%, rgba(0, 0, 0, 0) 100%);
110
+ }
111
+ .post-viewer__text {
112
+ color: #ffffff;
113
+ font-size: 1.125rem;
114
+ font-weight: 400;
115
+ text-shadow: 0 1px 0 rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 6px rgba(0, 0, 0, 0.05);
116
+ padding: var(--post-viewer--information--text--padding);
117
+ }
118
+ .post-viewer__attachments {
119
+ margin-top: 1.25rem;
120
+ }</style>
@@ -1,7 +1,8 @@
1
1
  import type { Locale } from '../../core/locale';
2
- import type { IPostSocialInteractionsHandler, ShortVideoViewerModel } from './types';
2
+ import { type IPostSocialInteractionsHandler } from '..';
3
+ import type { PostViewerModel } from './types';
3
4
  type Props = {
4
- model: ShortVideoViewerModel;
5
+ model: PostViewerModel;
5
6
  socialInteractionsHandler?: IPostSocialInteractionsHandler;
6
7
  showAttachments?: boolean;
7
8
  showControls?: boolean;
@@ -0,0 +1,76 @@
1
+ <script lang="ts">import { ImageRound } from '../../ui/image';
2
+ import { TimeAgo } from '../../ui/time-ago';
3
+ import { PostViewerLocalization } from './post-viewer-localization';
4
+ let { model, localization } = $props();
5
+ </script>
6
+
7
+ <div class="post-viewer-heading">
8
+ <div class="post-viewer-heading__source-image">
9
+ <ImageRound src={model.image} alt={`${model.name} profilbilde`} noBorders={true} />
10
+ </div>
11
+
12
+ <div class="post-viewer-heading__info">
13
+ <div class="post-viewer-heading__source-name">{model.name}</div>
14
+ <p class="post-viewer-heading__metadata">
15
+ <TimeAgo date={model.displayDate} locale={localization.locale} />
16
+ {#if Number.isInteger(model.viewsCount) && model.viewsCount}
17
+ <span>&middot;</span>
18
+ {localization.viewsCount(model.viewsCount)}
19
+ {/if}
20
+ </p>
21
+ </div>
22
+ </div>
23
+
24
+ <style>@keyframes fadeIn {
25
+ 0% {
26
+ opacity: 1;
27
+ }
28
+ 50% {
29
+ opacity: 0.4;
30
+ }
31
+ 100% {
32
+ opacity: 1;
33
+ }
34
+ }
35
+ .post-viewer-heading {
36
+ display: flex;
37
+ align-items: center;
38
+ padding: var(--post-viewer--heading--padding);
39
+ min-width: 0;
40
+ }
41
+ .post-viewer-heading__source-image {
42
+ width: 2rem;
43
+ min-width: 2rem;
44
+ max-width: 2rem;
45
+ height: 2rem;
46
+ min-height: 2rem;
47
+ max-height: 2rem;
48
+ margin-right: 0.625rem;
49
+ --image--rounded--outer--border-radius: 0.5rem;
50
+ --image--rounded--inner--border-width: 0;
51
+ --rounded-img-background: none;
52
+ }
53
+ .post-viewer-heading__info {
54
+ display: flex;
55
+ flex-direction: column;
56
+ min-width: 0;
57
+ }
58
+ .post-viewer-heading__source-name {
59
+ font-size: 0.75rem;
60
+ line-height: 0.9375rem;
61
+ font-weight: 500;
62
+ color: #ffffff;
63
+ text-shadow: 1px 1px hsl(0, 0%, 10%);
64
+ text-overflow: ellipsis;
65
+ width: 100%;
66
+ white-space: nowrap;
67
+ overflow: hidden;
68
+ }
69
+ .post-viewer-heading__metadata {
70
+ margin: 0;
71
+ font-size: 0.625rem;
72
+ line-height: 0.75rem;
73
+ font-weight: 400;
74
+ color: #ffffff;
75
+ text-shadow: 1px 1px hsl(0, 0%, 10%);
76
+ }</style>
@@ -0,0 +1,9 @@
1
+ import { PostViewerLocalization } from './post-viewer-localization';
2
+ import type { PostViewerHeadingModel } from './types';
3
+ type Props = {
4
+ model: PostViewerHeadingModel;
5
+ localization: PostViewerLocalization;
6
+ };
7
+ declare const Heading: import("svelte").Component<Props, {}, "">;
8
+ type Heading = ReturnType<typeof Heading>;
9
+ export default Heading;
@@ -0,0 +1,4 @@
1
+ export { default as PostViewer } from './cmp.post-viewer.svelte';
2
+ export type { PostViewerModel, PostViewerAdCardModel, PostViewerProductCardModel } from './types';
3
+ export { mapToPostViewerModel } from './mapper';
4
+ export { getPostCoverImage } from './utils';
@@ -0,0 +1,3 @@
1
+ export { default as PostViewer } from './cmp.post-viewer.svelte';
2
+ export { mapToPostViewerModel } from './mapper';
3
+ export { getPostCoverImage } from './utils';
@@ -0,0 +1,3 @@
1
+ import type { PostViewerPayloadFragment } from './operations.generated';
2
+ import type { PostViewerModel } from './types';
3
+ export declare const mapToPostViewerModel: (payload: PostViewerPayloadFragment) => PostViewerModel;
@@ -1,26 +1,15 @@
1
1
  import { MediaType } from '../../core/enums';
2
2
  import { getMediaItemImageUrl } from '../../core/media';
3
3
  import { shouldUseSalePrice } from '../../products/price-helper';
4
- export const mapToShortVideoViewerModel = (payload) => {
5
- const mediaBlob = payload.postData.media[0];
6
- if (!mediaBlob) {
7
- console.warn(`Short video '${payload.id}' media is missing. Unexpected behavior.`);
8
- }
4
+ export const mapToPostViewerModel = (payload) => {
9
5
  return {
10
6
  id: payload.id,
11
- media: mediaBlob.type === MediaType.Image
12
- ? { isImage: true, url: mediaBlob.url }
13
- : {
14
- isImage: false,
15
- url: mediaBlob.url,
16
- thumbnailUrl: mediaBlob.thumbnailUrl
17
- },
7
+ media: mapToPostViewerMediaModel(payload.postData),
18
8
  text: payload.postData.shortVideoData.text,
19
9
  enableSocialInteractions: payload.enableSocialInteractions,
20
10
  heading: null,
21
- hasAttachments: !!(payload.allProducts.length || payload.ad),
22
- ad: payload.ad ? mapToShortVideoAdCardModel(payload.ad) : null,
23
- products: payload.allProducts.map((x) => mapToShortVideoProductCard(x))
11
+ ads: payload.ad ? [mapToPostViewerAdCardModel(payload.ad)] : [],
12
+ products: payload.allProducts.map((x) => mapToPostViewerProductCard(x))
24
13
  // uncomment if you want to test many products behavior
25
14
  // .flatMap((x) =>
26
15
  // Array.from({ length: 20 }, (_, i) => ({
@@ -30,7 +19,34 @@ export const mapToShortVideoViewerModel = (payload) => {
30
19
  // )
31
20
  };
32
21
  };
33
- const mapToShortVideoAdCardModel = (payload) => {
22
+ const emptyMedia = { type: 'image', url: '', isMutable: false };
23
+ const toSingleMediaItem = (mediaBlob) => {
24
+ switch (mediaBlob.type) {
25
+ case MediaType.Image:
26
+ return { type: 'image', url: mediaBlob.url, isMutable: false };
27
+ case MediaType.Video:
28
+ case MediaType.ShortVideo:
29
+ return { type: 'video', url: mediaBlob.url, thumbnailUrl: mediaBlob.thumbnailUrl, isMutable: true };
30
+ default:
31
+ return emptyMedia;
32
+ }
33
+ };
34
+ const mapToPostViewerMediaModel = (payload) => {
35
+ const mediaBlob = payload.media[0];
36
+ if (!payload.media.length) {
37
+ return emptyMedia;
38
+ }
39
+ if (payload.media.length > 1) {
40
+ const items = payload.media.map(toSingleMediaItem);
41
+ return {
42
+ type: 'gallery',
43
+ items,
44
+ isMutable: items.some((x) => x.isMutable)
45
+ };
46
+ }
47
+ return toSingleMediaItem(mediaBlob);
48
+ };
49
+ const mapToPostViewerAdCardModel = (payload) => {
34
50
  return {
35
51
  id: payload.id,
36
52
  type: payload.type,
@@ -43,7 +59,7 @@ const mapToShortVideoAdCardModel = (payload) => {
43
59
  ctaButton: payload.ctaButton
44
60
  };
45
61
  };
46
- const mapToShortVideoProductCard = (payload, referenceDate) => {
62
+ const mapToPostViewerProductCard = (payload, referenceDate) => {
47
63
  const effectiveSalePrice = payload.priceAndAvailability.productSalePrices?.find((x) => shouldUseSalePrice({
48
64
  price: payload.priceAndAvailability.price,
49
65
  salePrice: x.salePrice,
@@ -1,6 +1,6 @@
1
1
  import type * as SchemaTypes from '../../../gql/types';
2
2
  import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
3
- export type ShortVideoViewerPayloadFragment = {
3
+ export type PostViewerPayloadFragment = {
4
4
  id: string;
5
5
  enableSocialInteractions: boolean;
6
6
  allProducts: Array<{
@@ -58,4 +58,4 @@ export type ShortVideoViewerPayloadFragment = {
58
58
  } | null;
59
59
  };
60
60
  };
61
- export declare const ShortVideoViewerPayloadFragmentDoc: DocumentNode<ShortVideoViewerPayloadFragment, unknown>;
61
+ export declare const PostViewerPayloadFragmentDoc: DocumentNode<PostViewerPayloadFragment, unknown>;
@@ -1,9 +1,9 @@
1
- export const ShortVideoViewerPayloadFragmentDoc = {
1
+ export const PostViewerPayloadFragmentDoc = {
2
2
  kind: 'Document',
3
3
  definitions: [
4
4
  {
5
5
  kind: 'FragmentDefinition',
6
- name: { kind: 'Name', value: 'ShortVideoViewerPayloadFragment' },
6
+ name: { kind: 'Name', value: 'PostViewerPayloadFragment' },
7
7
  typeCondition: { kind: 'NamedType', name: { kind: 'Name', value: 'Post' } },
8
8
  selectionSet: {
9
9
  kind: 'SelectionSet',
@@ -1,4 +1,4 @@
1
- fragment ShortVideoViewerPayloadFragment on Post {
1
+ fragment PostViewerPayloadFragment on Post {
2
2
  id
3
3
  enableSocialInteractions
4
4
  allProducts {
@@ -0,0 +1,20 @@
1
+ <script lang="ts">import { Image } from '../../ui/image';
2
+ import { Video } from '../../ui/video';
3
+ let { id, media, autoplay = 'on-appearance', on } = $props();
4
+ </script>
5
+
6
+ {#if media.type === 'video'}
7
+ <Video
8
+ src={media.url}
9
+ poster={media.thumbnailUrl}
10
+ controls={false}
11
+ autoplay={autoplay}
12
+ loop={true}
13
+ id={id}
14
+ hideSpeaker={true}
15
+ on={{
16
+ progress: on?.progress
17
+ }} />
18
+ {:else if media.type === 'image'}
19
+ <Image src={media.url} />
20
+ {/if}
@@ -0,0 +1,12 @@
1
+ import type { PostViewerMediaModel } from './types';
2
+ type Props = {
3
+ id: string;
4
+ media: PostViewerMediaModel;
5
+ autoplay?: true | false | 'on-appearance';
6
+ on?: {
7
+ progress?: (progress: number) => void;
8
+ };
9
+ };
10
+ declare const PostMedia: import("svelte").Component<Props, {}, "">;
11
+ type PostMedia = ReturnType<typeof PostMedia>;
12
+ export default PostMedia;
@@ -1,7 +1,6 @@
1
1
  import { type Locale } from '../../core/locale';
2
- export declare class ShortVideoViewerLocalization {
2
+ export declare class PostViewerLocalization {
3
3
  viewsCount: (count: number) => string;
4
- timeAgoLocale: Locale;
5
- productLocale: Locale;
4
+ locale: Locale;
6
5
  constructor(locale: Locale);
7
6
  }
@@ -1,12 +1,10 @@
1
1
  import {} from '../../core/locale';
2
- export class ShortVideoViewerLocalization {
2
+ export class PostViewerLocalization {
3
3
  viewsCount;
4
- timeAgoLocale;
5
- productLocale;
4
+ locale;
6
5
  constructor(locale) {
7
6
  this.viewsCount = loc.viewsCount[locale];
8
- this.timeAgoLocale = locale;
9
- this.productLocale = locale;
7
+ this.locale = locale;
10
8
  }
11
9
  }
12
10
  const loc = {
@@ -1,36 +1,36 @@
1
1
  import { AdType, type Currency } from '../../core/enums';
2
- export type ShortVideoViewerModel = {
2
+ export type PostViewerModel = {
3
3
  id: string;
4
- media: {
5
- isImage: true;
6
- url: string;
7
- } | {
8
- isImage: false;
9
- url: string;
10
- thumbnailUrl: string;
11
- };
4
+ media: PostViewerMediaModel;
12
5
  text: string | null;
13
- heading: ShortVideoViewerHeadingModel | null;
6
+ heading: PostViewerHeadingModel | null;
14
7
  enableSocialInteractions: boolean;
15
- products: ShortVideoProductCardModel[];
16
- ad: ShortVideoAdCardModel | null;
17
- hasAttachments: boolean;
8
+ products: PostViewerProductCardModel[];
9
+ ads: PostViewerAdCardModel[];
10
+ };
11
+ export type PostViewerMediaModel = PostViewerImageMediaModel | PostViewerVideoMediaModel | {
12
+ type: 'gallery';
13
+ items: Array<PostViewerImageMediaModel | PostViewerVideoMediaModel>;
14
+ isMutable: boolean;
15
+ };
16
+ export type PostViewerImageMediaModel = {
17
+ type: 'image';
18
+ url: string;
19
+ isMutable: false;
20
+ };
21
+ export type PostViewerVideoMediaModel = {
22
+ type: 'video';
23
+ url: string;
24
+ thumbnailUrl: string;
25
+ isMutable: true;
18
26
  };
19
- export type ShortVideoViewerHeadingModel = {
27
+ export type PostViewerHeadingModel = {
20
28
  image: string | null;
21
29
  name: string;
22
30
  displayDate: string;
23
31
  viewsCount: number;
24
32
  };
25
- export interface IPostSocialInteractionsHandler {
26
- getIsLiked: (shortVideoId: string) => PromiseLike<{
27
- readonly isLiked: boolean;
28
- }>;
29
- toggleLike: (shortVideoId: string) => PromiseLike<void>;
30
- share: (shortVideoId: string) => PromiseLike<void>;
31
- }
32
- type PromiseLike<T> = T | Promise<T>;
33
- export type ShortVideoProductCardModel = {
33
+ export type PostViewerProductCardModel = {
34
34
  id: string;
35
35
  title: string;
36
36
  shortDescription: string | null;
@@ -41,7 +41,7 @@ export type ShortVideoProductCardModel = {
41
41
  currency: Currency;
42
42
  salePrice: number | null;
43
43
  };
44
- export type ShortVideoAdCardModel = {
44
+ export type PostViewerAdCardModel = {
45
45
  id: string;
46
46
  type: AdType;
47
47
  image: string | null;
@@ -58,4 +58,3 @@ export type ShortVideoAdCardModel = {
58
58
  border: string;
59
59
  } | null;
60
60
  };
61
- export {};
@@ -1,4 +1,4 @@
1
- export declare class ShortVideoViewerUiManager {
1
+ export declare class PostViewerUiManager {
2
2
  readonly globalCssVariables: string;
3
3
  readonly showAttachments: boolean;
4
4
  readonly showControls: boolean;
@@ -6,8 +6,10 @@ export declare class ShortVideoViewerUiManager {
6
6
  private canShowControls;
7
7
  private canShowAttachments;
8
8
  private enableAttachments;
9
- updateCanShowAttachments: (value: boolean) => void;
10
- updateCanShowControls: (value: boolean) => void;
9
+ private infoPaddingLeft;
10
+ private infoPaddingRight;
11
+ setCanShowAttachments: (value: boolean) => void;
12
+ setCanShowControls: (value: boolean) => void;
11
13
  toggleEnableAttachments: () => void;
12
14
  setControlsPanelWidth(value: number): void;
13
15
  }
@@ -1,6 +1,11 @@
1
- export class ShortVideoViewerUiManager {
1
+ const INFO_PADDING_HORIZONTAL = 20;
2
+ export class PostViewerUiManager {
2
3
  globalCssVariables = $derived.by(() => {
3
- const values = [`--_short-video-viewer--controls-panel--width: ${this.controlsPanelWidth}px`];
4
+ const values = [
5
+ `--post-viewer--heading--padding: 0 ${this.infoPaddingRight}px 14px ${this.infoPaddingLeft}px`,
6
+ `--post-viewer--information--text--padding: 0 ${this.infoPaddingRight}px 0 ${this.infoPaddingLeft}px`,
7
+ `--post-viewer--attachments-horizontal--padding-horizontal: ${INFO_PADDING_HORIZONTAL}px`
8
+ ];
4
9
  return values.join(';');
5
10
  });
6
11
  showAttachments = $derived.by(() => {
@@ -16,10 +21,12 @@ export class ShortVideoViewerUiManager {
16
21
  canShowAttachments = $state(false);
17
22
  // managed internally by component
18
23
  enableAttachments = $state(true);
19
- updateCanShowAttachments = (value) => {
24
+ infoPaddingLeft = $derived(INFO_PADDING_HORIZONTAL);
25
+ infoPaddingRight = $derived(INFO_PADDING_HORIZONTAL + this.controlsPanelWidth ? this.controlsPanelWidth + 10 : 0);
26
+ setCanShowAttachments = (value) => {
20
27
  this.canShowAttachments = value;
21
28
  };
22
- updateCanShowControls = (value) => {
29
+ setCanShowControls = (value) => {
23
30
  this.canShowControls = value;
24
31
  };
25
32
  toggleEnableAttachments = () => {
@@ -0,0 +1,2 @@
1
+ import type { PostViewerModel } from './types';
2
+ export declare const getPostCoverImage: (post: PostViewerModel) => string;
@@ -0,0 +1,13 @@
1
+ import { Utils } from '../../core/utils';
2
+ export const getPostCoverImage = (post) => {
3
+ switch (post.media.type) {
4
+ case 'image':
5
+ return post.media.url;
6
+ case 'video':
7
+ return post.media.thumbnailUrl;
8
+ case 'gallery':
9
+ return post.media.items[0].type === 'image' ? post.media.items[0].url : post.media.items[0].thumbnailUrl;
10
+ default:
11
+ Utils.assertUnreachable(post.media);
12
+ }
13
+ };
@@ -0,0 +1 @@
1
+ export type { IPostSocialInteractionsHandler } from './types';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ export interface IPostSocialInteractionsHandler {
2
+ getIsLiked: (shortVideoId: string) => PromiseLike<{
3
+ readonly isLiked: boolean;
4
+ }>;
5
+ toggleLike: (shortVideoId: string) => PromiseLike<void>;
6
+ share: (shortVideoId: string) => PromiseLike<void>;
7
+ }
8
+ type PromiseLike<T> = T | Promise<T>;
9
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -5,12 +5,31 @@ import { ProportionalContainer } from '../../ui/proportional-container';
5
5
  import { ProductCardLocalization } from './product-card-localization';
6
6
  let { product, includeBeforeNowPrefix, inert = false, locale = 'en', on } = $props();
7
7
  const localization = $derived(new ProductCardLocalization(locale));
8
- const showDescriptionPresented = $derived(product.shortDescription && product.shortDescription.length > 0);
8
+ const shortDescriptionPresented = $derived(product.shortDescription && product.shortDescription.length > 0);
9
+ const trackImpression = (node) => {
10
+ if (on === null || on === void 0 ? void 0 : on.impression) {
11
+ const observer = new IntersectionObserver((entries) => {
12
+ entries.forEach((entry) => {
13
+ var _a;
14
+ if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
15
+ (_a = on.impression) === null || _a === void 0 ? void 0 : _a.call(on, product.id);
16
+ observer.unobserve(entry.target);
17
+ }
18
+ });
19
+ }, { threshold: 0.5 });
20
+ observer.observe(node);
21
+ return {
22
+ destroy() {
23
+ observer.disconnect();
24
+ }
25
+ };
26
+ }
27
+ };
9
28
  const onProductClicked = (event) => {
10
29
  event.preventDefault();
11
30
  event.stopPropagation();
12
- if (on === null || on === void 0 ? void 0 : on.productClick) {
13
- on.productClick(product.id);
31
+ if (on === null || on === void 0 ? void 0 : on.click) {
32
+ on.click(product.id);
14
33
  }
15
34
  if (!product.link) {
16
35
  return;
@@ -19,7 +38,7 @@ const onProductClicked = (event) => {
19
38
  };
20
39
  </script>
21
40
 
22
- <div class="product-card" inert={inert}>
41
+ <div class="product-card" inert={inert} use:trackImpression>
23
42
  <ProportionalContainer ratio={1}>
24
43
  <Image src={product.image} />
25
44
  </ProportionalContainer>
@@ -28,11 +47,11 @@ const onProductClicked = (event) => {
28
47
  <LineClamp maxLines={1}>
29
48
  <div class="product-card__brand">{product.brandName}</div>
30
49
  </LineClamp>
31
- <LineClamp value={product.shortDescription} maxLines={showDescriptionPresented ? 1 : 2}>
32
- <div class="product-card__title" class:two-lines={!showDescriptionPresented}>{product.title}</div>
50
+ <LineClamp value={product.shortDescription} maxLines={shortDescriptionPresented ? 1 : 2}>
51
+ <div class="product-card__title" class:two-lines={!shortDescriptionPresented}>{product.title}</div>
33
52
  </LineClamp>
34
53
  <LineClamp value={product.shortDescription} maxLines={2}>
35
- <div class="product-card__description" class:two-lines={showDescriptionPresented}>{product.shortDescription}</div>
54
+ <div class="product-card__description" class:two-lines={shortDescriptionPresented}>{product.shortDescription}</div>
36
55
  </LineClamp>
37
56
  <div class="product-price">
38
57
  <div class="product-price__before-price">
@@ -49,7 +68,7 @@ const onProductClicked = (event) => {
49
68
  </div>
50
69
  </div>
51
70
 
52
- {#if product.link || on?.productClick}
71
+ {#if product.link || on?.click}
53
72
  <a href={product.link} onclick={onProductClicked} target="_blank" rel="noopener noreferrer" class="product-card__link" aria-label="none">&nbsp;</a>
54
73
  {/if}
55
74
  </div>
@@ -6,7 +6,8 @@ type Props = {
6
6
  includeBeforeNowPrefix?: boolean;
7
7
  inert?: boolean;
8
8
  on?: {
9
- productClick?: (id: string) => void;
9
+ click?: (id: string) => void;
10
+ impression?: (id: string) => void;
10
11
  };
11
12
  };
12
13
  declare const Cmp: import("svelte").Component<Props, {}, "">;