@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.
- package/dist/content-player/cmp.content-player.svelte +69 -34
- package/dist/content-player/content-player-config.svelte.d.ts +8 -17
- package/dist/content-player/content-player-config.svelte.js +16 -15
- package/dist/content-player/content-player-settings.d.ts +14 -0
- package/dist/content-player/content-player-settings.js +14 -0
- package/dist/content-player/controls-and-attachments.svelte +9 -4
- package/dist/content-player/header.svelte +1 -1
- package/dist/content-player/index.d.ts +1 -1
- package/dist/core/analytics.profile-id.js +27 -1
- package/dist/core/utils/html-helper.d.ts +1 -0
- package/dist/core/utils/html-helper.js +3 -0
- package/dist/media-center/media-center/cmp.media-center.svelte +32 -24
- package/dist/media-center/media-center/discover-panel.svelte +1 -1
- package/dist/posts/attachments/cmp.attachments.svelte +7 -6
- package/dist/posts/attachments/cmp.attachments.svelte.d.ts +2 -2
- package/dist/posts/controls/cmp.controls.svelte +2 -2
- package/dist/posts/controls/cmp.controls.svelte.d.ts +2 -2
- package/dist/posts/index.d.ts +1 -0
- package/dist/posts/model/index.d.ts +3 -1
- package/dist/posts/model/index.js +2 -1
- package/dist/posts/model/post-media-model.svelte.d.ts +20 -0
- package/dist/posts/model/post-media-model.svelte.js +16 -0
- package/dist/posts/model/post-model.d.ts +25 -0
- package/dist/posts/model/post-model.js +28 -0
- package/dist/posts/model/types.d.ts +53 -9
- package/dist/posts/model/types.js +1 -1
- package/dist/posts/model/utils.d.ts +4 -0
- package/dist/posts/model/utils.js +7 -0
- package/dist/posts/post-viewer/attachments-horizontal.svelte +7 -2
- package/dist/posts/post-viewer/attachments-horizontal.svelte.d.ts +2 -2
- package/dist/posts/post-viewer/cmp.post-viewer.svelte +27 -50
- package/dist/posts/post-viewer/cmp.post-viewer.svelte.d.ts +2 -2
- package/dist/posts/post-viewer/heading.svelte +2 -1
- package/dist/posts/post-viewer/heading.svelte.d.ts +2 -2
- package/dist/posts/post-viewer/index.d.ts +1 -3
- package/dist/posts/post-viewer/index.js +1 -2
- package/dist/posts/post-viewer/mapper.d.ts +2 -2
- package/dist/posts/post-viewer/mapper.js +23 -27
- package/dist/posts/post-viewer/media/post-media.svelte +64 -0
- package/dist/posts/post-viewer/{post-media.svelte.d.ts → media/post-media.svelte.d.ts} +4 -6
- package/dist/posts/post-viewer/post-texts.svelte +101 -0
- package/dist/posts/post-viewer/post-texts.svelte.d.ts +11 -0
- package/dist/posts/post-viewer/post-viewer-localization.d.ts +1 -0
- package/dist/posts/post-viewer/post-viewer-localization.js +4 -1
- package/dist/posts/posts-player/index.d.ts +2 -3
- package/dist/posts/posts-player/index.js +0 -1
- package/dist/posts/posts-player/posts-player-view.svelte +3 -2
- package/dist/posts/posts-player/types.d.ts +5 -4
- package/dist/short-videos/short-videos-player/index.d.ts +3 -4
- package/dist/short-videos/short-videos-player/index.js +0 -1
- package/dist/short-videos/short-videos-player/mapper.js +2 -2
- package/dist/short-videos/short-videos-player/short-videos-player-view.svelte +3 -2
- package/dist/short-videos/short-videos-player/types.d.ts +5 -4
- package/dist/streams/layout/element-views/cmp.short-video-stream-element.svelte +4 -3
- package/dist/streams/layout/models/index.d.ts +1 -1
- package/dist/streams/layout/models/index.js +1 -1
- package/dist/streams/layout/models/mapper.d.ts +2 -2
- package/dist/streams/layout/models/mapper.js +10 -9
- package/dist/streams/stream-player/index.d.ts +3 -4
- package/dist/streams/stream-player/stream-player-view.svelte +4 -3
- package/dist/streams/stream-player/types.d.ts +3 -2
- package/dist/ui/line-clamp/cmp.line-clamp.svelte +1 -0
- package/dist/ui/player-slider/cmp.player-slider.svelte +44 -7
- package/dist/ui/player-slider/cmp.player-slider.svelte.d.ts +2 -2
- package/dist/ui/player-slider/player-buffer.svelte.d.ts +4 -3
- package/dist/ui/player-slider/player-buffer.svelte.js +9 -3
- package/dist/ui/player-slider/types.d.ts +5 -2
- package/dist/ui/slider/cmp.slider.svelte +398 -0
- package/dist/ui/slider/cmp.slider.svelte.d.ts +31 -0
- package/dist/ui/slider/index.d.ts +2 -0
- package/dist/ui/slider/index.js +2 -0
- package/dist/ui/slider/slider-localization.d.ts +5 -0
- package/dist/ui/slider/slider-localization.js +13 -0
- package/dist/ui/slider/types.d.ts +11 -0
- package/dist/ui/slider/types.js +8 -0
- package/package.json +2 -2
- package/dist/posts/post-viewer/media/media-slider.svelte +0 -10
- package/dist/posts/post-viewer/media/media-slider.svelte.d.ts +0 -27
- package/dist/posts/post-viewer/post-media.svelte +0 -26
- package/dist/posts/post-viewer/types.d.ts +0 -60
- package/dist/posts/post-viewer/types.js +0 -1
- package/dist/posts/post-viewer/utils.d.ts +0 -2
- package/dist/posts/post-viewer/utils.js +0 -13
|
@@ -18,7 +18,7 @@ import { default as Header } from './header.svelte';
|
|
|
18
18
|
import { default as OverviewPanel } from './overview-panel.svelte';
|
|
19
19
|
import { onMount, untrack } from 'svelte';
|
|
20
20
|
let { config, nonPostItemView, overviewPanelContent } = $props();
|
|
21
|
-
const localization = new ContentPlayerLocalization(config.locale);
|
|
21
|
+
const localization = new ContentPlayerLocalization(config.settings.locale);
|
|
22
22
|
let everTouched = $state(false);
|
|
23
23
|
const uiManager = config.uiManager;
|
|
24
24
|
onMount(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -48,6 +48,13 @@ const handleContentPlayerMounted = (node) => {
|
|
|
48
48
|
node.addEventListener('wheel', markAsTouched);
|
|
49
49
|
node.addEventListener('click', markAsTouched);
|
|
50
50
|
node.addEventListener('keypress', markAsTouched);
|
|
51
|
+
return {
|
|
52
|
+
destroy: () => {
|
|
53
|
+
removeListeners();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const handleSliderMounted = (node) => {
|
|
51
58
|
let resizeObserver = new ResizeObserver(() => {
|
|
52
59
|
const { width: playerWidth, height: playerHeight } = node.getBoundingClientRect();
|
|
53
60
|
uiManager.playerTotalWidth = playerWidth;
|
|
@@ -95,7 +102,6 @@ const handleContentPlayerMounted = (node) => {
|
|
|
95
102
|
resizeObserver.observe(node);
|
|
96
103
|
return {
|
|
97
104
|
destroy: () => {
|
|
98
|
-
removeListeners();
|
|
99
105
|
resizeObserver.disconnect();
|
|
100
106
|
}
|
|
101
107
|
};
|
|
@@ -115,15 +121,31 @@ const variables = $derived.by(() => {
|
|
|
115
121
|
|
|
116
122
|
<svelte:document
|
|
117
123
|
onkeydown={(e) => {
|
|
118
|
-
if (config.enableCloseButton) {
|
|
124
|
+
if (config.settings.enableCloseButton) {
|
|
119
125
|
handleEsc(e, () => config.callbacks?.close?.());
|
|
120
126
|
}
|
|
121
127
|
}} />
|
|
122
128
|
|
|
129
|
+
<svelte:head>
|
|
130
|
+
<meta name="theme-color" content="#242424" />
|
|
131
|
+
<meta name="color-scheme" content="dark" />
|
|
132
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
133
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
134
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
|
135
|
+
|
|
136
|
+
<style>
|
|
137
|
+
html,
|
|
138
|
+
body {
|
|
139
|
+
background-color: #242424;
|
|
140
|
+
color-scheme: dark;
|
|
141
|
+
}
|
|
142
|
+
</style>
|
|
143
|
+
</svelte:head>
|
|
144
|
+
|
|
123
145
|
<div
|
|
124
146
|
class="content-player-container"
|
|
125
|
-
class:content-player-container--background-enabled={!config.disableBackground}
|
|
126
|
-
class:content-player-container--background-loading={!config.disableBackground && !uiManager.backgroundImageUrl}
|
|
147
|
+
class:content-player-container--background-enabled={!config.settings.disableBackground}
|
|
148
|
+
class:content-player-container--background-loading={!config.settings.disableBackground && !uiManager.backgroundImageUrl}
|
|
127
149
|
class:content-player-container--faded={config.fadeContent}
|
|
128
150
|
style={variables}>
|
|
129
151
|
<Header config={config} overviewPanelContent={overviewPanelContent} localization={localization} />
|
|
@@ -133,7 +155,7 @@ const variables = $derived.by(() => {
|
|
|
133
155
|
</OverviewPanel>
|
|
134
156
|
{/if}
|
|
135
157
|
<div class="content-player" use:handleContentPlayerMounted>
|
|
136
|
-
{#if config.showStreamsCloudWatermark}
|
|
158
|
+
{#if config.settings.showStreamsCloudWatermark}
|
|
137
159
|
<div class="content-player__watermark">
|
|
138
160
|
<a href="https://streamscloud.com/" tabindex="-1" aria-label="none">
|
|
139
161
|
<img src="https://embedabble-assets.streamscloud-cdn.com/watermark.svg" alt="StreamsCloud" />
|
|
@@ -141,35 +163,37 @@ const variables = $derived.by(() => {
|
|
|
141
163
|
</div>
|
|
142
164
|
{/if}
|
|
143
165
|
{#if config.playerBuffer}
|
|
144
|
-
<
|
|
145
|
-
{
|
|
146
|
-
{
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
{
|
|
165
|
-
|
|
166
|
+
<div class="content-player__slider" use:handleSliderMounted>
|
|
167
|
+
<PlayerSlider buffer={config.playerBuffer} on={config.playerSliderCallbacks}>
|
|
168
|
+
{#snippet children({ item })}
|
|
169
|
+
{@const postModel = config.itemAsPostViewerModel(item)}
|
|
170
|
+
<div class="content-player__content">
|
|
171
|
+
{#if postModel}
|
|
172
|
+
<PostViewer
|
|
173
|
+
model={postModel}
|
|
174
|
+
socialInteractionsHandler={config.socialInteractionsHandler}
|
|
175
|
+
enableAttachments={config.uiManager.showPostOverlayAttachments}
|
|
176
|
+
enableControls={config.uiManager.showPostOverlayControls}
|
|
177
|
+
autoplay="on-appearance"
|
|
178
|
+
locale={config.settings.locale}
|
|
179
|
+
on={{
|
|
180
|
+
progress: (progress) => config.callbacks?.videoProgress?.(item.id, postModel.id, progress),
|
|
181
|
+
productClick: (productId) => config.callbacks?.productClick?.(productId, postModel.id),
|
|
182
|
+
productImpression: (productId) => config.callbacks?.productImpression?.(productId, postModel.id),
|
|
183
|
+
adClick: (adId) => config.callbacks?.adClick?.(adId, postModel.id),
|
|
184
|
+
adImpression: (adId) => config.callbacks?.adImpression?.(adId, postModel.id)
|
|
185
|
+
}} />
|
|
186
|
+
{:else if nonPostItemView}
|
|
187
|
+
{@render nonPostItemView({ item })}
|
|
188
|
+
{/if}
|
|
166
189
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
190
|
+
{#if uiManager.isMobileView && config.playerBuffer && config.playerBuffer.loaded.length > 1 && !everTouched}
|
|
191
|
+
<SwipeIndicator locale={config.settings.locale} />
|
|
192
|
+
{/if}
|
|
193
|
+
</div>
|
|
194
|
+
{/snippet}
|
|
195
|
+
</PlayerSlider>
|
|
196
|
+
</div>
|
|
173
197
|
<ControlsAndAttachments config={config} />
|
|
174
198
|
{:else}
|
|
175
199
|
<Loading positionFixedCenter={true} timeout={1000} />
|
|
@@ -226,6 +250,14 @@ const variables = $derived.by(() => {
|
|
|
226
250
|
padding: 0;
|
|
227
251
|
}
|
|
228
252
|
}
|
|
253
|
+
.content-player__slider {
|
|
254
|
+
width: 100%;
|
|
255
|
+
min-width: 100%;
|
|
256
|
+
max-width: 100%;
|
|
257
|
+
height: 100%;
|
|
258
|
+
min-height: 100%;
|
|
259
|
+
max-height: 100%;
|
|
260
|
+
}
|
|
229
261
|
.content-player__watermark {
|
|
230
262
|
position: absolute;
|
|
231
263
|
bottom: 5rem;
|
|
@@ -240,4 +272,7 @@ const variables = $derived.by(() => {
|
|
|
240
272
|
position: relative;
|
|
241
273
|
opacity: var(--content-player--elements-opacity);
|
|
242
274
|
transition: opacity 0.3s ease-in-out;
|
|
275
|
+
display: flex;
|
|
276
|
+
justify-content: center;
|
|
277
|
+
align-items: center;
|
|
243
278
|
}</style>
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
import type { Locale } from '../core/locale';
|
|
2
1
|
import type { MediaCenterData } from '../media-center/model/types';
|
|
3
|
-
import type
|
|
2
|
+
import { type IPostModel, PostModel } from '../posts/model';
|
|
4
3
|
import type { IPostSocialInteractionsHandler } from '../posts/social-interactions';
|
|
5
4
|
import type { IPlayerBuffer } from '../ui/player-slider';
|
|
6
5
|
import type { PlayerSliderCallbacks } from '../ui/player-slider/types';
|
|
6
|
+
import { ContentPlayerSettings } from './content-player-settings';
|
|
7
7
|
import { ContentPlayerUIManager } from './ui-manager.svelte';
|
|
8
8
|
export declare class ContentPlayerConfig<T extends {
|
|
9
9
|
id: string;
|
|
10
10
|
}> {
|
|
11
11
|
playerBuffer: IPlayerBuffer<T> | null;
|
|
12
|
-
readonly
|
|
13
|
-
readonly disableBackground: boolean;
|
|
14
|
-
readonly enableCloseButton: boolean;
|
|
15
|
-
readonly showStreamsCloudWatermark: boolean;
|
|
12
|
+
readonly settings: ContentPlayerSettings;
|
|
16
13
|
readonly callbacks: ContentPlayerCallbacks | null;
|
|
17
14
|
readonly playerSliderCallbacks: PlayerSliderCallbacks<T> | undefined;
|
|
18
15
|
readonly socialInteractionsHandler: IPostSocialInteractionsHandler | undefined;
|
|
19
16
|
readonly uiManager: ContentPlayerUIManager;
|
|
20
17
|
private _mediaCenterData;
|
|
21
|
-
private _initialMediaIndex;
|
|
22
18
|
private _mappers;
|
|
19
|
+
private mappedPostsCache;
|
|
23
20
|
constructor(init: {
|
|
24
21
|
playerBuffer: IPlayerBuffer<T> | null;
|
|
25
22
|
mappers: ContentPlayerMappers<T>;
|
|
@@ -33,20 +30,14 @@ export declare class ContentPlayerConfig<T extends {
|
|
|
33
30
|
get mediaCenterCallbacks(): MediaCenterData['callbacks'] | null;
|
|
34
31
|
get playerLogo(): string | null;
|
|
35
32
|
get fadeContent(): boolean;
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
itemAsPostViewerModel: (item: T & {
|
|
34
|
+
mediaIndex?: number;
|
|
35
|
+
}) => PostModel | null;
|
|
38
36
|
setBackgroundImageUrl: (imageUrl: string | null) => void;
|
|
39
37
|
updateMediaCenterData: (data: MediaCenterData | undefined) => void;
|
|
40
38
|
}
|
|
41
|
-
export type ContentPlayerSettings = {
|
|
42
|
-
disableBackground?: boolean;
|
|
43
|
-
hideCloseButton?: boolean;
|
|
44
|
-
locale?: Locale;
|
|
45
|
-
showStreamsCloudWatermark?: boolean;
|
|
46
|
-
initialMediaIndex?: number;
|
|
47
|
-
};
|
|
48
39
|
export type ContentPlayerMappers<T> = {
|
|
49
|
-
postModelFromCurrentItem: (item: T) =>
|
|
40
|
+
postModelFromCurrentItem: (item: T) => IPostModel | null;
|
|
50
41
|
};
|
|
51
42
|
export type ContentPlayerCallbacks = {
|
|
52
43
|
close?: () => void;
|
|
@@ -1,24 +1,20 @@
|
|
|
1
|
+
import { PostModel } from '../posts/model';
|
|
2
|
+
import { ContentPlayerSettings } from './content-player-settings';
|
|
1
3
|
import { ContentPlayerUIManager } from './ui-manager.svelte';
|
|
2
4
|
export class ContentPlayerConfig {
|
|
3
5
|
playerBuffer = $state.raw(null);
|
|
4
|
-
|
|
5
|
-
disableBackground;
|
|
6
|
-
enableCloseButton;
|
|
7
|
-
showStreamsCloudWatermark;
|
|
6
|
+
settings;
|
|
8
7
|
callbacks;
|
|
9
8
|
playerSliderCallbacks;
|
|
10
9
|
socialInteractionsHandler;
|
|
11
10
|
uiManager = new ContentPlayerUIManager();
|
|
12
11
|
_mediaCenterData = $state.raw(null);
|
|
13
|
-
_initialMediaIndex = 0;
|
|
14
12
|
_mappers;
|
|
13
|
+
mappedPostsCache = new Map();
|
|
15
14
|
constructor(init) {
|
|
16
15
|
const { playerBuffer, mappers, socialInteractionsHandler, mediaCenterData, settings, callbacks, playerSliderCallbacks } = init;
|
|
17
16
|
this.playerBuffer = playerBuffer;
|
|
18
|
-
this.
|
|
19
|
-
this.disableBackground = settings?.disableBackground ?? false;
|
|
20
|
-
this.showStreamsCloudWatermark = settings?.showStreamsCloudWatermark ?? false;
|
|
21
|
-
this.enableCloseButton = !settings?.hideCloseButton;
|
|
17
|
+
this.settings = settings || new ContentPlayerSettings();
|
|
22
18
|
this._mediaCenterData = mediaCenterData || null;
|
|
23
19
|
this.callbacks = callbacks || null;
|
|
24
20
|
this.playerSliderCallbacks = playerSliderCallbacks;
|
|
@@ -37,13 +33,18 @@ export class ContentPlayerConfig {
|
|
|
37
33
|
get fadeContent() {
|
|
38
34
|
return this._mediaCenterData?.overlayIsActive || false;
|
|
39
35
|
}
|
|
40
|
-
get initialMediaIndex() {
|
|
41
|
-
const index = this._initialMediaIndex;
|
|
42
|
-
this._initialMediaIndex = 0;
|
|
43
|
-
return index;
|
|
44
|
-
}
|
|
45
36
|
itemAsPostViewerModel = (item) => {
|
|
46
|
-
|
|
37
|
+
if (this.mappedPostsCache.has(item.id)) {
|
|
38
|
+
return this.mappedPostsCache.get(item.id) || null;
|
|
39
|
+
}
|
|
40
|
+
const post = this._mappers.postModelFromCurrentItem(item);
|
|
41
|
+
if (!post) {
|
|
42
|
+
this.mappedPostsCache.set(item.id, null);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const postModel = new PostModel(post);
|
|
46
|
+
this.mappedPostsCache.set(item.id, postModel);
|
|
47
|
+
return postModel;
|
|
47
48
|
};
|
|
48
49
|
setBackgroundImageUrl = (imageUrl) => {
|
|
49
50
|
this.uiManager.backgroundImageUrl = imageUrl;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Locale } from '../core/locale';
|
|
2
|
+
export declare class ContentPlayerSettings {
|
|
3
|
+
disableBackground: boolean;
|
|
4
|
+
enableCloseButton: boolean;
|
|
5
|
+
locale: Locale;
|
|
6
|
+
showStreamsCloudWatermark: boolean;
|
|
7
|
+
constructor(init?: IContentPlayerSettingsInitializer);
|
|
8
|
+
}
|
|
9
|
+
export interface IContentPlayerSettingsInitializer {
|
|
10
|
+
disableBackground?: boolean;
|
|
11
|
+
hideCloseButton?: boolean;
|
|
12
|
+
locale?: Locale;
|
|
13
|
+
showStreamsCloudWatermark?: boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export class ContentPlayerSettings {
|
|
2
|
+
disableBackground = false;
|
|
3
|
+
enableCloseButton = true;
|
|
4
|
+
locale = 'en';
|
|
5
|
+
showStreamsCloudWatermark = false;
|
|
6
|
+
constructor(init) {
|
|
7
|
+
if (init) {
|
|
8
|
+
this.disableBackground = init.disableBackground ?? this.disableBackground;
|
|
9
|
+
this.enableCloseButton = init.hideCloseButton !== undefined ? !init.hideCloseButton : this.enableCloseButton;
|
|
10
|
+
this.locale = init.locale ?? this.locale;
|
|
11
|
+
this.showStreamsCloudWatermark = init.showStreamsCloudWatermark ?? this.showStreamsCloudWatermark;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -52,7 +52,9 @@ const variables = $derived.by(() => {
|
|
|
52
52
|
on={{ attachmentsClicked: changeShowAttachments }} />
|
|
53
53
|
{/if}
|
|
54
54
|
{#if config.playerBuffer}
|
|
55
|
-
<div
|
|
55
|
+
<div
|
|
56
|
+
class="controls-and-attachments__navigation-buttons"
|
|
57
|
+
class:controls-and-attachments__navigation-buttons--invisible={config.playerBuffer.loaded.length <= 1}>
|
|
56
58
|
<PlayerButton
|
|
57
59
|
icon={IconChevronUp}
|
|
58
60
|
disabled={!config.playerBuffer.canLoadPrevious}
|
|
@@ -69,11 +71,11 @@ const variables = $derived.by(() => {
|
|
|
69
71
|
<img src={config.playerLogo} class="controls-and-attachments__logo-img" alt="Player Logo" />
|
|
70
72
|
</div>
|
|
71
73
|
{/if}
|
|
72
|
-
{#if currentItemPostContainer && !attachmentsCollapsed &&
|
|
74
|
+
{#if currentItemPostContainer && !attachmentsCollapsed && currentItemPostContainer.attachments}
|
|
73
75
|
<div class="controls-and-attachments__post-attachments" transition:slideHorizontally|local>
|
|
74
76
|
<PostAttachments
|
|
75
|
-
|
|
76
|
-
locale={config.locale}
|
|
77
|
+
model={currentItemPostContainer}
|
|
78
|
+
locale={config.settings.locale}
|
|
77
79
|
on={{
|
|
78
80
|
productClick: (id) => config.callbacks?.productClick?.(id, currentItemPostContainer.id),
|
|
79
81
|
productImpression: (id) => config.callbacks?.productImpression?.(id, currentItemPostContainer.id),
|
|
@@ -186,4 +188,7 @@ const variables = $derived.by(() => {
|
|
|
186
188
|
flex-direction: column;
|
|
187
189
|
gap: 1rem;
|
|
188
190
|
z-index: 1;
|
|
191
|
+
}
|
|
192
|
+
.controls-and-attachments__navigation-buttons--invisible {
|
|
193
|
+
visibility: hidden;
|
|
189
194
|
}</style>
|
|
@@ -78,7 +78,7 @@ const buttonVariables = $derived.by(() => {
|
|
|
78
78
|
</div>
|
|
79
79
|
{/if}
|
|
80
80
|
|
|
81
|
-
{#if config.enableCloseButton && config.callbacks?.close}
|
|
81
|
+
{#if config.settings.enableCloseButton && config.callbacks?.close}
|
|
82
82
|
<div class="close-button" style={buttonVariables}>
|
|
83
83
|
<PlayerButton icon={IconDismiss} on={{ click: config.callbacks.close }} />
|
|
84
84
|
</div>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default as ContentPlayer } from './cmp.content-player.svelte';
|
|
2
|
-
export { ContentPlayerConfig
|
|
2
|
+
export { ContentPlayerConfig } from './content-player-config.svelte';
|
|
@@ -9,9 +9,35 @@ const PROFILE_ID_STORAGE_KEY = 'streamscloud_profile_id';
|
|
|
9
9
|
export const getOrCreateProfileId = () => {
|
|
10
10
|
const storedProfileId = localStorage.getItem(PROFILE_ID_STORAGE_KEY);
|
|
11
11
|
if (!storedProfileId) {
|
|
12
|
-
const newProfileId =
|
|
12
|
+
const newProfileId = safeRandomUUID();
|
|
13
13
|
localStorage.setItem(PROFILE_ID_STORAGE_KEY, newProfileId);
|
|
14
14
|
return newProfileId;
|
|
15
15
|
}
|
|
16
16
|
return storedProfileId;
|
|
17
17
|
};
|
|
18
|
+
function safeRandomUUID() {
|
|
19
|
+
// 1) Native support
|
|
20
|
+
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
|
21
|
+
try {
|
|
22
|
+
return crypto.randomUUID();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// continue to fallbacks
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// 2) Use crypto.getRandomValues to build UUID v4
|
|
29
|
+
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
|
|
30
|
+
const bytes = new Uint8Array(16);
|
|
31
|
+
crypto.getRandomValues(bytes);
|
|
32
|
+
// Per RFC 4122 v4
|
|
33
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
|
|
34
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 10
|
|
35
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));
|
|
36
|
+
return [hex.slice(0, 4).join(''), hex.slice(4, 6).join(''), hex.slice(6, 8).join(''), hex.slice(8, 10).join(''), hex.slice(10, 16).join('')].join('-');
|
|
37
|
+
}
|
|
38
|
+
// 3) Non-crypto fallback (not suitable for security-sensitive IDs)
|
|
39
|
+
// Good enough for element keys or local-only IDs
|
|
40
|
+
const time = Date.now().toString(16);
|
|
41
|
+
const rnd = Math.random().toString(16).slice(2);
|
|
42
|
+
return `${time.slice(-8)}-${rnd.slice(0, 4)}-4${rnd.slice(4, 7)}-8${rnd.slice(7, 10)}-${rnd.slice(10, 22)}`;
|
|
43
|
+
}
|
|
@@ -36,6 +36,7 @@ export declare class HtmlHelper {
|
|
|
36
36
|
* DomHelper.insert(siblingElement, newContentField, false);
|
|
37
37
|
*/
|
|
38
38
|
static insert(newElement: Element, siblingElement: Element, insertBefore?: boolean): void;
|
|
39
|
+
static sanitizeHtml(html: string): string;
|
|
39
40
|
static sanitizeSvg(svg: string): string;
|
|
40
41
|
static pasteIntoInput(value: string, element: HTMLInputElement | HTMLTextAreaElement): void;
|
|
41
42
|
}
|
|
@@ -71,6 +71,9 @@ export class HtmlHelper {
|
|
|
71
71
|
HtmlHelper.insertAfter(newElement, siblingElement);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
static sanitizeHtml(html) {
|
|
75
|
+
return dp.sanitize(html);
|
|
76
|
+
}
|
|
74
77
|
static sanitizeSvg(svg) {
|
|
75
78
|
return dp.sanitize(svg, { USE_PROFILES: { svg: true, svgFilters: true }, ADD_ATTR: ['dominant-baseline'] });
|
|
76
79
|
}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
var _a;
|
|
11
10
|
import { horizontalWheelScroll } from '../../core/actions';
|
|
12
11
|
import { Utils } from '../../core/utils';
|
|
13
12
|
import { default as ShortVideosPlayerView } from '../../short-videos/short-videos-player/short-videos-player-view.svelte';
|
|
@@ -29,14 +28,9 @@ import IconScreenSearch from '@fluentui/svg-icons/icons/screen_search_20_regular
|
|
|
29
28
|
import { fade } from 'svelte/transition';
|
|
30
29
|
let { config, playerProps, locale = 'en' } = $props();
|
|
31
30
|
const localization = $derived(new MediaCenterLocalization(locale));
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
initialMediaIndex = 0; // reset after first use
|
|
36
|
-
return {
|
|
37
|
-
playerSettings: playerProps.props.playerSettings ? Object.assign(Object.assign({}, playerProps.props.playerSettings), { initialMediaIndex: mediaIndex }) : undefined,
|
|
38
|
-
on: playerProps.props.on
|
|
39
|
-
};
|
|
31
|
+
const commonPlayerSettings = {
|
|
32
|
+
playerSettings: playerProps.props.playerSettings,
|
|
33
|
+
on: playerProps.props.on
|
|
40
34
|
};
|
|
41
35
|
const handler = new MediaCenterHandler(config);
|
|
42
36
|
const discoverHandler = new DiscoverPanelHandler(config);
|
|
@@ -64,7 +58,7 @@ const selectCategory = (categoryId) => __awaiter(void 0, void 0, void 0, functio
|
|
|
64
58
|
handler.selectedCategoryId = categoryId;
|
|
65
59
|
computedPlayerProps = {
|
|
66
60
|
mode: 'short-videos',
|
|
67
|
-
props: Object.assign({ dataProvider: makeShortVideosProvider({ config, categoryId }), socialInteractionsHandler: (_a = config.handlers) === null || _a === void 0 ? void 0 : _a.socialInteractionsHandler, analyticsHandler: (_b = config.handlers) === null || _b === void 0 ? void 0 : _b.analyticsHandler }, commonPlayerSettings
|
|
61
|
+
props: Object.assign({ dataProvider: makeShortVideosProvider({ config, categoryId }), socialInteractionsHandler: (_a = config.handlers) === null || _a === void 0 ? void 0 : _a.socialInteractionsHandler, analyticsHandler: (_b = config.handlers) === null || _b === void 0 ? void 0 : _b.analyticsHandler }, commonPlayerSettings)
|
|
68
62
|
};
|
|
69
63
|
discoverHandler.deactivate();
|
|
70
64
|
break;
|
|
@@ -91,7 +85,7 @@ const activateSelectedShortVideoPlayer = (shortVideo) => {
|
|
|
91
85
|
mediaCenterMode = 'short-videos';
|
|
92
86
|
computedPlayerProps = {
|
|
93
87
|
mode: 'short-videos',
|
|
94
|
-
props: Object.assign({ dataProvider: makeShortVideosProvider({ config, prefetchedItems: [shortVideo] }), socialInteractionsHandler: (_a = config.handlers) === null || _a === void 0 ? void 0 : _a.socialInteractionsHandler, analyticsHandler: (_b = config.handlers) === null || _b === void 0 ? void 0 : _b.analyticsHandler }, commonPlayerSettings
|
|
88
|
+
props: Object.assign({ dataProvider: makeShortVideosProvider({ config, prefetchedItems: [shortVideo] }), socialInteractionsHandler: (_a = config.handlers) === null || _a === void 0 ? void 0 : _a.socialInteractionsHandler, analyticsHandler: (_b = config.handlers) === null || _b === void 0 ? void 0 : _b.analyticsHandler }, commonPlayerSettings)
|
|
95
89
|
};
|
|
96
90
|
handler.selectedCategoryId = null;
|
|
97
91
|
discoverHandler.deactivate();
|
|
@@ -105,7 +99,7 @@ const activateSelectedStreamPlayer = (id) => {
|
|
|
105
99
|
mediaCenterMode = 'stream';
|
|
106
100
|
computedPlayerProps = {
|
|
107
101
|
mode: 'stream',
|
|
108
|
-
props: Object.assign({ streamId: id, dataProvider: config.streamPlayer.streamPlayerDataProvider, analyticsHandler: (_a = config.handlers) === null || _a === void 0 ? void 0 : _a.analyticsHandler, postSocialInteractionsHandler: (_b = config.handlers) === null || _b === void 0 ? void 0 : _b.socialInteractionsHandler }, commonPlayerSettings
|
|
102
|
+
props: Object.assign({ streamId: id, dataProvider: config.streamPlayer.streamPlayerDataProvider, analyticsHandler: (_a = config.handlers) === null || _a === void 0 ? void 0 : _a.analyticsHandler, postSocialInteractionsHandler: (_b = config.handlers) === null || _b === void 0 ? void 0 : _b.socialInteractionsHandler }, commonPlayerSettings)
|
|
109
103
|
};
|
|
110
104
|
handler.selectedCategoryId = null;
|
|
111
105
|
discoverHandler.deactivate();
|
|
@@ -181,7 +175,12 @@ const onWidthAnchorMounted = (node) => {
|
|
|
181
175
|
class="media-center-controls-panel__button"
|
|
182
176
|
class:media-center-controls-panel__button--active={discoverHandler.activated}
|
|
183
177
|
onclick={toggleDiscover}>
|
|
184
|
-
<
|
|
178
|
+
<span class="media-center-controls-panel__button-icon">
|
|
179
|
+
<Icon src={IconScreenSearch} />
|
|
180
|
+
</span>
|
|
181
|
+
<span class="media-center-controls-panel__button-value">
|
|
182
|
+
{localization.discoverButton}
|
|
183
|
+
</span>
|
|
185
184
|
</button>
|
|
186
185
|
<div class="media-center-controls-panel__scroll-area" use:onScrollMounted use:horizontalWheelScroll onscroll={handleScrollingAreaScroll}>
|
|
187
186
|
{#each handler.categories as category (category.id)}
|
|
@@ -194,7 +193,11 @@ const onWidthAnchorMounted = (node) => {
|
|
|
194
193
|
handler.controlsPanelSelectedCategory?.childName) ||
|
|
195
194
|
undefined}
|
|
196
195
|
title={category.name}
|
|
197
|
-
onclick={() => selectCategory(category.id)}>
|
|
196
|
+
onclick={() => selectCategory(category.id)}>
|
|
197
|
+
<span class="media-center-controls-panel__button-value">
|
|
198
|
+
{category.name}
|
|
199
|
+
</span>
|
|
200
|
+
</button>
|
|
198
201
|
{/each}
|
|
199
202
|
</div>
|
|
200
203
|
</div>
|
|
@@ -310,21 +313,14 @@ const onWidthAnchorMounted = (node) => {
|
|
|
310
313
|
.media-center-controls-panel__button {
|
|
311
314
|
position: relative;
|
|
312
315
|
pointer-events: auto;
|
|
313
|
-
font-size: 0.875rem;
|
|
314
|
-
line-height: 1.0625rem;
|
|
315
316
|
padding: 0.5rem 1.5rem;
|
|
316
|
-
white-space: nowrap;
|
|
317
|
-
width: auto;
|
|
318
|
-
max-width: none;
|
|
319
|
-
min-width: 0;
|
|
320
|
-
scroll-snap-align: start;
|
|
321
|
-
flex: 0 0 auto;
|
|
322
317
|
display: flex;
|
|
323
318
|
gap: 0.375rem;
|
|
324
319
|
justify-content: center;
|
|
325
320
|
align-items: center;
|
|
326
|
-
|
|
327
|
-
|
|
321
|
+
max-width: 12.5rem;
|
|
322
|
+
width: auto;
|
|
323
|
+
min-width: 0;
|
|
328
324
|
border-radius: 0.875rem;
|
|
329
325
|
background-color: rgba(0, 0, 0, 0.6);
|
|
330
326
|
color: #f2f2f2;
|
|
@@ -361,6 +357,18 @@ const onWidthAnchorMounted = (node) => {
|
|
|
361
357
|
color: #ffffff;
|
|
362
358
|
pointer-events: none;
|
|
363
359
|
}
|
|
360
|
+
.media-center-controls-panel__button-icon {
|
|
361
|
+
--icon--color: #ffffff;
|
|
362
|
+
--icon--size: 1.0625rem;
|
|
363
|
+
}
|
|
364
|
+
.media-center-controls-panel__button-value {
|
|
365
|
+
font-size: 0.875rem;
|
|
366
|
+
line-height: 1.0625rem;
|
|
367
|
+
text-overflow: ellipsis;
|
|
368
|
+
width: 100%;
|
|
369
|
+
white-space: nowrap;
|
|
370
|
+
overflow: hidden;
|
|
371
|
+
}
|
|
364
372
|
|
|
365
373
|
.media-center-overlay {
|
|
366
374
|
position: absolute;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts">import { getPostCoverImage } from '../../posts/
|
|
1
|
+
<script lang="ts">import { getPostCoverImage } from '../../posts/model';
|
|
2
2
|
import { ProductCard } from '../../products/product-card';
|
|
3
3
|
import { ShortVideoCard } from '../../short-videos/short-video-card';
|
|
4
4
|
import { StreamCard } from '../../streams/stream-card';
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script lang="ts">import { AdCard } from '../../ads/ad-card';
|
|
2
|
+
import { PostModel } from '../model';
|
|
2
3
|
import { ProductCard } from '../../products/product-card';
|
|
3
|
-
let {
|
|
4
|
+
let { model, locale = 'en', on } = $props();
|
|
4
5
|
</script>
|
|
5
6
|
|
|
6
|
-
{#if
|
|
7
|
+
{#if model.attachments}
|
|
7
8
|
<div class="post-attachments">
|
|
8
|
-
{#if
|
|
9
|
-
{#each
|
|
9
|
+
{#if model.attachments.ads.length}
|
|
10
|
+
{#each model.attachments.ads as ad (ad.id)}
|
|
10
11
|
<AdCard
|
|
11
12
|
ad={ad}
|
|
12
13
|
on={{
|
|
@@ -16,8 +17,8 @@ let { container, locale = 'en', on } = $props();
|
|
|
16
17
|
{/each}
|
|
17
18
|
{/if}
|
|
18
19
|
|
|
19
|
-
{#if
|
|
20
|
-
{#each
|
|
20
|
+
{#if model.attachments.products.length}
|
|
21
|
+
{#each model.attachments.products as product (product.id)}
|
|
21
22
|
<ProductCard
|
|
22
23
|
product={product}
|
|
23
24
|
locale={locale}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Locale } from '../../core/locale';
|
|
2
|
-
import
|
|
2
|
+
import { PostModel } from '../model';
|
|
3
3
|
type Props = {
|
|
4
|
-
|
|
4
|
+
model: PostModel;
|
|
5
5
|
locale?: Locale;
|
|
6
6
|
on?: {
|
|
7
7
|
productClick?: (productId: string) => void;
|
|
@@ -25,7 +25,7 @@ let isLikedStore = $state.raw({
|
|
|
25
25
|
});
|
|
26
26
|
const actions = $derived.by(() => {
|
|
27
27
|
const result = [];
|
|
28
|
-
if (model.
|
|
28
|
+
if (model.attachments) {
|
|
29
29
|
result.push({ icon: IconShoppingBag, callback: onAttachmentsClicked });
|
|
30
30
|
}
|
|
31
31
|
if (showSocialInteractions) {
|
|
@@ -36,7 +36,7 @@ const actions = $derived.by(() => {
|
|
|
36
36
|
});
|
|
37
37
|
result.push({ icon: IconShare, callback: onShareClicked });
|
|
38
38
|
}
|
|
39
|
-
if (model.media && model.media.
|
|
39
|
+
if (model.media && !model.media.currentItem.isImage) {
|
|
40
40
|
result.push({ icon: MediaVolumeManager.isMuted ? IconSpeakerMute : IconSpeaker2, callback: onMuteClicked });
|
|
41
41
|
}
|
|
42
42
|
return result;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PostModel } from '../model';
|
|
2
2
|
import type { IPostSocialInteractionsHandler } from '../social-interactions';
|
|
3
3
|
type Props = {
|
|
4
|
-
model:
|
|
4
|
+
model: PostModel;
|
|
5
5
|
socialInteractionsHandler?: IPostSocialInteractionsHandler;
|
|
6
6
|
on?: {
|
|
7
7
|
attachmentsClicked?: () => void;
|
package/dist/posts/index.d.ts
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type { IPostModel, IPostProductCardModel, IPostHeadingModel, IPostAdCardModel, IPostMediaItemModel, PostModelMediaFit } from './types';
|
|
2
|
+
export { PostModel } from './post-model';
|
|
3
|
+
export { getPostCoverImage } from './utils';
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {};
|
|
1
|
+
export { PostModel } from './post-model';
|
|
2
|
+
export { getPostCoverImage } from './utils';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IPostMediaItemModel, PostModelMediaFit } from './types';
|
|
2
|
+
export declare class PostViewerMediaModel {
|
|
3
|
+
readonly currentItem: {
|
|
4
|
+
isImage: false;
|
|
5
|
+
url: string;
|
|
6
|
+
thumbnailUrl: string;
|
|
7
|
+
} | {
|
|
8
|
+
isImage: boolean;
|
|
9
|
+
url: string;
|
|
10
|
+
};
|
|
11
|
+
currentIndex: number;
|
|
12
|
+
readonly isGallery: boolean;
|
|
13
|
+
items: IPostMediaItemModel[];
|
|
14
|
+
mediaFit: PostModelMediaFit;
|
|
15
|
+
constructor(init: {
|
|
16
|
+
media: IPostMediaItemModel[];
|
|
17
|
+
mediaFit: PostModelMediaFit;
|
|
18
|
+
mediaIndex?: number;
|
|
19
|
+
});
|
|
20
|
+
}
|