@streamscloud/embeddable 16.0.7-1772107327250 → 16.0.7-1772186925109
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/articles/article/article-proxy.svelte.d.ts +1 -1
- package/dist/articles/article/cmp.article.svelte +1 -1
- package/dist/articles/article/index.d.ts +1 -1
- package/dist/articles/article/types.d.ts +5 -0
- package/dist/articles/article-dialog/article-dialog-localization.d.ts +3 -0
- package/dist/articles/article-dialog/article-dialog-localization.js +9 -0
- package/dist/articles/article-dialog/cmp.article-dialog.svelte +98 -0
- package/dist/articles/article-dialog/cmp.article-dialog.svelte.d.ts +9 -0
- package/dist/articles/article-dialog/index.d.ts +6 -0
- package/dist/articles/article-dialog/index.js +10 -0
- package/dist/articles/article-dialog/types.d.ts +6 -0
- package/dist/articles/article-dialog/types.js +1 -0
- package/dist/articles/data-providers/index.d.ts +1 -0
- package/dist/articles/data-providers/index.js +1 -0
- package/dist/articles/data-providers/types.d.ts +14 -0
- package/dist/articles/data-providers/types.js +1 -0
- package/dist/external-api/article/cmp.embed-article.svelte +9 -28
- package/dist/external-api/data-providers/article/article-data-provider.d.ts +4 -0
- package/dist/external-api/data-providers/article/article-data-provider.js +32 -0
- package/dist/external-api/data-providers/article/index.d.ts +1 -0
- package/dist/external-api/data-providers/article/index.js +1 -0
- package/dist/external-api/{article → data-providers/article}/operations.generated.d.ts +1 -1
- package/dist/external-api/data-providers/internal-media-center-data-provider.svelte.js +3 -1
- package/dist/media-center/config/types.d.ts +3 -0
- package/dist/media-center/media-center/cmp.media-center-proxy.svelte +9 -4
- package/dist/media-center/media-center/cmp.media-center-proxy.svelte.d.ts +2 -3
- package/dist/media-center/media-center/index.d.ts +0 -1
- package/dist/media-center/media-center/index.js +0 -1
- package/dist/media-center/media-center/media-center-settings.svelte.d.ts +1 -1
- package/dist/media-center/media-center/media-center-settings.svelte.js +2 -2
- package/dist/media-center/media-center/posts-feed/posts-feed-handler.svelte.js +1 -0
- package/dist/media-page/cmp.media-page.svelte +10 -9
- package/dist/media-page/index.js +4 -4
- package/dist/posts/model/post-model.d.ts +1 -0
- package/dist/posts/model/post-model.js +2 -0
- package/dist/posts/post-viewer/cmp.post-viewer.svelte +10 -2
- package/dist/posts/post-viewer/cmp.post-viewer.svelte.d.ts +1 -0
- package/dist/posts/post-viewer/post-texts.svelte +8 -1
- package/dist/posts/post-viewer/post-texts.svelte.d.ts +3 -0
- package/dist/posts/posts-player/cmp.posts-player.svelte +23 -13
- package/dist/posts/posts-player/cmp.posts-player.svelte.d.ts +2 -0
- package/dist/posts/posts-player/index.d.ts +8 -1
- package/dist/posts/posts-player/index.js +7 -1
- package/dist/posts/posts-player/posts-player-proxy.svelte +3 -2
- package/dist/posts/posts-player/posts-player-proxy.svelte.d.ts +2 -0
- package/dist/posts/posts-player/posts-player-view.svelte +18 -4
- package/dist/posts/posts-player/types.d.ts +3 -0
- package/dist/streams/streams-player/cmp.streams-player.svelte +22 -13
- package/dist/streams/streams-player/streams-player-proxy.svelte +1 -1
- package/dist/ui/shadow-dom/cmp.shadow-root.svelte +3 -2
- package/dist/ui/shadow-dom/index.d.ts +1 -1
- package/dist/ui/shadow-dom/index.js +1 -1
- package/dist/ui/shadow-dom/shadow-root-service.d.ts +1 -0
- package/dist/ui/shadow-dom/shadow-root-service.js +8 -0
- package/package.json +1 -1
- package/dist/posts/posts-player/posts-player-host-settings.svelte.d.ts +0 -20
- package/dist/posts/posts-player/posts-player-host-settings.svelte.js +0 -15
- package/dist/streams/streams-player/streams-player-host-settings.svelte.d.ts +0 -20
- package/dist/streams/streams-player/streams-player-host-settings.svelte.js +0 -15
- /package/dist/external-api/{article → data-providers/article}/operations.generated.js +0 -0
- /package/dist/external-api/{article → data-providers/article}/operations.graphql +0 -0
|
@@ -4,7 +4,7 @@ import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
|
|
|
4
4
|
type Props = {
|
|
5
5
|
sections: ArticleSectionModel[];
|
|
6
6
|
metadata: ArticleMetadata;
|
|
7
|
-
theme: ThemeValue;
|
|
7
|
+
theme: ThemeValue | undefined;
|
|
8
8
|
locale: AppLocaleValue | undefined;
|
|
9
9
|
};
|
|
10
10
|
declare const ArticleProxy: import("svelte").Component<Props, {}, "">;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">import { createShadowRoot } from '../../ui/shadow-dom';
|
|
2
2
|
import { default as ArticleProxy } from './article-proxy.svelte';
|
|
3
3
|
import { mount, unmount } from 'svelte';
|
|
4
|
-
let { sections, metadata, theme
|
|
4
|
+
let { sections, metadata, theme, locale } = $props();
|
|
5
5
|
const initHost = (node) => {
|
|
6
6
|
const shadowRoot = createShadowRoot(node);
|
|
7
7
|
const mounted = mount(ArticleProxy, {
|
|
@@ -3,5 +3,5 @@ export { default as ArticleView } from './article-view.svelte';
|
|
|
3
3
|
export { default as FactsContainer } from './cmp.facts-container.svelte';
|
|
4
4
|
export { fieldIsFilled, layoutIsFilled, sectionIsFilled } from './helpers';
|
|
5
5
|
export { ArticleStylesHelper } from './styles-transformer';
|
|
6
|
-
export type { ArticleLayoutModel, ArticleLayoutStylesModel, ArticleMetadata, ArticleSectionModel, ArticleSectionStylesModel } from './types';
|
|
6
|
+
export type { ArticleLayoutModel, ArticleLayoutStylesModel, ArticleMetadata, ArticleSectionModel, ArticleSectionStylesModel, ArticleSeo } from './types';
|
|
7
7
|
export type { ArticleFieldDataModel, ArticleFieldModel, ArticleFieldStylesModel, BylineFieldDataModel, FieldMetadata, ImageFieldDataModel, MediaFieldDataModel, MediaGalleryFieldDataModel, RichTextFieldDataModel, TextFieldDataModel, VideoFieldDataModel } from './fields/types';
|
|
@@ -2,6 +2,11 @@ import type { ArticleFieldModel } from './fields/types';
|
|
|
2
2
|
export type ArticleMetadata = {
|
|
3
3
|
displayDate: string;
|
|
4
4
|
};
|
|
5
|
+
export type ArticleSeo = {
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
keywords: string[];
|
|
9
|
+
};
|
|
5
10
|
export type ArticleSectionModel = {
|
|
6
11
|
id: string;
|
|
7
12
|
styles: ArticleSectionStylesModel | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AppLocale } from '@streamscloud/kit/core/locale';
|
|
2
|
+
export class ArticleDialogLocalization {
|
|
3
|
+
get failedToLoad() {
|
|
4
|
+
return loc.failedToLoad[AppLocale.current];
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
const loc = {
|
|
8
|
+
failedToLoad: { en: 'Failed to load article', no: 'Kunne ikke laste artikkelen' }
|
|
9
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script lang="ts">import { default as ArticleView } from '../article/article-view.svelte';
|
|
2
|
+
import { ArticleDialogLocalization } from './article-dialog-localization';
|
|
3
|
+
import { DialogCloseButton } from '@streamscloud/kit/ui/dialog';
|
|
4
|
+
import { Loading } from '@streamscloud/kit/ui/loading';
|
|
5
|
+
import { untrack } from 'svelte';
|
|
6
|
+
let { controller, data } = $props();
|
|
7
|
+
const localization = new ArticleDialogLocalization();
|
|
8
|
+
$effect(() => untrack(() => {
|
|
9
|
+
controller.updateSettings({ closeOnEsc: true, closeOnClickOutside: true });
|
|
10
|
+
controller.updateContainerSettings({ position: 'full-screen' });
|
|
11
|
+
}));
|
|
12
|
+
let articleData = $state.raw(null);
|
|
13
|
+
let loading = $state(true);
|
|
14
|
+
let failed = $state(false);
|
|
15
|
+
const load = async () => {
|
|
16
|
+
loading = true;
|
|
17
|
+
failed = false;
|
|
18
|
+
const result = await data.fetchArticle({ id: data.articleId });
|
|
19
|
+
if (result) {
|
|
20
|
+
articleData = result;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
failed = true;
|
|
24
|
+
}
|
|
25
|
+
loading = false;
|
|
26
|
+
};
|
|
27
|
+
void load();
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<div class="article-dialog">
|
|
31
|
+
<div class="article-dialog__close">
|
|
32
|
+
<DialogCloseButton controller={controller} />
|
|
33
|
+
</div>
|
|
34
|
+
<div class="article-dialog__content">
|
|
35
|
+
{#if loading}
|
|
36
|
+
<div class="article-dialog__loading">
|
|
37
|
+
<Loading positionAbsoluteCenter timeout={400} />
|
|
38
|
+
</div>
|
|
39
|
+
{:else if failed}
|
|
40
|
+
<div class="article-dialog__error">{localization.failedToLoad}</div>
|
|
41
|
+
{:else if articleData}
|
|
42
|
+
<ArticleView sections={articleData.sections} metadata={articleData.metadata} />
|
|
43
|
+
{/if}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<style>.article-dialog {
|
|
48
|
+
width: 100%;
|
|
49
|
+
height: 100%;
|
|
50
|
+
position: relative;
|
|
51
|
+
}
|
|
52
|
+
.article-dialog__close {
|
|
53
|
+
--sc-kit--dialog-close-button--color: #fff;
|
|
54
|
+
--sc-kit--icon--filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.2));
|
|
55
|
+
position: absolute;
|
|
56
|
+
top: 0.75rem;
|
|
57
|
+
right: 1rem;
|
|
58
|
+
z-index: 10;
|
|
59
|
+
}
|
|
60
|
+
.article-dialog__content {
|
|
61
|
+
--article--max-width: 56.25rem;
|
|
62
|
+
--article--container-background: light-dark(rgba(255, 255, 255, 0.8), rgba(0, 0, 0, 0.8));
|
|
63
|
+
width: 100%;
|
|
64
|
+
height: 100%;
|
|
65
|
+
overflow-y: auto;
|
|
66
|
+
--_cross-browser-scrollbar--thumb-color: var(--scrollbar--thumb-color, #7d7d7d);
|
|
67
|
+
--_cross-browser-scrollbar--track-color: var(--scrollbar--track-color, transparent);
|
|
68
|
+
}
|
|
69
|
+
.article-dialog__content::-webkit-scrollbar {
|
|
70
|
+
width: 6px;
|
|
71
|
+
height: 6px;
|
|
72
|
+
}
|
|
73
|
+
.article-dialog__content::-webkit-scrollbar-track {
|
|
74
|
+
background: var(--_cross-browser-scrollbar--track-color);
|
|
75
|
+
border-radius: 100vw;
|
|
76
|
+
}
|
|
77
|
+
.article-dialog__content::-webkit-scrollbar-thumb {
|
|
78
|
+
background: var(--_cross-browser-scrollbar--thumb-color);
|
|
79
|
+
border-radius: 100vw;
|
|
80
|
+
}
|
|
81
|
+
@supports (scrollbar-color: transparent transparent) {
|
|
82
|
+
.article-dialog__content {
|
|
83
|
+
scrollbar-color: var(--_cross-browser-scrollbar--thumb-color) var(--_cross-browser-scrollbar--track-color);
|
|
84
|
+
scrollbar-width: thin;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
.article-dialog__loading {
|
|
88
|
+
position: relative;
|
|
89
|
+
min-height: 18.75rem;
|
|
90
|
+
}
|
|
91
|
+
.article-dialog__error {
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
justify-content: center;
|
|
95
|
+
min-height: 12.5rem;
|
|
96
|
+
color: light-dark(#9ca3af, #6b7280);
|
|
97
|
+
font-size: 1rem;
|
|
98
|
+
}</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ArticleDialogViewData } from './types';
|
|
2
|
+
import { type DialogController } from '@streamscloud/kit/ui/dialog';
|
|
3
|
+
type Props = {
|
|
4
|
+
controller: DialogController;
|
|
5
|
+
data: ArticleDialogViewData;
|
|
6
|
+
};
|
|
7
|
+
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type Cmp = ReturnType<typeof Cmp>;
|
|
9
|
+
export default Cmp;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { default as ArticleDialog } from './cmp.article-dialog.svelte';
|
|
2
|
+
import { Dialogs } from '@streamscloud/kit/ui/dialog';
|
|
3
|
+
export const openArticleDialog = (data) => {
|
|
4
|
+
const { anchor, articleId, fetchArticle } = data;
|
|
5
|
+
void Dialogs.open({
|
|
6
|
+
view: ArticleDialog,
|
|
7
|
+
data: { articleId, fetchArticle },
|
|
8
|
+
host: anchor
|
|
9
|
+
});
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { ArticleData, ArticleDataProvider } from './types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ArticleMetadata, ArticleSectionModel, ArticleSeo } from '../article';
|
|
2
|
+
/** Article data returned by a data provider. */
|
|
3
|
+
export type ArticleData = {
|
|
4
|
+
sections: ArticleSectionModel[];
|
|
5
|
+
metadata: ArticleMetadata;
|
|
6
|
+
seo: ArticleSeo;
|
|
7
|
+
};
|
|
8
|
+
/** Provider for fetching article content by ID. */
|
|
9
|
+
export type ArticleDataProvider = {
|
|
10
|
+
fetchArticle: (input: {
|
|
11
|
+
id?: string;
|
|
12
|
+
slug?: string;
|
|
13
|
+
}) => Promise<ArticleData | null>;
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
<script lang="ts">import { Article } from '../../articles/article';
|
|
2
2
|
import { createLocalGQLClient } from '../../core/graphql';
|
|
3
|
-
import {
|
|
3
|
+
import { createArticleDataProvider } from '../data-providers/article/article-data-provider';
|
|
4
4
|
import { Loading } from '@streamscloud/kit/ui/loading';
|
|
5
5
|
import { untrack } from 'svelte';
|
|
6
|
-
let { id, slug, initiator, graphqlOrigin, theme
|
|
7
|
-
let
|
|
8
|
-
let metadata = $state.raw(null);
|
|
6
|
+
let { id, slug, initiator, graphqlOrigin, theme, on } = $props();
|
|
7
|
+
let data = $state.raw(null);
|
|
9
8
|
let notFound = $state(false);
|
|
10
|
-
const mapSections = (article) => article.sections.map((section) => ({
|
|
11
|
-
id: section.id,
|
|
12
|
-
facts: section.facts,
|
|
13
|
-
styles: section.styles,
|
|
14
|
-
layouts: section.layouts.map((layout) => ({
|
|
15
|
-
id: layout.id,
|
|
16
|
-
styles: layout.styles,
|
|
17
|
-
fields: layout.fields.map((field) => ({
|
|
18
|
-
id: field.id,
|
|
19
|
-
name: field.name,
|
|
20
|
-
description: field.description,
|
|
21
|
-
styles: field.styles,
|
|
22
|
-
fieldData: field.fieldData
|
|
23
|
-
}))
|
|
24
|
-
}))
|
|
25
|
-
}));
|
|
26
9
|
const extractCoverImageUrl = (article) => {
|
|
27
10
|
for (const section of article.sections) {
|
|
28
11
|
for (const layout of section.layouts) {
|
|
@@ -39,15 +22,13 @@ const extractCoverImageUrl = (article) => {
|
|
|
39
22
|
};
|
|
40
23
|
const load = async () => {
|
|
41
24
|
const graphql = createLocalGQLClient(graphqlOrigin, { initiator });
|
|
42
|
-
const
|
|
43
|
-
|
|
25
|
+
const dataProvider = createArticleDataProvider(graphql);
|
|
26
|
+
data = await dataProvider.fetchArticle({ id, slug });
|
|
27
|
+
if (!data) {
|
|
44
28
|
notFound = true;
|
|
45
29
|
return;
|
|
46
30
|
}
|
|
47
|
-
|
|
48
|
-
sections = mapSections(article);
|
|
49
|
-
metadata = { displayDate: article.publishedAt ?? '' };
|
|
50
|
-
on?.seoLoaded?.({ ...article.seo, imageUrl: extractCoverImageUrl(article) });
|
|
31
|
+
on?.seoLoaded?.({ ...data.seo, imageUrl: extractCoverImageUrl(data) });
|
|
51
32
|
};
|
|
52
33
|
$effect(() => {
|
|
53
34
|
untrack(() => {
|
|
@@ -58,8 +39,8 @@ $effect(() => {
|
|
|
58
39
|
|
|
59
40
|
{#if notFound}
|
|
60
41
|
<div class="embed-article__not-found">¯\_(ツ)_/¯</div>
|
|
61
|
-
{:else if
|
|
62
|
-
<Article sections={sections} metadata={metadata} theme={theme} />
|
|
42
|
+
{:else if data}
|
|
43
|
+
<Article sections={data.sections} metadata={data.metadata} theme={theme} />
|
|
63
44
|
{:else}
|
|
64
45
|
<div class="embed-article__loading">
|
|
65
46
|
<Loading positionAbsoluteCenter timeout={600} />
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ArticleDataProvider } from '../../../articles/data-providers';
|
|
2
|
+
import type { Client } from '@urql/core';
|
|
3
|
+
/** Creates an ArticleDataProvider that fetches articles via the GetEmbedArticle GraphQL query. */
|
|
4
|
+
export declare const createArticleDataProvider: (graphql: Client) => ArticleDataProvider;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { GetEmbedArticleDocument } from './operations.generated';
|
|
2
|
+
/** Creates an ArticleDataProvider that fetches articles via the GetEmbedArticle GraphQL query. */
|
|
3
|
+
export const createArticleDataProvider = (graphql) => ({
|
|
4
|
+
fetchArticle: async (input) => {
|
|
5
|
+
const { id, slug } = input;
|
|
6
|
+
const result = await graphql.query(GetEmbedArticleDocument, { input: { id, slug } }).toPromise();
|
|
7
|
+
const article = result.data?.article;
|
|
8
|
+
if (!article) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
sections: article.sections.map((section) => ({
|
|
13
|
+
id: section.id,
|
|
14
|
+
facts: section.facts,
|
|
15
|
+
styles: section.styles,
|
|
16
|
+
layouts: section.layouts.map((layout) => ({
|
|
17
|
+
id: layout.id,
|
|
18
|
+
styles: layout.styles,
|
|
19
|
+
fields: layout.fields.map((field) => ({
|
|
20
|
+
id: field.id,
|
|
21
|
+
name: field.name,
|
|
22
|
+
description: field.description,
|
|
23
|
+
styles: field.styles,
|
|
24
|
+
fieldData: field.fieldData
|
|
25
|
+
}))
|
|
26
|
+
}))
|
|
27
|
+
})),
|
|
28
|
+
metadata: { displayDate: article.publishedAt ?? '' },
|
|
29
|
+
seo: article.seo
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createArticleDataProvider } from './article-data-provider';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createArticleDataProvider } from './article-data-provider';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type * as SchemaTypes from '
|
|
1
|
+
import type * as SchemaTypes from '../../../../gql/types';
|
|
2
2
|
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
3
3
|
export type GetEmbedArticleQueryVariables = SchemaTypes.Exact<{
|
|
4
4
|
input: SchemaTypes.EmbedArticleInput;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createLocalGQLClient } from '../../core/graphql';
|
|
2
|
+
import { createArticleDataProvider } from './article';
|
|
2
3
|
import { InternalMediaCenterAnalyticsHandler } from './internal-media-center-analytics-handler';
|
|
3
4
|
import { MockCategoryFollowingProvider, MockMediaCenterContentManagementHandler, MockMembershipHandler, MockNavigationHandler, MockPostSocialInteractionsHandler } from './mocks';
|
|
4
5
|
import { GetMediaPageConfigDocument } from './operations.generated';
|
|
@@ -57,7 +58,8 @@ export class InternalMediaCenterDataProvider {
|
|
|
57
58
|
limit,
|
|
58
59
|
graphql: this.graphql
|
|
59
60
|
});
|
|
60
|
-
}
|
|
61
|
+
},
|
|
62
|
+
fetchArticle: createArticleDataProvider(this.graphql).fetchArticle
|
|
61
63
|
};
|
|
62
64
|
this.streamPlayer = {
|
|
63
65
|
getStreamsCursor: async ({ filter, limit, continuationToken }) => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ArticleDataProvider } from '../../articles/data-providers';
|
|
1
2
|
import type { PostType } from '../../core/enums';
|
|
2
3
|
import type { IContentCategoryFollowingHandler } from '../categories-following';
|
|
3
4
|
import type { IMediaCenterContentManagementHandler } from '../content-management';
|
|
@@ -36,6 +37,8 @@ export interface IMediaCenterDataProvider {
|
|
|
36
37
|
items: PostPlayerModel[];
|
|
37
38
|
continuationToken: string | null;
|
|
38
39
|
}>;
|
|
40
|
+
/** Provider for fetching article content. Enables "Read more" button that opens an article dialog in posts player. */
|
|
41
|
+
fetchArticle?: ArticleDataProvider['fetchArticle'];
|
|
39
42
|
};
|
|
40
43
|
streamPlayer: {
|
|
41
44
|
getStreamsCursor: (input: {
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
<script lang="ts">import {} from '../../ui/player/close-orchestrator';
|
|
2
2
|
import { ShadowRoot } from '../../ui/shadow-dom';
|
|
3
3
|
import { MediaCenterContext } from './media-center-context.svelte';
|
|
4
|
+
import { MediaCenterSettings } from './media-center-settings.svelte';
|
|
4
5
|
import { default as MediaCenterView } from './media-center-view.svelte';
|
|
5
6
|
import { Utils } from '@streamscloud/kit/core/utils';
|
|
6
7
|
import { Loading } from '@streamscloud/kit/ui/loading';
|
|
7
8
|
import { untrack } from 'svelte';
|
|
8
9
|
let { dataProvider, modeProps, settings, closeOrchestrator, dynamicActions } = $props();
|
|
10
|
+
const settingsHolder = untrack(() => new MediaCenterSettings(settings));
|
|
11
|
+
$effect(() => {
|
|
12
|
+
settingsHolder.update(settings);
|
|
13
|
+
});
|
|
9
14
|
const context = untrack(() => new MediaCenterContext({
|
|
10
15
|
dataProvider,
|
|
11
16
|
closeOrchestrator,
|
|
12
|
-
settings,
|
|
17
|
+
settings: settingsHolder,
|
|
13
18
|
on: {
|
|
14
19
|
initialized: (instance) => {
|
|
15
20
|
switch (modeProps.mode) {
|
|
@@ -26,8 +31,8 @@ const context = untrack(() => new MediaCenterContext({
|
|
|
26
31
|
});
|
|
27
32
|
break;
|
|
28
33
|
case 'default':
|
|
29
|
-
if (
|
|
30
|
-
instance.restoreState(
|
|
34
|
+
if (settingsHolder.state) {
|
|
35
|
+
instance.restoreState(settingsHolder.state);
|
|
31
36
|
}
|
|
32
37
|
else {
|
|
33
38
|
instance.activateDiscover({ categoryId: null });
|
|
@@ -50,7 +55,7 @@ const context = untrack(() => new MediaCenterContext({
|
|
|
50
55
|
{:else if !context.initialized}
|
|
51
56
|
Not initialized placeholder
|
|
52
57
|
{:else}
|
|
53
|
-
<ShadowRoot locale={
|
|
58
|
+
<ShadowRoot locale={settingsHolder.locale} theme={settingsHolder.theme} {...context.backgroundWrapperProps}>
|
|
54
59
|
<MediaCenterView context={context} dynamicActions={dynamicActions} />
|
|
55
60
|
</ShadowRoot>
|
|
56
61
|
{/if}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { IMediaCenterDataProvider } from '../config/types';
|
|
2
2
|
import { type ICloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
3
|
-
import type {
|
|
4
|
-
import type { MediaCenterModeProps } from './types';
|
|
3
|
+
import type { IMediaCenterSettings, MediaCenterModeProps } from './types';
|
|
5
4
|
import { type Snippet } from 'svelte';
|
|
6
5
|
type Props = {
|
|
7
6
|
dataProvider: IMediaCenterDataProvider;
|
|
8
|
-
settings
|
|
7
|
+
settings?: IMediaCenterSettings;
|
|
9
8
|
modeProps: MediaCenterModeProps;
|
|
10
9
|
closeOrchestrator: ICloseOrchestrator;
|
|
11
10
|
dynamicActions?: Snippet;
|
|
@@ -6,7 +6,7 @@ export declare class MediaCenterSettings {
|
|
|
6
6
|
locale: AppLocaleValue;
|
|
7
7
|
showStreamsCloudWatermark: boolean;
|
|
8
8
|
disableBackground: boolean;
|
|
9
|
-
theme: ThemeValue;
|
|
9
|
+
theme: ThemeValue | undefined;
|
|
10
10
|
state: MediaCenterState | null;
|
|
11
11
|
constructor(init: IMediaCenterSettings | undefined);
|
|
12
12
|
update: (data: IMediaCenterSettings | undefined) => void;
|
|
@@ -2,7 +2,7 @@ export class MediaCenterSettings {
|
|
|
2
2
|
locale = $state('en');
|
|
3
3
|
showStreamsCloudWatermark = $state(false);
|
|
4
4
|
disableBackground = $state(false);
|
|
5
|
-
theme = $state(
|
|
5
|
+
theme = $state(undefined);
|
|
6
6
|
state = $state.raw(null);
|
|
7
7
|
constructor(init) {
|
|
8
8
|
this.update(init);
|
|
@@ -11,7 +11,7 @@ export class MediaCenterSettings {
|
|
|
11
11
|
this.locale = data?.locale ?? 'en';
|
|
12
12
|
this.showStreamsCloudWatermark = data?.showStreamsCloudWatermark ?? false;
|
|
13
13
|
this.disableBackground = data?.disableBackground ?? false;
|
|
14
|
-
this.theme = data?.theme
|
|
14
|
+
this.theme = data?.theme;
|
|
15
15
|
this.state = data?.state ?? null;
|
|
16
16
|
};
|
|
17
17
|
}
|
|
@@ -175,6 +175,7 @@ export class PostsFeedHandler {
|
|
|
175
175
|
socialInteractionsHandler: this._dataProvider.handlers?.postSocialInteractionsHandler,
|
|
176
176
|
sharingHandler: this._dataProvider.handlers?.postSharingHandler,
|
|
177
177
|
analyticsHandler: this._dataProvider.handlers?.analyticsHandler,
|
|
178
|
+
articleDataProvider: this._dataProvider.postsPlayer.fetchArticle ? { fetchArticle: this._dataProvider.postsPlayer.fetchArticle } : undefined,
|
|
178
179
|
playerSettings: this._mediaCenterSettingsHandler.playerSettings,
|
|
179
180
|
closeOrchestrator: this._closeOrchestrator,
|
|
180
181
|
on: {
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
<script lang="ts">import { MediaCenterProxy } from '../media-center/media-center';
|
|
2
|
-
import { MediaCenterSettings } from '../media-center/media-center/media-center-settings.svelte';
|
|
3
2
|
import { CloseOrchestrator } from '../ui/player/close-orchestrator';
|
|
4
3
|
import { createShadowRoot } from '../ui/shadow-dom';
|
|
5
|
-
import { mount, unmount
|
|
4
|
+
import { mount, unmount } from 'svelte';
|
|
6
5
|
let { dataProvider, settings, dynamicActions } = $props();
|
|
7
|
-
const settingsHolder = untrack(() => new MediaCenterSettings(settings));
|
|
8
|
-
$effect(() => {
|
|
9
|
-
settingsHolder.update(settings);
|
|
10
|
-
});
|
|
11
6
|
const initHost = (node) => {
|
|
12
7
|
const shadowRoot = createShadowRoot(node);
|
|
13
8
|
const mounted = mount(MediaCenterProxy, {
|
|
14
9
|
target: shadowRoot,
|
|
15
10
|
props: {
|
|
16
|
-
dataProvider
|
|
17
|
-
|
|
11
|
+
get dataProvider() {
|
|
12
|
+
return dataProvider;
|
|
13
|
+
},
|
|
14
|
+
get settings() {
|
|
15
|
+
return settings;
|
|
16
|
+
},
|
|
18
17
|
modeProps: { mode: 'default' },
|
|
19
|
-
dynamicActions
|
|
18
|
+
get dynamicActions() {
|
|
19
|
+
return dynamicActions;
|
|
20
|
+
},
|
|
20
21
|
closeOrchestrator: new CloseOrchestrator({
|
|
21
22
|
closeFn: async () => {
|
|
22
23
|
await unmount(mounted);
|
package/dist/media-page/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {} from '../media-center/config/types';
|
|
2
|
-
import { MediaCenterProxy
|
|
2
|
+
import { MediaCenterProxy } from '../media-center/media-center';
|
|
3
3
|
import { CloseOrchestrator } from '../ui/player/close-orchestrator';
|
|
4
4
|
import { ModalShadowHost } from '../ui/shadow-dom';
|
|
5
5
|
import { mount, unmount } from 'svelte';
|
|
@@ -83,7 +83,7 @@ export function openMediaPageModal(init) {
|
|
|
83
83
|
target: shadowHost.shadowRoot,
|
|
84
84
|
props: {
|
|
85
85
|
dataProvider,
|
|
86
|
-
settings:
|
|
86
|
+
settings: viewerSettings,
|
|
87
87
|
modeProps: {
|
|
88
88
|
mode: 'default'
|
|
89
89
|
},
|
|
@@ -110,7 +110,7 @@ export function openMediaPageModalWithInitialPostsProvider(init) {
|
|
|
110
110
|
target: shadowHost.shadowRoot,
|
|
111
111
|
props: {
|
|
112
112
|
dataProvider: mediaCenterDataProvider,
|
|
113
|
-
settings:
|
|
113
|
+
settings: viewerSettings,
|
|
114
114
|
modeProps: {
|
|
115
115
|
mode: 'posts',
|
|
116
116
|
props: {
|
|
@@ -141,7 +141,7 @@ export function openMediaPageModalWithInitialStreamsProvider(init) {
|
|
|
141
141
|
target: shadowHost.shadowRoot,
|
|
142
142
|
props: {
|
|
143
143
|
dataProvider: mediaCenterDataProvider,
|
|
144
|
-
settings:
|
|
144
|
+
settings: viewerSettings,
|
|
145
145
|
modeProps: {
|
|
146
146
|
mode: 'streams',
|
|
147
147
|
props: {
|
|
@@ -3,6 +3,7 @@ export class PostModel {
|
|
|
3
3
|
id;
|
|
4
4
|
media;
|
|
5
5
|
postType;
|
|
6
|
+
articleId;
|
|
6
7
|
texts;
|
|
7
8
|
heading;
|
|
8
9
|
enableSocialInteractions;
|
|
@@ -10,6 +11,7 @@ export class PostModel {
|
|
|
10
11
|
constructor(init) {
|
|
11
12
|
this.id = init.id;
|
|
12
13
|
this.postType = init.postType;
|
|
14
|
+
this.articleId = init.articleId;
|
|
13
15
|
this.media = new PostViewerMediaModel({ media: init.media, mediaFit: init.mediaFit, mediaIndex: init.mediaIndex });
|
|
14
16
|
this.texts = {
|
|
15
17
|
kicker: init.kicker,
|
|
@@ -45,6 +45,14 @@ const trackControlsPanelSize = (node) => {
|
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
|
+
const handleArticleReadMore = $derived.by(() => {
|
|
49
|
+
const articleId = model.articleId;
|
|
50
|
+
const handler = on?.articleReadMore;
|
|
51
|
+
if (!articleId || !handler) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return () => handler(articleId);
|
|
55
|
+
});
|
|
48
56
|
const variables = $derived.by(() => {
|
|
49
57
|
const values = [];
|
|
50
58
|
if (model.media.isGallery) {
|
|
@@ -56,12 +64,12 @@ const variables = $derived.by(() => {
|
|
|
56
64
|
|
|
57
65
|
<div class="post-viewer" style={variables} use:viewerMounted>
|
|
58
66
|
<PostMedia id={model.id} media={model.media} autoplay={autoplay} on={{ videoProgress: on?.progress }} />
|
|
59
|
-
{#if (uiManager.showAttachments && model.attachments) || model.heading || model.texts.kicker || model.texts.title || model.texts.text || model.texts.readMoreUrl}
|
|
67
|
+
{#if (uiManager.showAttachments && model.attachments) || model.heading || model.texts.kicker || model.texts.title || model.texts.text || model.texts.readMoreUrl || handleArticleReadMore}
|
|
60
68
|
<div class="post-viewer__information">
|
|
61
69
|
{#if model.heading}
|
|
62
70
|
<Heading model={model.heading} uiManager={uiManager} localization={localization} />
|
|
63
71
|
{/if}
|
|
64
|
-
<Texts model={model.texts} uiManager={uiManager} localization={localization} />
|
|
72
|
+
<Texts model={model.texts} uiManager={uiManager} localization={localization} on={{ readMore: handleArticleReadMore }} />
|
|
65
73
|
|
|
66
74
|
{#if uiManager.showAttachments && model.attachments}
|
|
67
75
|
<AttachmentsHorizontal
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">import { PostViewerLocalization } from './post-viewer-localization';
|
|
2
2
|
import { PostViewerUiManager } from './ui-manager.svelte';
|
|
3
3
|
import { LineClamp } from '@streamscloud/kit/ui/line-clamp';
|
|
4
|
-
let { model, uiManager, localization } = $props();
|
|
4
|
+
let { model, uiManager, localization, on } = $props();
|
|
5
5
|
const variables = $derived.by(() => {
|
|
6
6
|
const values = [
|
|
7
7
|
`--_post-viewer-texts--padding: 0 ${uiManager.controlsPanelWidth ? uiManager.controlsPanelWidth : uiManager.infoPaddingInline}px 0 ${uiManager.infoPaddingInline}px`
|
|
@@ -30,6 +30,10 @@ const variables = $derived.by(() => {
|
|
|
30
30
|
<a class="post-viewer-texts__read-more" href={model.readMoreUrl} target="_blank" rel="noopener noreferrer">
|
|
31
31
|
{localization.readMore}
|
|
32
32
|
</a>
|
|
33
|
+
{:else if on?.readMore}
|
|
34
|
+
<button type="button" class="post-viewer-texts__read-more" onclick={on.readMore}>
|
|
35
|
+
{localization.readMore}
|
|
36
|
+
</button>
|
|
33
37
|
{/if}
|
|
34
38
|
</div>
|
|
35
39
|
|
|
@@ -83,6 +87,9 @@ const variables = $derived.by(() => {
|
|
|
83
87
|
pointer-events: auto;
|
|
84
88
|
font-size: 1rem;
|
|
85
89
|
font-weight: 400;
|
|
90
|
+
color: inherit;
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
text-shadow: inherit;
|
|
86
93
|
/* Set 'container-type: inline-size;' to reference container*/
|
|
87
94
|
}
|
|
88
95
|
@container (width < 576px) {
|
|
@@ -5,6 +5,9 @@ type Props = {
|
|
|
5
5
|
model: PostModel['texts'];
|
|
6
6
|
uiManager: PostViewerUiManager;
|
|
7
7
|
localization: PostViewerLocalization;
|
|
8
|
+
on?: {
|
|
9
|
+
readMore?: () => void;
|
|
10
|
+
};
|
|
8
11
|
};
|
|
9
12
|
declare const PostTexts: import("svelte").Component<Props, {}, "">;
|
|
10
13
|
type PostTexts = ReturnType<typeof PostTexts>;
|
|
@@ -1,30 +1,40 @@
|
|
|
1
1
|
<script lang="ts">import { CloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
2
2
|
import { createShadowRoot } from '../../ui/shadow-dom';
|
|
3
|
-
import { PostsPlayerHostSettings } from './posts-player-host-settings.svelte';
|
|
4
3
|
import { default as PostsPlayerProxy } from './posts-player-proxy.svelte';
|
|
5
|
-
import { mount, unmount
|
|
6
|
-
let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, on } = $props();
|
|
7
|
-
const settingsHolder = untrack(() => new PostsPlayerHostSettings(playerSettings));
|
|
8
|
-
$effect(() => {
|
|
9
|
-
settingsHolder.update(playerSettings);
|
|
10
|
-
});
|
|
4
|
+
import { mount, unmount } from 'svelte';
|
|
5
|
+
let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, articleDataProvider, on } = $props();
|
|
11
6
|
const initHost = (node) => {
|
|
12
7
|
const shadowRoot = createShadowRoot(node);
|
|
13
8
|
const mounted = mount(PostsPlayerProxy, {
|
|
14
9
|
target: shadowRoot,
|
|
15
10
|
props: {
|
|
16
|
-
dataProvider
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
get dataProvider() {
|
|
12
|
+
return dataProvider;
|
|
13
|
+
},
|
|
14
|
+
get socialInteractionsHandler() {
|
|
15
|
+
return socialInteractionsHandler;
|
|
16
|
+
},
|
|
17
|
+
get sharingHandler() {
|
|
18
|
+
return sharingHandler;
|
|
19
|
+
},
|
|
20
|
+
get playerSettings() {
|
|
21
|
+
return playerSettings;
|
|
22
|
+
},
|
|
23
|
+
get analyticsHandler() {
|
|
24
|
+
return analyticsHandler;
|
|
25
|
+
},
|
|
26
|
+
get articleDataProvider() {
|
|
27
|
+
return articleDataProvider;
|
|
28
|
+
},
|
|
21
29
|
closeOrchestrator: new CloseOrchestrator({
|
|
22
30
|
closeFn: async () => {
|
|
23
31
|
await unmount(mounted);
|
|
24
32
|
},
|
|
25
33
|
canClose: false
|
|
26
34
|
}),
|
|
27
|
-
on
|
|
35
|
+
get on() {
|
|
36
|
+
return on;
|
|
37
|
+
}
|
|
28
38
|
}
|
|
29
39
|
});
|
|
30
40
|
return {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ArticleDataProvider } from '../../articles/data-providers';
|
|
1
2
|
import type { IPostSocialInteractionsHandler } from '..';
|
|
2
3
|
import type { IPostSharingHandler } from '../sharing';
|
|
3
4
|
import type { IPostAnalyticsHandler, PostPlayerModel } from './types';
|
|
@@ -8,6 +9,7 @@ type Props = {
|
|
|
8
9
|
socialInteractionsHandler?: IPostSocialInteractionsHandler;
|
|
9
10
|
sharingHandler?: IPostSharingHandler;
|
|
10
11
|
analyticsHandler?: IPostAnalyticsHandler;
|
|
12
|
+
articleDataProvider?: ArticleDataProvider;
|
|
11
13
|
playerSettings?: {
|
|
12
14
|
locale?: AppLocaleValue;
|
|
13
15
|
showStreamsCloudWatermark?: boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ArticleDataProvider } from '../../articles/data-providers';
|
|
1
2
|
import { type IMediaCenterDataProvider } from '../../media-center/config/types';
|
|
2
3
|
import type { IPostSharingHandler } from '../sharing';
|
|
3
4
|
import type { IPostSocialInteractionsHandler } from '../social-interactions';
|
|
@@ -5,7 +6,7 @@ import { default as PostsPlayer } from './cmp.posts-player.svelte';
|
|
|
5
6
|
import type { IPostAnalyticsHandler, PostPlayerModel } from './types';
|
|
6
7
|
import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
|
|
7
8
|
export { PostsPlayer, type PostPlayerModel };
|
|
8
|
-
export type { IMediaCenterDataProvider, IPostAnalyticsHandler };
|
|
9
|
+
export type { ArticleDataProvider, IMediaCenterDataProvider, IPostAnalyticsHandler };
|
|
9
10
|
/**
|
|
10
11
|
* Opens the posts player modal.
|
|
11
12
|
*
|
|
@@ -23,6 +24,11 @@ export type { IMediaCenterDataProvider, IPostAnalyticsHandler };
|
|
|
23
24
|
* @param {IPostSocialInteractionsHandler} [init.socialInteractionsHandler]
|
|
24
25
|
* Handler for social interactions (like, share, etc.).
|
|
25
26
|
*
|
|
27
|
+
* Article data provider (optional)
|
|
28
|
+
* @param {ArticleDataProvider} [init.articleDataProvider]
|
|
29
|
+
* Provider for fetching article content. When provided, article posts will show
|
|
30
|
+
* a "Read more" button that opens an article dialog instead of navigating to a URL.
|
|
31
|
+
*
|
|
26
32
|
* Player settings (optional)
|
|
27
33
|
* @param {object} [init.playerSettings]
|
|
28
34
|
* Player UI and behavior settings.
|
|
@@ -87,6 +93,7 @@ export declare function openPostsPlayer(init: {
|
|
|
87
93
|
analyticsHandler?: IPostAnalyticsHandler;
|
|
88
94
|
socialInteractionsHandler?: IPostSocialInteractionsHandler;
|
|
89
95
|
sharingHandler?: IPostSharingHandler;
|
|
96
|
+
articleDataProvider?: ArticleDataProvider;
|
|
90
97
|
playerSettings?: {
|
|
91
98
|
disableBackground?: boolean;
|
|
92
99
|
locale?: AppLocaleValue;
|
|
@@ -22,6 +22,11 @@ export { PostsPlayer };
|
|
|
22
22
|
* @param {IPostSocialInteractionsHandler} [init.socialInteractionsHandler]
|
|
23
23
|
* Handler for social interactions (like, share, etc.).
|
|
24
24
|
*
|
|
25
|
+
* Article data provider (optional)
|
|
26
|
+
* @param {ArticleDataProvider} [init.articleDataProvider]
|
|
27
|
+
* Provider for fetching article content. When provided, article posts will show
|
|
28
|
+
* a "Read more" button that opens an article dialog instead of navigating to a URL.
|
|
29
|
+
*
|
|
25
30
|
* Player settings (optional)
|
|
26
31
|
* @param {object} [init.playerSettings]
|
|
27
32
|
* Player UI and behavior settings.
|
|
@@ -82,7 +87,7 @@ export { PostsPlayer };
|
|
|
82
87
|
* ```
|
|
83
88
|
*/
|
|
84
89
|
export function openPostsPlayer(init) {
|
|
85
|
-
const { postsProvider: dataProvider, analyticsHandler, socialInteractionsHandler, sharingHandler, playerSettings, on } = init;
|
|
90
|
+
const { postsProvider: dataProvider, analyticsHandler, socialInteractionsHandler, sharingHandler, articleDataProvider, playerSettings, on } = init;
|
|
86
91
|
const shadowHost = new ModalShadowHost();
|
|
87
92
|
let mounted = null;
|
|
88
93
|
const makeCloseOrchestrator = () => new CloseOrchestrator({
|
|
@@ -102,6 +107,7 @@ export function openPostsPlayer(init) {
|
|
|
102
107
|
socialInteractionsHandler,
|
|
103
108
|
sharingHandler,
|
|
104
109
|
analyticsHandler,
|
|
110
|
+
articleDataProvider,
|
|
105
111
|
playerSettings,
|
|
106
112
|
closeOrchestrator: makeCloseOrchestrator(),
|
|
107
113
|
on: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">import {} from '../../ui/player/close-orchestrator';
|
|
2
2
|
import { ShadowRoot } from '../../ui/shadow-dom';
|
|
3
3
|
import { default as PostsPlayerView } from './posts-player-view.svelte';
|
|
4
|
-
let { dataProvider, socialInteractionsHandler, sharingHandler, closeOrchestrator, playerSettings, analyticsHandler, on } = $props();
|
|
4
|
+
let { dataProvider, socialInteractionsHandler, sharingHandler, closeOrchestrator, playerSettings, analyticsHandler, articleDataProvider, on } = $props();
|
|
5
5
|
let backgroundImageUrl = $state(null);
|
|
6
6
|
const handleBackgroundImagedLoaded = (url) => {
|
|
7
7
|
backgroundImageUrl = url;
|
|
@@ -10,7 +10,7 @@ const handleBackgroundImagedLoaded = (url) => {
|
|
|
10
10
|
|
|
11
11
|
<ShadowRoot
|
|
12
12
|
locale={playerSettings?.locale}
|
|
13
|
-
theme={playerSettings?.theme
|
|
13
|
+
theme={playerSettings?.theme}
|
|
14
14
|
backgroundDisabled={playerSettings?.disableBackground === true}
|
|
15
15
|
backgroundImageUrl={backgroundImageUrl}>
|
|
16
16
|
<PostsPlayerView
|
|
@@ -19,6 +19,7 @@ const handleBackgroundImagedLoaded = (url) => {
|
|
|
19
19
|
sharingHandler={sharingHandler}
|
|
20
20
|
playerSettings={playerSettings}
|
|
21
21
|
analyticsHandler={analyticsHandler}
|
|
22
|
+
articleDataProvider={articleDataProvider}
|
|
22
23
|
closeOrchestrator={closeOrchestrator}
|
|
23
24
|
on={{ postActivated: on?.postActivated, backgroundImageLoaded: playerSettings?.disableBackground === true ? undefined : handleBackgroundImagedLoaded }} />
|
|
24
25
|
</ShadowRoot>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ArticleDataProvider } from '../../articles/data-providers';
|
|
1
2
|
import type { IPostSharingHandler } from '../sharing';
|
|
2
3
|
import type { IPostSocialInteractionsHandler } from '../social-interactions';
|
|
3
4
|
import { type ICloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
@@ -9,6 +10,7 @@ type Props = {
|
|
|
9
10
|
socialInteractionsHandler?: IPostSocialInteractionsHandler;
|
|
10
11
|
sharingHandler?: IPostSharingHandler;
|
|
11
12
|
analyticsHandler?: IPostAnalyticsHandler;
|
|
13
|
+
articleDataProvider?: ArticleDataProvider;
|
|
12
14
|
closeOrchestrator: ICloseOrchestrator;
|
|
13
15
|
playerSettings?: {
|
|
14
16
|
locale?: AppLocaleValue;
|
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
<script lang="ts">import {
|
|
1
|
+
<script lang="ts">import { openArticleDialog } from '../../articles/article-dialog';
|
|
2
|
+
import { PostAttachments } from '../attachments';
|
|
2
3
|
import { PostActionsGenerator } from '../controls';
|
|
3
4
|
import { getPostCoverImage, PostModel } from '../model';
|
|
4
5
|
import { PostViewer } from '../post-viewer';
|
|
5
6
|
import { Player, PlayerConfig, PlayerSettings } from '../../ui/player';
|
|
7
|
+
import { getDialogAnchor } from '../../ui/shadow-dom';
|
|
6
8
|
import IconDelete from '@fluentui/svg-icons/icons/delete_32_regular.svg?raw';
|
|
7
9
|
import IconEdit from '@fluentui/svg-icons/icons/edit_32_regular.svg?raw';
|
|
8
10
|
import { preloadImage } from '@streamscloud/kit/core/utils';
|
|
9
11
|
import { initBufferFromProvider } from '@streamscloud/kit/ui/player/providers';
|
|
10
12
|
import { untrack } from 'svelte';
|
|
11
|
-
let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, managementActions, closeOrchestrator, on } = $props();
|
|
13
|
+
let { dataProvider, socialInteractionsHandler, sharingHandler, playerSettings, analyticsHandler, managementActions, articleDataProvider, closeOrchestrator, on } = $props();
|
|
14
|
+
let playerHostElement = $state();
|
|
15
|
+
const handleArticleReadMore = (articleId) => {
|
|
16
|
+
if (!articleDataProvider || !playerHostElement) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const anchor = getDialogAnchor(playerHostElement);
|
|
20
|
+
if (!anchor) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
openArticleDialog({ anchor, articleId, fetchArticle: articleDataProvider.fetchArticle });
|
|
24
|
+
};
|
|
12
25
|
let buffer = $state.raw(null);
|
|
13
26
|
let mappedPostsCache = {};
|
|
14
27
|
$effect(() => {
|
|
@@ -145,7 +158,7 @@ const currentItemActions = $derived.by(() => {
|
|
|
145
158
|
adImpression: (id) => onAdImpression(id)
|
|
146
159
|
}} />
|
|
147
160
|
{/snippet}
|
|
148
|
-
<div class="player-host">
|
|
161
|
+
<div class="player-host" bind:this={playerHostElement}>
|
|
149
162
|
<Player
|
|
150
163
|
config={contentPlayerConfig}
|
|
151
164
|
itemActions={currentItemActions}
|
|
@@ -164,7 +177,8 @@ const currentItemActions = $derived.by(() => {
|
|
|
164
177
|
productClick: (productId) => onProductClick(productId, postModel.id),
|
|
165
178
|
productImpression: (productId) => onProductImpression(productId, postModel.id),
|
|
166
179
|
adClick: (adId) => onAdClick(adId),
|
|
167
|
-
adImpression: (adId) => onAdImpression(adId)
|
|
180
|
+
adImpression: (adId) => onAdImpression(adId),
|
|
181
|
+
articleReadMore: articleDataProvider ? handleArticleReadMore : undefined
|
|
168
182
|
}} />
|
|
169
183
|
{/snippet}
|
|
170
184
|
</Player>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ArticleDataProvider } from '../../articles/data-providers';
|
|
1
2
|
import type { PostType } from '../../core/enums';
|
|
2
3
|
import type { IPostModel } from '..';
|
|
3
4
|
import type { IPostSharingHandler } from '../sharing';
|
|
@@ -26,6 +27,8 @@ export type PostsPlayerProps = {
|
|
|
26
27
|
sharingHandler?: IPostSharingHandler;
|
|
27
28
|
analyticsHandler?: IPostAnalyticsHandler;
|
|
28
29
|
managementActions?: PostManagementActions;
|
|
30
|
+
/** Provider for fetching article content. Enables "Read more" button that opens an article dialog. */
|
|
31
|
+
articleDataProvider?: ArticleDataProvider;
|
|
29
32
|
playerSettings?: PostPlayerSettings;
|
|
30
33
|
closeOrchestrator: ICloseOrchestrator;
|
|
31
34
|
on?: {
|
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
<script lang="ts">import { CloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
2
2
|
import { createShadowRoot } from '../../ui/shadow-dom';
|
|
3
|
-
import { StreamsPlayerHostSettings } from './streams-player-host-settings.svelte';
|
|
4
3
|
import { default as StreamsPlayerProxy } from './streams-player-proxy.svelte';
|
|
5
|
-
import { mount, unmount
|
|
4
|
+
import { mount, unmount } from 'svelte';
|
|
6
5
|
let { dataProvider, postSocialInteractionsHandler, sharingHandler, amplificationParameters, playerSettings, analyticsHandler, on } = $props();
|
|
7
|
-
const settingsHolder = untrack(() => new StreamsPlayerHostSettings(playerSettings));
|
|
8
|
-
$effect(() => {
|
|
9
|
-
settingsHolder.update(playerSettings);
|
|
10
|
-
});
|
|
11
6
|
const initHost = (node) => {
|
|
12
7
|
const shadowRoot = createShadowRoot(node);
|
|
13
8
|
const mounted = mount(StreamsPlayerProxy, {
|
|
14
9
|
target: shadowRoot,
|
|
15
10
|
props: {
|
|
16
|
-
dataProvider
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
get dataProvider() {
|
|
12
|
+
return dataProvider;
|
|
13
|
+
},
|
|
14
|
+
get postSocialInteractionsHandler() {
|
|
15
|
+
return postSocialInteractionsHandler;
|
|
16
|
+
},
|
|
17
|
+
get sharingHandler() {
|
|
18
|
+
return sharingHandler;
|
|
19
|
+
},
|
|
20
|
+
get analyticsHandler() {
|
|
21
|
+
return analyticsHandler;
|
|
22
|
+
},
|
|
23
|
+
get amplificationParameters() {
|
|
24
|
+
return amplificationParameters;
|
|
25
|
+
},
|
|
26
|
+
get playerSettings() {
|
|
27
|
+
return playerSettings;
|
|
28
|
+
},
|
|
22
29
|
closeOrchestrator: new CloseOrchestrator({
|
|
23
30
|
closeFn: async () => {
|
|
24
31
|
await unmount(mounted);
|
|
25
32
|
},
|
|
26
33
|
canClose: false
|
|
27
34
|
}),
|
|
28
|
-
on
|
|
35
|
+
get on() {
|
|
36
|
+
return on;
|
|
37
|
+
}
|
|
29
38
|
}
|
|
30
39
|
});
|
|
31
40
|
return {
|
|
@@ -10,7 +10,7 @@ const handleBackgroundImagedLoaded = (url) => {
|
|
|
10
10
|
|
|
11
11
|
<ShadowRoot
|
|
12
12
|
locale={playerSettings?.locale}
|
|
13
|
-
theme={playerSettings?.theme
|
|
13
|
+
theme={playerSettings?.theme}
|
|
14
14
|
backgroundDisabled={playerSettings?.disableBackground === true}
|
|
15
15
|
backgroundImageUrl={backgroundImageUrl}>
|
|
16
16
|
<StreamsPlayerView
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">import { brandColors } from '../../core/theme';
|
|
2
2
|
import { AppLocale } from '@streamscloud/kit/core/locale';
|
|
3
|
-
let { locale, theme
|
|
3
|
+
let { locale, theme, backgroundDisabled, backgroundImageUrl, children } = $props();
|
|
4
4
|
$effect(() => {
|
|
5
5
|
if (locale) {
|
|
6
6
|
AppLocale.change(locale);
|
|
@@ -42,9 +42,10 @@ const styles = $derived.by(() => {
|
|
|
42
42
|
class:shadow-root--background-enabled={!backgroundDisabled}
|
|
43
43
|
class:shadow-root--background-active={!backgroundDisabled && backgroundImageUrl && backgroundImageUrl !== 'not-applicable'}
|
|
44
44
|
class:shadow-root--background-loading={!backgroundDisabled && !backgroundImageUrl}
|
|
45
|
-
style:color-scheme={theme}
|
|
45
|
+
style:color-scheme={theme ?? 'light dark'}
|
|
46
46
|
style={styles}>
|
|
47
47
|
{@render children()}
|
|
48
|
+
<div data-dialog-anchor></div>
|
|
48
49
|
</div>
|
|
49
50
|
|
|
50
51
|
<style>@charset "UTF-8";
|
|
@@ -11,3 +11,11 @@ export const createShadowRoot = (host) => {
|
|
|
11
11
|
const prepareShadowRootHost = (host) => {
|
|
12
12
|
host.style.all = 'unset';
|
|
13
13
|
};
|
|
14
|
+
const DIALOG_ANCHOR_SELECTOR = '[data-dialog-anchor]';
|
|
15
|
+
export const getDialogAnchor = (element) => {
|
|
16
|
+
const root = element.getRootNode();
|
|
17
|
+
if (root instanceof ShadowRoot) {
|
|
18
|
+
return root.querySelector(DIALOG_ANCHOR_SELECTOR);
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
};
|
package/package.json
CHANGED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { ThemeValue } from '../../core/theme';
|
|
2
|
-
import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
|
|
3
|
-
export declare class PostsPlayerHostSettings {
|
|
4
|
-
locale: AppLocaleValue | undefined;
|
|
5
|
-
showStreamsCloudWatermark: boolean | undefined;
|
|
6
|
-
disableBackground: boolean | undefined;
|
|
7
|
-
theme: ThemeValue | undefined;
|
|
8
|
-
constructor(init: {
|
|
9
|
-
locale?: AppLocaleValue;
|
|
10
|
-
showStreamsCloudWatermark?: boolean;
|
|
11
|
-
disableBackground?: boolean;
|
|
12
|
-
theme?: ThemeValue;
|
|
13
|
-
} | undefined);
|
|
14
|
-
update: (data: {
|
|
15
|
-
locale?: AppLocaleValue;
|
|
16
|
-
showStreamsCloudWatermark?: boolean;
|
|
17
|
-
disableBackground?: boolean;
|
|
18
|
-
theme?: ThemeValue;
|
|
19
|
-
} | undefined) => void;
|
|
20
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export class PostsPlayerHostSettings {
|
|
2
|
-
locale = $state();
|
|
3
|
-
showStreamsCloudWatermark = $state();
|
|
4
|
-
disableBackground = $state();
|
|
5
|
-
theme = $state();
|
|
6
|
-
constructor(init) {
|
|
7
|
-
this.update(init);
|
|
8
|
-
}
|
|
9
|
-
update = (data) => {
|
|
10
|
-
this.locale = data?.locale;
|
|
11
|
-
this.showStreamsCloudWatermark = data?.showStreamsCloudWatermark;
|
|
12
|
-
this.disableBackground = data?.disableBackground;
|
|
13
|
-
this.theme = data?.theme;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { ThemeValue } from '../../core/theme';
|
|
2
|
-
import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
|
|
3
|
-
export declare class StreamsPlayerHostSettings {
|
|
4
|
-
locale: AppLocaleValue | undefined;
|
|
5
|
-
showStreamsCloudWatermark: boolean | undefined;
|
|
6
|
-
disableBackground: boolean | undefined;
|
|
7
|
-
theme: ThemeValue | undefined;
|
|
8
|
-
constructor(init: {
|
|
9
|
-
locale?: AppLocaleValue;
|
|
10
|
-
showStreamsCloudWatermark?: boolean;
|
|
11
|
-
disableBackground?: boolean;
|
|
12
|
-
theme?: ThemeValue;
|
|
13
|
-
} | undefined);
|
|
14
|
-
update: (data: {
|
|
15
|
-
locale?: AppLocaleValue;
|
|
16
|
-
showStreamsCloudWatermark?: boolean;
|
|
17
|
-
disableBackground?: boolean;
|
|
18
|
-
theme?: ThemeValue;
|
|
19
|
-
} | undefined) => void;
|
|
20
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export class StreamsPlayerHostSettings {
|
|
2
|
-
locale = $state();
|
|
3
|
-
showStreamsCloudWatermark = $state();
|
|
4
|
-
disableBackground = $state();
|
|
5
|
-
theme = $state();
|
|
6
|
-
constructor(init) {
|
|
7
|
-
this.update(init);
|
|
8
|
-
}
|
|
9
|
-
update = (data) => {
|
|
10
|
-
this.locale = data?.locale;
|
|
11
|
-
this.showStreamsCloudWatermark = data?.showStreamsCloudWatermark;
|
|
12
|
-
this.disableBackground = data?.disableBackground;
|
|
13
|
-
this.theme = data?.theme;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
File without changes
|
|
File without changes
|