@streamscloud/embeddable 7.5.2 → 8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/content-player/cmp.content-player.svelte +69 -34
  2. package/dist/content-player/content-player-config.svelte.d.ts +8 -17
  3. package/dist/content-player/content-player-config.svelte.js +16 -15
  4. package/dist/content-player/content-player-settings.d.ts +14 -0
  5. package/dist/content-player/content-player-settings.js +14 -0
  6. package/dist/content-player/controls-and-attachments.svelte +9 -4
  7. package/dist/content-player/header.svelte +1 -1
  8. package/dist/content-player/index.d.ts +1 -1
  9. package/dist/core/analytics.profile-id.js +27 -1
  10. package/dist/core/utils/html-helper.d.ts +1 -0
  11. package/dist/core/utils/html-helper.js +3 -0
  12. package/dist/media-center/media-center/cmp.media-center.svelte +32 -24
  13. package/dist/media-center/media-center/discover-panel.svelte +1 -1
  14. package/dist/posts/attachments/cmp.attachments.svelte +7 -6
  15. package/dist/posts/attachments/cmp.attachments.svelte.d.ts +2 -2
  16. package/dist/posts/controls/cmp.controls.svelte +2 -2
  17. package/dist/posts/controls/cmp.controls.svelte.d.ts +2 -2
  18. package/dist/posts/index.d.ts +1 -0
  19. package/dist/posts/model/index.d.ts +3 -1
  20. package/dist/posts/model/index.js +2 -1
  21. package/dist/posts/model/post-media-model.svelte.d.ts +20 -0
  22. package/dist/posts/model/post-media-model.svelte.js +16 -0
  23. package/dist/posts/model/post-model.d.ts +25 -0
  24. package/dist/posts/model/post-model.js +28 -0
  25. package/dist/posts/model/types.d.ts +53 -9
  26. package/dist/posts/model/types.js +1 -1
  27. package/dist/posts/model/utils.d.ts +4 -0
  28. package/dist/posts/model/utils.js +7 -0
  29. package/dist/posts/post-viewer/attachments-horizontal.svelte +7 -2
  30. package/dist/posts/post-viewer/attachments-horizontal.svelte.d.ts +2 -2
  31. package/dist/posts/post-viewer/cmp.post-viewer.svelte +27 -50
  32. package/dist/posts/post-viewer/cmp.post-viewer.svelte.d.ts +2 -2
  33. package/dist/posts/post-viewer/heading.svelte +2 -1
  34. package/dist/posts/post-viewer/heading.svelte.d.ts +2 -2
  35. package/dist/posts/post-viewer/index.d.ts +1 -3
  36. package/dist/posts/post-viewer/index.js +1 -2
  37. package/dist/posts/post-viewer/mapper.d.ts +2 -2
  38. package/dist/posts/post-viewer/mapper.js +23 -27
  39. package/dist/posts/post-viewer/media/post-media.svelte +64 -0
  40. package/dist/posts/post-viewer/{post-media.svelte.d.ts → media/post-media.svelte.d.ts} +4 -6
  41. package/dist/posts/post-viewer/post-texts.svelte +101 -0
  42. package/dist/posts/post-viewer/post-texts.svelte.d.ts +11 -0
  43. package/dist/posts/post-viewer/post-viewer-localization.d.ts +1 -0
  44. package/dist/posts/post-viewer/post-viewer-localization.js +4 -1
  45. package/dist/posts/posts-player/index.d.ts +2 -3
  46. package/dist/posts/posts-player/index.js +0 -1
  47. package/dist/posts/posts-player/posts-player-view.svelte +3 -2
  48. package/dist/posts/posts-player/types.d.ts +5 -4
  49. package/dist/short-videos/short-videos-player/index.d.ts +3 -4
  50. package/dist/short-videos/short-videos-player/index.js +0 -1
  51. package/dist/short-videos/short-videos-player/mapper.js +2 -2
  52. package/dist/short-videos/short-videos-player/short-videos-player-view.svelte +3 -2
  53. package/dist/short-videos/short-videos-player/types.d.ts +5 -4
  54. package/dist/streams/layout/element-views/cmp.short-video-stream-element.svelte +4 -3
  55. package/dist/streams/layout/models/index.d.ts +1 -1
  56. package/dist/streams/layout/models/index.js +1 -1
  57. package/dist/streams/layout/models/mapper.d.ts +2 -2
  58. package/dist/streams/layout/models/mapper.js +10 -9
  59. package/dist/streams/stream-player/index.d.ts +3 -4
  60. package/dist/streams/stream-player/stream-player-view.svelte +4 -3
  61. package/dist/streams/stream-player/types.d.ts +3 -2
  62. package/dist/ui/line-clamp/cmp.line-clamp.svelte +1 -0
  63. package/dist/ui/player-slider/cmp.player-slider.svelte +44 -7
  64. package/dist/ui/player-slider/cmp.player-slider.svelte.d.ts +2 -2
  65. package/dist/ui/player-slider/player-buffer.svelte.d.ts +4 -3
  66. package/dist/ui/player-slider/player-buffer.svelte.js +9 -3
  67. package/dist/ui/player-slider/types.d.ts +5 -2
  68. package/dist/ui/slider/cmp.slider.svelte +398 -0
  69. package/dist/ui/slider/cmp.slider.svelte.d.ts +31 -0
  70. package/dist/ui/slider/index.d.ts +2 -0
  71. package/dist/ui/slider/index.js +2 -0
  72. package/dist/ui/slider/slider-localization.d.ts +5 -0
  73. package/dist/ui/slider/slider-localization.js +13 -0
  74. package/dist/ui/slider/types.d.ts +11 -0
  75. package/dist/ui/slider/types.js +8 -0
  76. package/package.json +2 -2
  77. package/dist/posts/post-viewer/media/media-slider.svelte +0 -10
  78. package/dist/posts/post-viewer/media/media-slider.svelte.d.ts +0 -27
  79. package/dist/posts/post-viewer/post-media.svelte +0 -26
  80. package/dist/posts/post-viewer/types.d.ts +0 -60
  81. package/dist/posts/post-viewer/types.js +0 -1
  82. package/dist/posts/post-viewer/utils.d.ts +0 -2
  83. package/dist/posts/post-viewer/utils.js +0 -13
@@ -0,0 +1,16 @@
1
+ export class PostViewerMediaModel {
2
+ currentItem = $derived.by(() => {
3
+ const item = this.items[this.currentIndex];
4
+ return item ? item : { isImage: true, url: '' };
5
+ });
6
+ currentIndex = $state(0);
7
+ isGallery = $derived.by(() => this.items.length > 1);
8
+ items;
9
+ mediaFit;
10
+ constructor(init) {
11
+ const { media, mediaFit, mediaIndex } = init;
12
+ this.items = media;
13
+ this.mediaFit = mediaFit;
14
+ this.currentIndex = mediaIndex || 0;
15
+ }
16
+ }
@@ -0,0 +1,25 @@
1
+ import { PostViewerMediaModel } from './post-media-model.svelte';
2
+ import type { IPostModel, IPostAdCardModel, IPostHeadingModel, IPostProductCardModel } from './types';
3
+ export declare class PostModel {
4
+ id: string;
5
+ media: PostViewerMediaModel;
6
+ texts: {
7
+ kicker: string | null;
8
+ title: string | null;
9
+ text: string | null;
10
+ readMoreUrl: string | null;
11
+ };
12
+ heading: PostHeadingModel | null;
13
+ enableSocialInteractions: boolean;
14
+ attachments: false | {
15
+ products: PostProductCardModel[];
16
+ ads: PostAdCardModel[];
17
+ };
18
+ constructor(init: IPostModel & {
19
+ mediaIndex?: number;
20
+ });
21
+ }
22
+ type PostHeadingModel = IPostHeadingModel;
23
+ type PostAdCardModel = IPostAdCardModel;
24
+ type PostProductCardModel = IPostProductCardModel;
25
+ export {};
@@ -0,0 +1,28 @@
1
+ import { PostViewerMediaModel } from './post-media-model.svelte';
2
+ export class PostModel {
3
+ id;
4
+ media;
5
+ texts;
6
+ heading;
7
+ enableSocialInteractions;
8
+ attachments;
9
+ constructor(init) {
10
+ this.id = init.id;
11
+ this.media = new PostViewerMediaModel({ media: init.media, mediaFit: init.mediaFit, mediaIndex: init.mediaIndex });
12
+ this.texts = {
13
+ kicker: init.kicker,
14
+ title: init.title,
15
+ text: init.text,
16
+ readMoreUrl: init.readMoreUrl ?? null
17
+ };
18
+ this.heading = init.heading;
19
+ this.enableSocialInteractions = init.enableSocialInteractions;
20
+ this.attachments =
21
+ init.products.length || init.ads.length
22
+ ? {
23
+ products: init.products,
24
+ ads: init.ads
25
+ }
26
+ : false;
27
+ }
28
+ }
@@ -1,13 +1,57 @@
1
- import type { AdCardModel } from '../../ads/ad-card';
2
- import type { ProductCardModel } from '../../products/product-card';
3
- export type PostContainer = PostAttachmentsContainer & {
1
+ import { AdType, type Currency } from '../../core/enums';
2
+ export type IPostModel = {
4
3
  id: string;
4
+ media: IPostMediaItemModel[];
5
+ mediaFit: PostModelMediaFit;
6
+ kicker: string | null;
7
+ title: string | null;
8
+ text: string | null;
9
+ readMoreUrl?: string;
10
+ heading: IPostHeadingModel | null;
5
11
  enableSocialInteractions: boolean;
6
- media: {
7
- isMutable: boolean;
8
- } | null;
12
+ products: IPostProductCardModel[];
13
+ ads: IPostAdCardModel[];
14
+ };
15
+ export type IPostMediaItemModel = {
16
+ isImage: true;
17
+ url: string;
18
+ } | {
19
+ isImage: false;
20
+ url: string;
21
+ thumbnailUrl: string;
9
22
  };
10
- export type PostAttachmentsContainer = {
11
- ads: AdCardModel[];
12
- products: ProductCardModel[];
23
+ export type IPostHeadingModel = {
24
+ image: string | null;
25
+ name: string;
26
+ displayDate: string;
27
+ viewsCount: number;
28
+ };
29
+ export type PostModelMediaFit = 'cover' | 'contain';
30
+ export type IPostProductCardModel = {
31
+ id: string;
32
+ title: string;
33
+ shortDescription: string | null;
34
+ link: string | null;
35
+ image: string | null;
36
+ brandName: string | null;
37
+ price: number;
38
+ currency: Currency;
39
+ salePrice: number | null;
40
+ };
41
+ export type IPostAdCardModel = {
42
+ id: string;
43
+ type: AdType;
44
+ image: string | null;
45
+ title: string;
46
+ description: string | null;
47
+ price: number | null;
48
+ priceInfoLabel: string | null;
49
+ currency: Currency | null;
50
+ ctaButton: {
51
+ background: string;
52
+ textColor: string;
53
+ text: string;
54
+ url: string;
55
+ border: string;
56
+ } | null;
13
57
  };
@@ -1 +1 @@
1
- export {};
1
+ import { AdType } from '../../core/enums';
@@ -0,0 +1,4 @@
1
+ import type { IPostMediaItemModel } from './types';
2
+ export declare const getPostCoverImage: (post: {
3
+ media: IPostMediaItemModel[];
4
+ }) => string;
@@ -0,0 +1,7 @@
1
+ export const getPostCoverImage = (post) => {
2
+ const firstItem = post.media[0];
3
+ if (!firstItem) {
4
+ return '';
5
+ }
6
+ return firstItem.isImage ? firstItem.url : firstItem.thumbnailUrl;
7
+ };
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">import { horizontalWheelScroll, swallowTouch } from '../../core/actions';
2
2
  import { Currency } from '../../core/enums';
3
+ import { PostModel } from '../model';
3
4
  import { toPriceRepresentation } from '../../products/price-helper';
4
5
  import { Icon, IconColor } from '../../ui/icon';
5
6
  import { ImageRounded } from '../../ui/image';
@@ -7,7 +8,10 @@ import { PostViewerUiManager } from './ui-manager.svelte';
7
8
  import IconTargetArrow from '@fluentui/svg-icons/icons/target_arrow_20_regular.svg?raw';
8
9
  let { model, uiManager, on } = $props();
9
10
  const attachmentsToShow = $derived.by(() => {
10
- const products = model.products
11
+ if (!model.attachments) {
12
+ return [];
13
+ }
14
+ const products = model.attachments.products
11
15
  .filter((p) => !!p.image)
12
16
  .map((p) => ({
13
17
  isAd: false,
@@ -22,7 +26,7 @@ const attachmentsToShow = $derived.by(() => {
22
26
  title: p.title,
23
27
  description: p.shortDescription
24
28
  }));
25
- const ads = model.ads
29
+ const ads = model.attachments.ads
26
30
  .filter((a) => !!a.image)
27
31
  .map((a) => {
28
32
  var _a;
@@ -154,6 +158,7 @@ const variables = $derived.by(() => {
154
158
  }
155
159
  }
156
160
  .attachments-horizontal {
161
+ pointer-events: auto;
157
162
  display: flex;
158
163
  gap: 0.5rem;
159
164
  flex-wrap: nowrap;
@@ -1,7 +1,7 @@
1
- import type { PostViewerModel } from './types';
1
+ import { PostModel } from '../model';
2
2
  import { PostViewerUiManager } from './ui-manager.svelte';
3
3
  type Props = {
4
- model: PostViewerModel;
4
+ model: PostModel;
5
5
  uiManager: PostViewerUiManager;
6
6
  on?: {
7
7
  productClick?: (productId: string) => void;
@@ -1,8 +1,9 @@
1
1
  <script lang="ts">import { PostControls } from '../controls';
2
- import { LineClamp } from '../../ui/line-clamp';
2
+ import { PostModel } from '../model';
3
3
  import { default as AttachmentsHorizontal } from './attachments-horizontal.svelte';
4
4
  import { default as Heading } from './heading.svelte';
5
- import { default as PostMedia } from './post-media.svelte';
5
+ import { default as PostMedia } from './media/post-media.svelte';
6
+ import { default as Texts } from './post-texts.svelte';
6
7
  import { PostViewerLocalization } from './post-viewer-localization';
7
8
  import { PostViewerUiManager } from './ui-manager.svelte';
8
9
  let { model, socialInteractionsHandler, enableAttachments = true, enableControls = true, autoplay = 'on-appearance', locale = 'en', on } = $props();
@@ -35,40 +36,33 @@ const trackControlsPanelSize = (node) => {
35
36
  }
36
37
  };
37
38
  };
38
- const handleMediaContentChanged = (data) => {
39
- console.warn('gallery:', data.galleryMode, 'seekBar:', data.videoSeekBar);
40
- };
41
39
  const variables = $derived.by(() => {
42
- const values = [
43
- `--_post-viewer--information--text--padding: 0 ${uiManager.controlsPanelWidth ? uiManager.controlsPanelWidth : uiManager.infoPaddingInline}px 0 ${uiManager.infoPaddingInline}px`
44
- ];
40
+ const values = [];
41
+ if (model.media.isGallery) {
42
+ values.push(`--_post-viewer--information--padding-bottom: 45px`);
43
+ }
45
44
  return values.join(';');
46
45
  });
47
46
  </script>
48
47
 
49
48
  <div class="post-viewer" style={variables} use:viewerMounted>
50
- <PostMedia id={model.id} media={model.media} autoplay={autoplay} on={{ progress: on?.progress, mediaChanged: handleMediaContentChanged }} />
49
+ <PostMedia id={model.id} media={model.media} locale={locale} autoplay={autoplay} on={{ videoProgress: on?.progress }} />
51
50
  <div class="post-viewer__information">
52
51
  {#if model.heading}
53
52
  <Heading model={model.heading} uiManager={uiManager} localization={localization} />
54
53
  {/if}
55
- <div class="post-viewer__text">
56
- {#if model.text}
57
- <LineClamp value={model.text} maxLines={2} enableShowMore={true} />
58
- {/if}
59
- </div>
60
- {#if uiManager.showAttachments && (model.ads.length || model.products.length)}
61
- <div class="post-viewer__attachments">
62
- <AttachmentsHorizontal
63
- model={model}
64
- uiManager={uiManager}
65
- on={{
66
- productClick: on?.productClick,
67
- productImpression: on?.productImpression,
68
- adClick: on?.adClick,
69
- adImpression: on?.adImpression
70
- }} />
71
- </div>
54
+ <Texts model={model.texts} uiManager={uiManager} localization={localization} />
55
+
56
+ {#if uiManager.showAttachments && model.attachments}
57
+ <AttachmentsHorizontal
58
+ model={model}
59
+ uiManager={uiManager}
60
+ on={{
61
+ productClick: on?.productClick,
62
+ productImpression: on?.productImpression,
63
+ adClick: on?.adClick,
64
+ adImpression: on?.adImpression
65
+ }} />
72
66
  {/if}
73
67
  </div>
74
68
 
@@ -94,7 +88,6 @@ const variables = $derived.by(() => {
94
88
  }
95
89
  }
96
90
  .post-viewer {
97
- --video--media-fit: cover;
98
91
  width: 100%;
99
92
  min-width: 100%;
100
93
  max-width: 100%;
@@ -116,7 +109,6 @@ const variables = $derived.by(() => {
116
109
  position: absolute;
117
110
  left: auto;
118
111
  right: 0;
119
- top: 5rem;
120
112
  bottom: 6.25rem;
121
113
  gap: 2.5rem;
122
114
  display: flex;
@@ -126,38 +118,23 @@ const variables = $derived.by(() => {
126
118
  padding: 0 0.625rem;
127
119
  }
128
120
  .post-viewer__information {
121
+ pointer-events: none;
129
122
  position: absolute;
130
123
  bottom: 0;
131
124
  left: 0;
132
125
  right: 0;
133
126
  padding: 1.875rem 0;
127
+ padding-bottom: var(--_post-viewer--information--padding-bottom, 1.875rem);
128
+ display: flex;
129
+ flex-direction: column;
130
+ gap: 1.25rem;
134
131
  background: linear-gradient(0deg, #000 0%, rgba(0, 0, 0, 0) 100%);
135
132
  /* Set 'container-type: inline-size;' to reference container*/
136
133
  }
137
134
  @container (width < 576px) {
138
135
  .post-viewer__information {
139
136
  padding-block: 1.25rem;
140
- }
141
- }
142
- .post-viewer__text {
143
- color: #ffffff;
144
- font-size: 1.125rem;
145
- font-weight: 400;
146
- 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);
147
- padding: var(--_post-viewer--information--text--padding);
148
- /* Set 'container-type: inline-size;' to reference container*/
149
- }
150
- @container (width < 576px) {
151
- .post-viewer__text {
152
- font-size: 0.9375rem;
153
- }
154
- }
155
- .post-viewer__attachments {
156
- margin-top: 1.25rem;
157
- /* Set 'container-type: inline-size;' to reference container*/
158
- }
159
- @container (width < 576px) {
160
- .post-viewer__attachments {
161
- margin-top: 0.625rem;
137
+ padding-bottom: var(--_post-viewer--information--padding-bottom, 1.25rem);
138
+ gap: 0.625rem;
162
139
  }
163
140
  }</style>
@@ -1,8 +1,8 @@
1
1
  import type { Locale } from '../../core/locale';
2
+ import { PostModel } from '../model';
2
3
  import type { IPostSocialInteractionsHandler } from '../social-interactions';
3
- import type { PostViewerModel } from './types';
4
4
  type Props = {
5
- model: PostViewerModel;
5
+ model: PostModel;
6
6
  socialInteractionsHandler?: IPostSocialInteractionsHandler;
7
7
  enableAttachments?: boolean;
8
8
  enableControls?: boolean;
@@ -1,4 +1,5 @@
1
- <script lang="ts">import { PostViewerUiManager } from './ui-manager.svelte';
1
+ <script lang="ts">import { PostModel } from '../model';
2
+ import { PostViewerUiManager } from './ui-manager.svelte';
2
3
  import { ImageRound } from '../../ui/image';
3
4
  import { TimeAgo } from '../../ui/time-ago';
4
5
  import { PostViewerLocalization } from './post-viewer-localization';
@@ -1,8 +1,8 @@
1
+ import { PostModel } from '../model';
1
2
  import { PostViewerUiManager } from './ui-manager.svelte';
2
3
  import { PostViewerLocalization } from './post-viewer-localization';
3
- import type { PostViewerHeadingModel } from './types';
4
4
  type Props = {
5
- model: PostViewerHeadingModel;
5
+ model: NonNullable<PostModel['heading']>;
6
6
  uiManager: PostViewerUiManager;
7
7
  localization: PostViewerLocalization;
8
8
  };
@@ -1,4 +1,2 @@
1
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';
2
+ export { mapToPostModel } from './mapper';
@@ -1,3 +1,2 @@
1
1
  export { default as PostViewer } from './cmp.post-viewer.svelte';
2
- export { mapToPostViewerModel } from './mapper';
3
- export { getPostCoverImage } from './utils';
2
+ export { mapToPostModel } from './mapper';
@@ -1,3 +1,3 @@
1
+ import type { IPostModel } from '../model';
1
2
  import type { PostViewerPayloadFragment } from './operations.generated';
2
- import type { PostViewerModel } from './types';
3
- export declare const mapToPostViewerModel: (payload: PostViewerPayloadFragment) => PostViewerModel;
3
+ export declare const mapToPostModel: (payload: PostViewerPayloadFragment) => IPostModel;
@@ -1,10 +1,13 @@
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 mapToPostViewerModel = (payload) => {
4
+ export const mapToPostModel = (payload) => {
5
5
  return {
6
6
  id: payload.id,
7
7
  media: mapToPostViewerMediaModel(payload.postData),
8
+ mediaFit: mediaFitFromPostType(payload.postData),
9
+ kicker: extractPostKicker(payload.postData),
10
+ title: extractPostTitle(payload.postData),
8
11
  text: extractPostText(payload.postData),
9
12
  enableSocialInteractions: payload.enableSocialInteractions,
10
13
  heading: null,
@@ -19,35 +22,28 @@ export const mapToPostViewerModel = (payload) => {
19
22
  // )
20
23
  };
21
24
  };
22
- const extractPostText = (payload) => {
23
- return payload.articleData?.title ?? payload.mediaData?.text ?? payload.momentData?.text ?? payload.shortVideoData?.text ?? payload.videoData?.text ?? null;
25
+ const mediaFitFromPostType = (payload) => {
26
+ return payload.shortVideoData || payload.momentData ? 'cover' : 'contain';
27
+ };
28
+ const extractPostKicker = (payload) => {
29
+ return payload.articleData?.kicker ?? null;
24
30
  };
25
- const emptyMedia = { type: 'image', url: '', isMutable: false };
26
- const toSingleMediaItem = (mediaBlob) => {
27
- switch (mediaBlob.type) {
28
- case MediaType.Image:
29
- return { type: 'image', url: mediaBlob.url, isMutable: false };
30
- case MediaType.Video:
31
- case MediaType.ShortVideo:
32
- return { type: 'video', url: mediaBlob.url, thumbnailUrl: mediaBlob.thumbnailUrl, isMutable: true };
33
- default:
34
- return emptyMedia;
35
- }
31
+ const extractPostTitle = (payload) => {
32
+ return payload.articleData?.title ?? payload.videoData?.title ?? null;
33
+ };
34
+ const extractPostText = (payload) => {
35
+ return payload.mediaData?.text ?? payload.momentData?.text ?? payload.shortVideoData?.text ?? payload.videoData?.text ?? null;
36
36
  };
37
37
  const mapToPostViewerMediaModel = (payload) => {
38
- const mediaBlob = payload.media[0];
39
- if (!payload.media.length) {
40
- return emptyMedia;
41
- }
42
- if (payload.media.length > 1) {
43
- const items = payload.media.map(toSingleMediaItem);
44
- return {
45
- type: 'gallery',
46
- items,
47
- isMutable: items.some((x) => x.isMutable)
48
- };
49
- }
50
- return toSingleMediaItem(mediaBlob);
38
+ return payload.media.map((i) => {
39
+ return i.type === MediaType.Image
40
+ ? { isImage: true, url: i.url }
41
+ : {
42
+ isImage: false,
43
+ url: i.url,
44
+ thumbnailUrl: i.thumbnailUrl
45
+ };
46
+ });
51
47
  };
52
48
  const mapToPostViewerAdCardModel = (payload) => {
53
49
  return {
@@ -0,0 +1,64 @@
1
+ <script lang="ts">import { Image } from '../../../ui/image';
2
+ import { Slider } from '../../../ui/slider';
3
+ import { Video } from '../../../ui/video';
4
+ let { id, media, locale, autoplay = 'on-appearance', on } = $props();
5
+ </script>
6
+
7
+ {#snippet mediaItem(item: IPostMediaItemModel)}
8
+ {#if item.isImage}
9
+ <Image src={item.url} />
10
+ {:else}
11
+ <Video
12
+ src={item.url}
13
+ poster={item.thumbnailUrl}
14
+ controls={false}
15
+ autoplay={autoplay}
16
+ loop={true}
17
+ id={id}
18
+ hideSpeaker={true}
19
+ on={{
20
+ progress: on?.videoProgress
21
+ }} />
22
+ {/if}
23
+ {/snippet}
24
+
25
+ <div class="post-media" class:post-media--fit={media.mediaFit === 'contain'} class:post-media--fill={media.mediaFit === 'cover'}>
26
+ {#if media.items.length === 1}
27
+ {@render mediaItem(media.items[0])}
28
+ {:else if media.items.length > 1}
29
+ <Slider items={media.items} initialIndex={media.currentIndex} locale={locale} on={{ indexChanged: (index) => (media.currentIndex = index) }}>
30
+ {#snippet children(item)}
31
+ {@render mediaItem(item)}
32
+ {/snippet}
33
+ </Slider>
34
+ {/if}
35
+ </div>
36
+
37
+ <style>@keyframes fadeIn {
38
+ 0% {
39
+ opacity: 1;
40
+ }
41
+ 50% {
42
+ opacity: 0.4;
43
+ }
44
+ 100% {
45
+ opacity: 1;
46
+ }
47
+ }
48
+ .post-media {
49
+ width: 100%;
50
+ min-width: 100%;
51
+ max-width: 100%;
52
+ height: 100%;
53
+ min-height: 100%;
54
+ max-height: 100%;
55
+ background-color: rgba(0, 0, 0, 0.6);
56
+ }
57
+ .post-media--fit {
58
+ --video--media-fit: contain;
59
+ --image--object-fit: contain;
60
+ }
61
+ .post-media--fill {
62
+ --video--media-fit: cover;
63
+ --image--object-fit: cover;
64
+ }</style>
@@ -1,14 +1,12 @@
1
- import type { PostViewerMediaModel } from './types';
1
+ import type { Locale } from '../../../core/locale';
2
+ import type { PostViewerMediaModel } from '../../model/post-media-model.svelte';
2
3
  type Props = {
3
4
  id: string;
4
5
  media: PostViewerMediaModel;
6
+ locale: Locale;
5
7
  autoplay?: true | false | 'on-appearance';
6
8
  on: {
7
- mediaChanged: (data: {
8
- videoSeekBar: boolean;
9
- galleryMode: boolean;
10
- }) => void;
11
- progress?: (progress: number) => void;
9
+ videoProgress?: (progress: number) => void;
12
10
  };
13
11
  };
14
12
  declare const PostMedia: import("svelte").Component<Props, {}, "">;
@@ -0,0 +1,101 @@
1
+ <script lang="ts">import { LineClamp } from '../../ui/line-clamp';
2
+ import { PostViewerLocalization } from './post-viewer-localization';
3
+ import { PostViewerUiManager } from './ui-manager.svelte';
4
+ let { model, uiManager, localization } = $props();
5
+ const variables = $derived.by(() => {
6
+ const values = [
7
+ `--_post-viewer-texts--padding: 0 ${uiManager.controlsPanelWidth ? uiManager.controlsPanelWidth : uiManager.infoPaddingInline}px 0 ${uiManager.infoPaddingInline}px`
8
+ ];
9
+ return values.join(';');
10
+ });
11
+ </script>
12
+
13
+ <div class="post-viewer-texts" style={variables}>
14
+ {#if model.kicker}
15
+ <div class="post-viewer-texts__kicker">
16
+ <LineClamp value={model.kicker} maxLines={1} enableShowMore={false} />
17
+ </div>
18
+ {/if}
19
+ {#if model.title}
20
+ <div class="post-viewer-texts__title">
21
+ <LineClamp value={model.title} maxLines={2} enableShowMore={false} />
22
+ </div>
23
+ {/if}
24
+ {#if model.text}
25
+ <div class="post-viewer-texts__text">
26
+ <LineClamp value={model.text} maxLines={2} enableShowMore={true} />
27
+ </div>
28
+ {/if}
29
+ {#if model.readMoreUrl}
30
+ <a class="post-viewer-texts__read-more" href={model.readMoreUrl} target="_blank" rel="noopener noreferrer">
31
+ {localization.readMore}
32
+ </a>
33
+ {/if}
34
+ </div>
35
+
36
+ <style>@keyframes fadeIn {
37
+ 0% {
38
+ opacity: 1;
39
+ }
40
+ 50% {
41
+ opacity: 0.4;
42
+ }
43
+ 100% {
44
+ opacity: 1;
45
+ }
46
+ }
47
+ .post-viewer-texts {
48
+ color: #ffffff;
49
+ 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);
50
+ padding: var(--_post-viewer-texts--padding);
51
+ display: flex;
52
+ flex-direction: column;
53
+ gap: 0.625rem;
54
+ /* Set 'container-type: inline-size;' to reference container*/
55
+ }
56
+ @container (width < 576px) {
57
+ .post-viewer-texts {
58
+ gap: 0.375rem;
59
+ }
60
+ }
61
+ .post-viewer-texts__kicker {
62
+ font-size: 1rem;
63
+ font-weight: 400;
64
+ /* Set 'container-type: inline-size;' to reference container*/
65
+ }
66
+ @container (width < 576px) {
67
+ .post-viewer-texts__kicker {
68
+ font-size: 0.875rem;
69
+ }
70
+ }
71
+ .post-viewer-texts__title {
72
+ font-size: 1.25rem;
73
+ font-weight: 500;
74
+ /* Set 'container-type: inline-size;' to reference container*/
75
+ }
76
+ @container (width < 576px) {
77
+ .post-viewer-texts__title {
78
+ font-size: 1rem;
79
+ }
80
+ }
81
+ .post-viewer-texts__text {
82
+ font-size: 1.125rem;
83
+ font-weight: 400;
84
+ /* Set 'container-type: inline-size;' to reference container*/
85
+ }
86
+ @container (width < 576px) {
87
+ .post-viewer-texts__text {
88
+ font-size: 0.9375rem;
89
+ }
90
+ }
91
+ .post-viewer-texts__read-more {
92
+ pointer-events: auto;
93
+ font-size: 1rem;
94
+ font-weight: 400;
95
+ /* Set 'container-type: inline-size;' to reference container*/
96
+ }
97
+ @container (width < 576px) {
98
+ .post-viewer-texts__read-more {
99
+ font-size: 0.875rem;
100
+ }
101
+ }</style>
@@ -0,0 +1,11 @@
1
+ import type { PostModel } from '../model/post-model';
2
+ import { PostViewerLocalization } from './post-viewer-localization';
3
+ import { PostViewerUiManager } from './ui-manager.svelte';
4
+ type Props = {
5
+ model: PostModel['texts'];
6
+ uiManager: PostViewerUiManager;
7
+ localization: PostViewerLocalization;
8
+ };
9
+ declare const PostTexts: import("svelte").Component<Props, {}, "">;
10
+ type PostTexts = ReturnType<typeof PostTexts>;
11
+ export default PostTexts;
@@ -1,6 +1,7 @@
1
1
  import { type Locale } from '../../core/locale';
2
2
  export declare class PostViewerLocalization {
3
3
  viewsCount: (count: number) => string;
4
+ readMore: string;
4
5
  locale: Locale;
5
6
  constructor(locale: Locale);
6
7
  }