@streamscloud/embeddable 16.0.7-1772050914349 → 16.0.7-1772056193230
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/cmp.article.svelte +2 -2
- package/dist/core/graphql.d.ts +4 -1
- package/dist/core/graphql.js +3 -3
- package/dist/external-api/article/cmp.embed-article.svelte +97 -0
- package/dist/external-api/article/cmp.embed-article.svelte.d.ts +42 -0
- package/dist/external-api/article/index.d.ts +1 -0
- package/dist/external-api/article/index.js +1 -0
- package/dist/external-api/article/operations.generated.d.ts +104 -0
- package/dist/external-api/article/operations.generated.js +262 -0
- package/dist/external-api/article/operations.graphql +99 -0
- package/dist/external-api/data-providers/internal-media-center-data-provider.svelte.js +1 -1
- package/dist/external-api/data-providers/internal-short-video-player-items-provider.js +1 -1
- package/dist/external-api/data-providers/internal-streams-player-data-provider.js +1 -1
- package/dist/external-api/index.d.ts +2 -1
- package/dist/external-api/index.js +2 -1
- package/dist/ui/media-items/media-item-view/cmp.media-item-view.svelte +18 -47
- package/package.json +1 -5
- package/dist/articles/article-viewer/article-viewer-host-settings.svelte.d.ts +0 -14
- package/dist/articles/article-viewer/article-viewer-host-settings.svelte.js +0 -11
- package/dist/articles/article-viewer/article-viewer-proxy.svelte +0 -9
- package/dist/articles/article-viewer/article-viewer-proxy.svelte.d.ts +0 -10
- package/dist/articles/article-viewer/article-viewer-view.svelte +0 -85
- package/dist/articles/article-viewer/article-viewer-view.svelte.d.ts +0 -9
- package/dist/articles/article-viewer/cmp.article-viewer.svelte +0 -34
- package/dist/articles/article-viewer/cmp.article-viewer.svelte.d.ts +0 -12
- package/dist/articles/article-viewer/index.d.ts +0 -43
- package/dist/articles/article-viewer/index.js +0 -60
- package/dist/articles/article-viewer/types.d.ts +0 -12
- package/dist/articles/article-viewer/types.js +0 -1
|
@@ -15,8 +15,8 @@ const fieldMetadata = $derived({ displayDate: metadata.displayDate });
|
|
|
15
15
|
|
|
16
16
|
<style>.article-container {
|
|
17
17
|
--_article--min-height: var(--article--min-height, 0);
|
|
18
|
-
--_article--background: var(--article--background, light-dark(#ffffff, #
|
|
19
|
-
--_article--text-color: var(--article--text-color);
|
|
18
|
+
--_article--background: var(--article--background, light-dark(#ffffff, #1e1e1e));
|
|
19
|
+
--_article--text-color: var(--article--text-color, light-dark(#000000, #ffffff));
|
|
20
20
|
container-type: inline-size;
|
|
21
21
|
min-height: var(--_article--min-height);
|
|
22
22
|
}
|
package/dist/core/graphql.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
export declare const createLocalGQLClient: (graphqlOrigin?: string,
|
|
1
|
+
export declare const createLocalGQLClient: (graphqlOrigin?: string, options?: {
|
|
2
|
+
initiator?: string;
|
|
3
|
+
customFetch?: typeof fetch;
|
|
4
|
+
}) => any;
|
|
2
5
|
export declare const resolveGraphQLOrigin: (origin?: string) => string;
|
|
3
6
|
export declare const constructGraphQLUrl: (graphqlOrigin?: string) => string;
|
package/dist/core/graphql.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createGQLClient } from '@streamscloud/kit/core';
|
|
2
|
-
export const createLocalGQLClient = (graphqlOrigin,
|
|
2
|
+
export const createLocalGQLClient = (graphqlOrigin, options) => createGQLClient({
|
|
3
3
|
url: constructGraphQLUrl(resolveGraphQLOrigin(graphqlOrigin)),
|
|
4
|
-
headers,
|
|
5
|
-
customFetch
|
|
4
|
+
headers: options?.initiator ? { 'x-initiator': options.initiator } : undefined,
|
|
5
|
+
customFetch: options?.customFetch
|
|
6
6
|
});
|
|
7
7
|
export const resolveGraphQLOrigin = (origin) => {
|
|
8
8
|
return origin || 'https://api.streamscloud.com';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<script lang="ts">import { Article } from '../../articles/article';
|
|
2
|
+
import { createLocalGQLClient } from '../../core/graphql';
|
|
3
|
+
import { GetEmbedArticleDocument } from './operations.generated';
|
|
4
|
+
import { untrack } from 'svelte';
|
|
5
|
+
let { id, slug, initiator, graphqlOrigin, on } = $props();
|
|
6
|
+
let sections = $state.raw(null);
|
|
7
|
+
let metadata = $state.raw(null);
|
|
8
|
+
let notFound = $state(false);
|
|
9
|
+
const mapSections = (article) => article.sections.map((section) => ({
|
|
10
|
+
id: section.id,
|
|
11
|
+
facts: section.facts,
|
|
12
|
+
styles: section.styles,
|
|
13
|
+
layouts: section.layouts.map((layout) => ({
|
|
14
|
+
id: layout.id,
|
|
15
|
+
styles: layout.styles,
|
|
16
|
+
fields: layout.fields.map((field) => ({
|
|
17
|
+
id: field.id,
|
|
18
|
+
name: field.name,
|
|
19
|
+
description: field.description,
|
|
20
|
+
styles: field.styles,
|
|
21
|
+
fieldData: field.fieldData
|
|
22
|
+
}))
|
|
23
|
+
}))
|
|
24
|
+
}));
|
|
25
|
+
const extractCoverImageUrl = (article) => {
|
|
26
|
+
for (const section of article.sections) {
|
|
27
|
+
for (const layout of section.layouts) {
|
|
28
|
+
for (const field of layout.fields) {
|
|
29
|
+
const { fieldData } = field;
|
|
30
|
+
const media = fieldData.imageData?.image ?? fieldData.mediaData?.media ?? fieldData.videoData?.video ?? fieldData.mediaGalleryData?.media?.[0];
|
|
31
|
+
if (media) {
|
|
32
|
+
return media.type === 'IMAGE' ? media.url : (media.thumbnailUrl ?? null);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
};
|
|
39
|
+
const load = async () => {
|
|
40
|
+
const graphql = createLocalGQLClient(graphqlOrigin, { initiator });
|
|
41
|
+
const result = await graphql.query(GetEmbedArticleDocument, { input: { id, slug } }).toPromise();
|
|
42
|
+
if (!result.data?.article) {
|
|
43
|
+
notFound = true;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const article = result.data.article;
|
|
47
|
+
sections = mapSections(article);
|
|
48
|
+
metadata = { displayDate: article.publishedAt ?? '' };
|
|
49
|
+
on?.seoLoaded?.({ ...article.seo, imageUrl: extractCoverImageUrl(article) });
|
|
50
|
+
};
|
|
51
|
+
$effect(() => {
|
|
52
|
+
untrack(() => {
|
|
53
|
+
void load();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
{#if notFound}
|
|
59
|
+
<div class="embed-article__not-found">¯\_(ツ)_/¯</div>
|
|
60
|
+
{:else if sections && metadata}
|
|
61
|
+
<Article sections={sections} metadata={metadata} />
|
|
62
|
+
{/if}
|
|
63
|
+
|
|
64
|
+
<!--
|
|
65
|
+
@component
|
|
66
|
+
Fetches and renders an article by `id` or `slug` via the `embedArticle` GraphQL query.
|
|
67
|
+
Displays a placeholder when the article is not found.
|
|
68
|
+
|
|
69
|
+
### Props
|
|
70
|
+
| Prop | Type | Description |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `id` | `string?` | Article ID to fetch |
|
|
73
|
+
| `slug` | `string?` | Article slug to fetch (alternative to `id`) |
|
|
74
|
+
| `initiator` | `string?` | Value for the `x-initiator` header |
|
|
75
|
+
| `graphqlOrigin` | `string?` | Custom GraphQL API origin |
|
|
76
|
+
|
|
77
|
+
### Callbacks (`on`)
|
|
78
|
+
| Callback | Type | Description |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `seoLoaded` | `(seo: ArticleSeoModel) => void` | Called after article is loaded with SEO data and cover image URL |
|
|
81
|
+
|
|
82
|
+
### CSS Custom Properties
|
|
83
|
+
| Property | Description | Default |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `--article--background` | Article background color | `white` / `dark-800` |
|
|
86
|
+
| `--article--text-color` | Article text color | `black` / `white` |
|
|
87
|
+
| `--article--min-height` | Minimum article height | `0` |
|
|
88
|
+
-->
|
|
89
|
+
|
|
90
|
+
<style>.embed-article__not-found {
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
min-height: 12.5rem;
|
|
95
|
+
font-size: 1.5rem;
|
|
96
|
+
color: light-dark(#9ca3af, #6b7280);
|
|
97
|
+
}</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type ArticleSeoModel = {
|
|
2
|
+
title: string;
|
|
3
|
+
description: string;
|
|
4
|
+
keywords: string[];
|
|
5
|
+
imageUrl: string | null;
|
|
6
|
+
};
|
|
7
|
+
type Props = {
|
|
8
|
+
id?: string;
|
|
9
|
+
slug?: string;
|
|
10
|
+
initiator?: string;
|
|
11
|
+
graphqlOrigin?: string;
|
|
12
|
+
on?: {
|
|
13
|
+
seoLoaded?: (seo: ArticleSeoModel) => void;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Fetches and renders an article by `id` or `slug` via the `embedArticle` GraphQL query.
|
|
18
|
+
* Displays a placeholder when the article is not found.
|
|
19
|
+
*
|
|
20
|
+
* ### Props
|
|
21
|
+
* | Prop | Type | Description |
|
|
22
|
+
* |---|---|---|
|
|
23
|
+
* | `id` | `string?` | Article ID to fetch |
|
|
24
|
+
* | `slug` | `string?` | Article slug to fetch (alternative to `id`) |
|
|
25
|
+
* | `initiator` | `string?` | Value for the `x-initiator` header |
|
|
26
|
+
* | `graphqlOrigin` | `string?` | Custom GraphQL API origin |
|
|
27
|
+
*
|
|
28
|
+
* ### Callbacks (`on`)
|
|
29
|
+
* | Callback | Type | Description |
|
|
30
|
+
* |---|---|---|
|
|
31
|
+
* | `seoLoaded` | `(seo: ArticleSeoModel) => void` | Called after article is loaded with SEO data and cover image URL |
|
|
32
|
+
*
|
|
33
|
+
* ### CSS Custom Properties
|
|
34
|
+
* | Property | Description | Default |
|
|
35
|
+
* |---|---|---|
|
|
36
|
+
* | `--article--background` | Article background color | `white` / `dark-800` |
|
|
37
|
+
* | `--article--text-color` | Article text color | `black` / `white` |
|
|
38
|
+
* | `--article--min-height` | Minimum article height | `0` |
|
|
39
|
+
*/
|
|
40
|
+
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
41
|
+
type Cmp = ReturnType<typeof Cmp>;
|
|
42
|
+
export default Cmp;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Article, type ArticleSeoModel } from './cmp.embed-article.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Article } from './cmp.embed-article.svelte';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type * as SchemaTypes from '../../../gql/types';
|
|
2
|
+
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
3
|
+
export type GetEmbedArticleQueryVariables = SchemaTypes.Exact<{
|
|
4
|
+
input: SchemaTypes.EmbedArticleInput;
|
|
5
|
+
}>;
|
|
6
|
+
export type GetEmbedArticleQuery = {
|
|
7
|
+
article: {
|
|
8
|
+
id: string;
|
|
9
|
+
publishedAt: any | null;
|
|
10
|
+
seo: {
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
keywords: Array<string>;
|
|
14
|
+
};
|
|
15
|
+
sections: Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
facts: string | null;
|
|
18
|
+
styles: {
|
|
19
|
+
paddingTop: number | null;
|
|
20
|
+
paddingBottom: number | null;
|
|
21
|
+
paddingLeft: number | null;
|
|
22
|
+
paddingRight: number | null;
|
|
23
|
+
} | null;
|
|
24
|
+
layouts: Array<{
|
|
25
|
+
id: string;
|
|
26
|
+
styles: {
|
|
27
|
+
paddingTop: number | null;
|
|
28
|
+
paddingBottom: number | null;
|
|
29
|
+
paddingLeft: number | null;
|
|
30
|
+
paddingRight: number | null;
|
|
31
|
+
} | null;
|
|
32
|
+
fields: Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
description: string | null;
|
|
36
|
+
styles: {
|
|
37
|
+
marginTop: number | null;
|
|
38
|
+
marginBottom: number | null;
|
|
39
|
+
marginLeft: number | null;
|
|
40
|
+
marginRight: number | null;
|
|
41
|
+
} | null;
|
|
42
|
+
fieldData: {
|
|
43
|
+
type: SchemaTypes.ArticleFieldType;
|
|
44
|
+
bylineData: {
|
|
45
|
+
authorName: string | null;
|
|
46
|
+
} | null;
|
|
47
|
+
imageData: {
|
|
48
|
+
preferredMediaFormat: SchemaTypes.MediaFormat;
|
|
49
|
+
altText: string | null;
|
|
50
|
+
image: {
|
|
51
|
+
type: SchemaTypes.MediaType;
|
|
52
|
+
url: string;
|
|
53
|
+
thumbnailUrl: string | null;
|
|
54
|
+
} | null;
|
|
55
|
+
} | null;
|
|
56
|
+
mediaData: {
|
|
57
|
+
preferredMediaFormat: SchemaTypes.MediaFormat;
|
|
58
|
+
altText: string | null;
|
|
59
|
+
media: {
|
|
60
|
+
type: SchemaTypes.MediaType;
|
|
61
|
+
url: string;
|
|
62
|
+
thumbnailUrl: string | null;
|
|
63
|
+
} | null;
|
|
64
|
+
} | null;
|
|
65
|
+
mediaGalleryData: {
|
|
66
|
+
galleryMode: SchemaTypes.GalleryFieldMode;
|
|
67
|
+
preferredMediaFormat: SchemaTypes.MediaFormat;
|
|
68
|
+
altText: string | null;
|
|
69
|
+
media: Array<{
|
|
70
|
+
type: SchemaTypes.MediaType;
|
|
71
|
+
url: string;
|
|
72
|
+
thumbnailUrl: string | null;
|
|
73
|
+
metadata: {
|
|
74
|
+
width: number;
|
|
75
|
+
height: number;
|
|
76
|
+
};
|
|
77
|
+
}> | null;
|
|
78
|
+
} | null;
|
|
79
|
+
richTextData: {
|
|
80
|
+
text: string | null;
|
|
81
|
+
textSize: number;
|
|
82
|
+
} | null;
|
|
83
|
+
textData: {
|
|
84
|
+
text: string | null;
|
|
85
|
+
textMode: SchemaTypes.TextFieldMode;
|
|
86
|
+
textSize: number;
|
|
87
|
+
textWeight: SchemaTypes.TextFieldWeight;
|
|
88
|
+
} | null;
|
|
89
|
+
videoData: {
|
|
90
|
+
preferredMediaFormat: SchemaTypes.MediaFormat;
|
|
91
|
+
altText: string | null;
|
|
92
|
+
video: {
|
|
93
|
+
type: SchemaTypes.MediaType;
|
|
94
|
+
url: string;
|
|
95
|
+
thumbnailUrl: string | null;
|
|
96
|
+
} | null;
|
|
97
|
+
} | null;
|
|
98
|
+
};
|
|
99
|
+
}>;
|
|
100
|
+
}>;
|
|
101
|
+
}>;
|
|
102
|
+
} | null;
|
|
103
|
+
};
|
|
104
|
+
export declare const GetEmbedArticleDocument: DocumentNode<GetEmbedArticleQuery, GetEmbedArticleQueryVariables>;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
export const GetEmbedArticleDocument = {
|
|
2
|
+
kind: 'Document',
|
|
3
|
+
definitions: [
|
|
4
|
+
{
|
|
5
|
+
kind: 'OperationDefinition',
|
|
6
|
+
operation: 'query',
|
|
7
|
+
name: { kind: 'Name', value: 'GetEmbedArticle' },
|
|
8
|
+
variableDefinitions: [
|
|
9
|
+
{
|
|
10
|
+
kind: 'VariableDefinition',
|
|
11
|
+
variable: { kind: 'Variable', name: { kind: 'Name', value: 'input' } },
|
|
12
|
+
type: { kind: 'NonNullType', type: { kind: 'NamedType', name: { kind: 'Name', value: 'EmbedArticleInput' } } }
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
selectionSet: {
|
|
16
|
+
kind: 'SelectionSet',
|
|
17
|
+
selections: [
|
|
18
|
+
{
|
|
19
|
+
kind: 'Field',
|
|
20
|
+
alias: { kind: 'Name', value: 'article' },
|
|
21
|
+
name: { kind: 'Name', value: 'embedArticle' },
|
|
22
|
+
arguments: [{ kind: 'Argument', name: { kind: 'Name', value: 'input' }, value: { kind: 'Variable', name: { kind: 'Name', value: 'input' } } }],
|
|
23
|
+
selectionSet: {
|
|
24
|
+
kind: 'SelectionSet',
|
|
25
|
+
selections: [
|
|
26
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
|
27
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'publishedAt' } },
|
|
28
|
+
{
|
|
29
|
+
kind: 'Field',
|
|
30
|
+
name: { kind: 'Name', value: 'seo' },
|
|
31
|
+
selectionSet: {
|
|
32
|
+
kind: 'SelectionSet',
|
|
33
|
+
selections: [
|
|
34
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'title' } },
|
|
35
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'description' } },
|
|
36
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'keywords' } }
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
kind: 'Field',
|
|
42
|
+
name: { kind: 'Name', value: 'sections' },
|
|
43
|
+
selectionSet: {
|
|
44
|
+
kind: 'SelectionSet',
|
|
45
|
+
selections: [
|
|
46
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
|
47
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'facts' } },
|
|
48
|
+
{
|
|
49
|
+
kind: 'Field',
|
|
50
|
+
name: { kind: 'Name', value: 'styles' },
|
|
51
|
+
selectionSet: {
|
|
52
|
+
kind: 'SelectionSet',
|
|
53
|
+
selections: [
|
|
54
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingTop' } },
|
|
55
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingBottom' } },
|
|
56
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingLeft' } },
|
|
57
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingRight' } }
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
kind: 'Field',
|
|
63
|
+
name: { kind: 'Name', value: 'layouts' },
|
|
64
|
+
selectionSet: {
|
|
65
|
+
kind: 'SelectionSet',
|
|
66
|
+
selections: [
|
|
67
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
|
68
|
+
{
|
|
69
|
+
kind: 'Field',
|
|
70
|
+
name: { kind: 'Name', value: 'styles' },
|
|
71
|
+
selectionSet: {
|
|
72
|
+
kind: 'SelectionSet',
|
|
73
|
+
selections: [
|
|
74
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingTop' } },
|
|
75
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingBottom' } },
|
|
76
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingLeft' } },
|
|
77
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'paddingRight' } }
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
kind: 'Field',
|
|
83
|
+
name: { kind: 'Name', value: 'fields' },
|
|
84
|
+
selectionSet: {
|
|
85
|
+
kind: 'SelectionSet',
|
|
86
|
+
selections: [
|
|
87
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
|
88
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
|
89
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'description' } },
|
|
90
|
+
{
|
|
91
|
+
kind: 'Field',
|
|
92
|
+
name: { kind: 'Name', value: 'styles' },
|
|
93
|
+
selectionSet: {
|
|
94
|
+
kind: 'SelectionSet',
|
|
95
|
+
selections: [
|
|
96
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'marginTop' } },
|
|
97
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'marginBottom' } },
|
|
98
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'marginLeft' } },
|
|
99
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'marginRight' } }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
kind: 'Field',
|
|
105
|
+
name: { kind: 'Name', value: 'fieldData' },
|
|
106
|
+
selectionSet: {
|
|
107
|
+
kind: 'SelectionSet',
|
|
108
|
+
selections: [
|
|
109
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'type' } },
|
|
110
|
+
{
|
|
111
|
+
kind: 'Field',
|
|
112
|
+
name: { kind: 'Name', value: 'bylineData' },
|
|
113
|
+
selectionSet: { kind: 'SelectionSet', selections: [{ kind: 'Field', name: { kind: 'Name', value: 'authorName' } }] }
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
kind: 'Field',
|
|
117
|
+
name: { kind: 'Name', value: 'imageData' },
|
|
118
|
+
selectionSet: {
|
|
119
|
+
kind: 'SelectionSet',
|
|
120
|
+
selections: [
|
|
121
|
+
{
|
|
122
|
+
kind: 'Field',
|
|
123
|
+
name: { kind: 'Name', value: 'image' },
|
|
124
|
+
selectionSet: {
|
|
125
|
+
kind: 'SelectionSet',
|
|
126
|
+
selections: [
|
|
127
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'type' } },
|
|
128
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'url' } },
|
|
129
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'thumbnailUrl' } }
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'preferredMediaFormat' } },
|
|
134
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'altText' } }
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
kind: 'Field',
|
|
140
|
+
name: { kind: 'Name', value: 'mediaData' },
|
|
141
|
+
selectionSet: {
|
|
142
|
+
kind: 'SelectionSet',
|
|
143
|
+
selections: [
|
|
144
|
+
{
|
|
145
|
+
kind: 'Field',
|
|
146
|
+
name: { kind: 'Name', value: 'media' },
|
|
147
|
+
selectionSet: {
|
|
148
|
+
kind: 'SelectionSet',
|
|
149
|
+
selections: [
|
|
150
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'type' } },
|
|
151
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'url' } },
|
|
152
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'thumbnailUrl' } }
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'preferredMediaFormat' } },
|
|
157
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'altText' } }
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
kind: 'Field',
|
|
163
|
+
name: { kind: 'Name', value: 'mediaGalleryData' },
|
|
164
|
+
selectionSet: {
|
|
165
|
+
kind: 'SelectionSet',
|
|
166
|
+
selections: [
|
|
167
|
+
{
|
|
168
|
+
kind: 'Field',
|
|
169
|
+
name: { kind: 'Name', value: 'media' },
|
|
170
|
+
selectionSet: {
|
|
171
|
+
kind: 'SelectionSet',
|
|
172
|
+
selections: [
|
|
173
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'type' } },
|
|
174
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'url' } },
|
|
175
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'thumbnailUrl' } },
|
|
176
|
+
{
|
|
177
|
+
kind: 'Field',
|
|
178
|
+
name: { kind: 'Name', value: 'metadata' },
|
|
179
|
+
selectionSet: {
|
|
180
|
+
kind: 'SelectionSet',
|
|
181
|
+
selections: [
|
|
182
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'width' } },
|
|
183
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'height' } }
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'galleryMode' } },
|
|
191
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'preferredMediaFormat' } },
|
|
192
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'altText' } }
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
kind: 'Field',
|
|
198
|
+
name: { kind: 'Name', value: 'richTextData' },
|
|
199
|
+
selectionSet: {
|
|
200
|
+
kind: 'SelectionSet',
|
|
201
|
+
selections: [
|
|
202
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'text' } },
|
|
203
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'textSize' } }
|
|
204
|
+
]
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
kind: 'Field',
|
|
209
|
+
name: { kind: 'Name', value: 'textData' },
|
|
210
|
+
selectionSet: {
|
|
211
|
+
kind: 'SelectionSet',
|
|
212
|
+
selections: [
|
|
213
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'text' } },
|
|
214
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'textMode' } },
|
|
215
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'textSize' } },
|
|
216
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'textWeight' } }
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
kind: 'Field',
|
|
222
|
+
name: { kind: 'Name', value: 'videoData' },
|
|
223
|
+
selectionSet: {
|
|
224
|
+
kind: 'SelectionSet',
|
|
225
|
+
selections: [
|
|
226
|
+
{
|
|
227
|
+
kind: 'Field',
|
|
228
|
+
name: { kind: 'Name', value: 'video' },
|
|
229
|
+
selectionSet: {
|
|
230
|
+
kind: 'SelectionSet',
|
|
231
|
+
selections: [
|
|
232
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'type' } },
|
|
233
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'url' } },
|
|
234
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'thumbnailUrl' } }
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'preferredMediaFormat' } },
|
|
239
|
+
{ kind: 'Field', name: { kind: 'Name', value: 'altText' } }
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# noinspection GraphQLSchemaValidation
|
|
2
|
+
query GetEmbedArticle($input: EmbedArticleInput!) {
|
|
3
|
+
article: embedArticle(input: $input) {
|
|
4
|
+
id
|
|
5
|
+
publishedAt
|
|
6
|
+
seo {
|
|
7
|
+
title
|
|
8
|
+
description
|
|
9
|
+
keywords
|
|
10
|
+
}
|
|
11
|
+
sections {
|
|
12
|
+
id
|
|
13
|
+
facts
|
|
14
|
+
styles {
|
|
15
|
+
paddingTop
|
|
16
|
+
paddingBottom
|
|
17
|
+
paddingLeft
|
|
18
|
+
paddingRight
|
|
19
|
+
}
|
|
20
|
+
layouts {
|
|
21
|
+
id
|
|
22
|
+
styles {
|
|
23
|
+
paddingTop
|
|
24
|
+
paddingBottom
|
|
25
|
+
paddingLeft
|
|
26
|
+
paddingRight
|
|
27
|
+
}
|
|
28
|
+
fields {
|
|
29
|
+
id
|
|
30
|
+
name
|
|
31
|
+
description
|
|
32
|
+
styles {
|
|
33
|
+
marginTop
|
|
34
|
+
marginBottom
|
|
35
|
+
marginLeft
|
|
36
|
+
marginRight
|
|
37
|
+
}
|
|
38
|
+
fieldData {
|
|
39
|
+
type
|
|
40
|
+
bylineData {
|
|
41
|
+
authorName
|
|
42
|
+
}
|
|
43
|
+
imageData {
|
|
44
|
+
image {
|
|
45
|
+
type
|
|
46
|
+
url
|
|
47
|
+
thumbnailUrl
|
|
48
|
+
}
|
|
49
|
+
preferredMediaFormat
|
|
50
|
+
altText
|
|
51
|
+
}
|
|
52
|
+
mediaData {
|
|
53
|
+
media {
|
|
54
|
+
type
|
|
55
|
+
url
|
|
56
|
+
thumbnailUrl
|
|
57
|
+
}
|
|
58
|
+
preferredMediaFormat
|
|
59
|
+
altText
|
|
60
|
+
}
|
|
61
|
+
mediaGalleryData {
|
|
62
|
+
media {
|
|
63
|
+
type
|
|
64
|
+
url
|
|
65
|
+
thumbnailUrl
|
|
66
|
+
metadata {
|
|
67
|
+
width
|
|
68
|
+
height
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
galleryMode
|
|
72
|
+
preferredMediaFormat
|
|
73
|
+
altText
|
|
74
|
+
}
|
|
75
|
+
richTextData {
|
|
76
|
+
text
|
|
77
|
+
textSize
|
|
78
|
+
}
|
|
79
|
+
textData {
|
|
80
|
+
text
|
|
81
|
+
textMode
|
|
82
|
+
textSize
|
|
83
|
+
textWeight
|
|
84
|
+
}
|
|
85
|
+
videoData {
|
|
86
|
+
video {
|
|
87
|
+
type
|
|
88
|
+
url
|
|
89
|
+
thumbnailUrl
|
|
90
|
+
}
|
|
91
|
+
preferredMediaFormat
|
|
92
|
+
altText
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -13,7 +13,7 @@ export class InternalMediaCenterDataProvider {
|
|
|
13
13
|
graphql;
|
|
14
14
|
constructor(input) {
|
|
15
15
|
const { mediaPageId, graphqlOrigin, initiator, testingStuff, onNavigationStateChange } = input;
|
|
16
|
-
this.graphql = createLocalGQLClient(graphqlOrigin,
|
|
16
|
+
this.graphql = createLocalGQLClient(graphqlOrigin, { initiator });
|
|
17
17
|
this.fetchModel = async () => {
|
|
18
18
|
const payload = await this.graphql.query(GetMediaPageConfigDocument, { mediaPageId }).toPromise();
|
|
19
19
|
if (!payload.data?.embedMediaPage) {
|
|
@@ -37,7 +37,7 @@ export class InternalShortVideoPlayerItemsProvider {
|
|
|
37
37
|
});
|
|
38
38
|
constructor(input) {
|
|
39
39
|
const { ids, graphqlOrigin, initiator, initialId } = input;
|
|
40
|
-
this.graphql = createLocalGQLClient(graphqlOrigin,
|
|
40
|
+
this.graphql = createLocalGQLClient(graphqlOrigin, { initiator });
|
|
41
41
|
this.ids = ids;
|
|
42
42
|
ids.forEach((id, idx) => this.idOrder.set(id, idx));
|
|
43
43
|
const startIndex = initialId ? ids.indexOf(initialId) : 0;
|
|
@@ -36,7 +36,7 @@ export class InternalStreamsPlayerDataProvider {
|
|
|
36
36
|
});
|
|
37
37
|
constructor(input) {
|
|
38
38
|
const { ids, initialId, graphqlOrigin, initiator } = input;
|
|
39
|
-
this.graphql = createLocalGQLClient(graphqlOrigin,
|
|
39
|
+
this.graphql = createLocalGQLClient(graphqlOrigin, { initiator });
|
|
40
40
|
this.ids = ids;
|
|
41
41
|
if (initialId && this.ids.includes(initialId)) {
|
|
42
42
|
this.ids = [initialId, ...this.ids.filter((id) => id !== initialId)];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { Article, type ArticleSeoModel } from './article';
|
|
1
2
|
export { openMediaPageModal } from './media-page';
|
|
2
|
-
export { openStreamsPlayer } from './streams-player';
|
|
3
3
|
export { openShortVideosPlayer } from './short-videos-player';
|
|
4
|
+
export { openStreamsPlayer } from './streams-player';
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
<script lang="ts">import { getMediaItemImageUrl } from '../types';
|
|
2
2
|
import IconDelete from '@fluentui/svg-icons/icons/delete_20_regular.svg?raw';
|
|
3
3
|
import IconEdit from '@fluentui/svg-icons/icons/edit_20_regular.svg?raw';
|
|
4
|
-
import {
|
|
4
|
+
import { cardActionContainer, CardActions } from '@streamscloud/kit/ui/card-actions';
|
|
5
5
|
import { Image } from '@streamscloud/kit/ui/image';
|
|
6
6
|
import { ProportionalContainer } from '@streamscloud/kit/ui/proportional-container';
|
|
7
7
|
import { Video } from '@streamscloud/kit/ui/video';
|
|
8
8
|
let { media, ratio = 0, inert = false, on } = $props();
|
|
9
|
-
const
|
|
9
|
+
const actions = $derived.by(() => {
|
|
10
|
+
const result = [];
|
|
11
|
+
if (on?.edit) {
|
|
12
|
+
result.push({ icon: IconEdit, iconColor: 'blue', callback: on.edit });
|
|
13
|
+
}
|
|
14
|
+
if (on?.remove) {
|
|
15
|
+
result.push({ icon: IconDelete, iconColor: 'red', callback: on.remove });
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
});
|
|
10
19
|
const handleClick = (e) => {
|
|
11
20
|
if (on?.click) {
|
|
12
21
|
e.stopPropagation();
|
|
13
22
|
on.click();
|
|
14
23
|
}
|
|
15
24
|
};
|
|
16
|
-
const handleEdit = (e) => {
|
|
17
|
-
e.stopPropagation();
|
|
18
|
-
on?.edit?.();
|
|
19
|
-
};
|
|
20
|
-
const handleRemove = (e) => {
|
|
21
|
-
e.stopPropagation();
|
|
22
|
-
on?.remove?.();
|
|
23
|
-
};
|
|
24
25
|
const parsedRatio = $derived.by(() => {
|
|
25
26
|
if (!ratio || ratio === 'fit-parent') {
|
|
26
27
|
return 0;
|
|
@@ -49,7 +50,12 @@ const parsedRatio = $derived.by(() => {
|
|
|
49
50
|
{/if}
|
|
50
51
|
{/snippet}
|
|
51
52
|
|
|
52
|
-
<div
|
|
53
|
+
<div
|
|
54
|
+
class="media-item-view"
|
|
55
|
+
class:media-item-view--clickable={on?.click}
|
|
56
|
+
class:media-item-view--fit-parent={ratio === 'fit-parent'}
|
|
57
|
+
use:cardActionContainer
|
|
58
|
+
inert={inert}>
|
|
53
59
|
{#if parsedRatio}
|
|
54
60
|
<ProportionalContainer ratio={parsedRatio}>
|
|
55
61
|
{@render mediaView()}
|
|
@@ -57,20 +63,7 @@ const parsedRatio = $derived.by(() => {
|
|
|
57
63
|
{:else}
|
|
58
64
|
{@render mediaView()}
|
|
59
65
|
{/if}
|
|
60
|
-
{
|
|
61
|
-
<div class="media-item-view__actions">
|
|
62
|
-
{#if on?.edit}
|
|
63
|
-
<button type="button" class="media-item-view__action" onclick={handleEdit} aria-label="edit">
|
|
64
|
-
<Icon src={IconEdit} />
|
|
65
|
-
</button>
|
|
66
|
-
{/if}
|
|
67
|
-
{#if on?.remove}
|
|
68
|
-
<button type="button" class="media-item-view__action" onclick={handleRemove} aria-label="remove">
|
|
69
|
-
<Icon src={IconDelete} />
|
|
70
|
-
</button>
|
|
71
|
-
{/if}
|
|
72
|
-
</div>
|
|
73
|
-
{/if}
|
|
66
|
+
<CardActions actions={actions} />
|
|
74
67
|
</div>
|
|
75
68
|
{/if}
|
|
76
69
|
|
|
@@ -100,28 +93,6 @@ const parsedRatio = $derived.by(() => {
|
|
|
100
93
|
height: 100%;
|
|
101
94
|
cursor: pointer;
|
|
102
95
|
}
|
|
103
|
-
.media-item-view__actions {
|
|
104
|
-
position: absolute;
|
|
105
|
-
top: 0.3125rem;
|
|
106
|
-
right: 0.3125rem;
|
|
107
|
-
opacity: 0;
|
|
108
|
-
transition: opacity ease-in-out 0.6s;
|
|
109
|
-
display: flex;
|
|
110
|
-
padding: 0 0.3125rem;
|
|
111
|
-
background: light-dark(#f2f2f3, #111827);
|
|
112
|
-
border-radius: 0.1875rem;
|
|
113
|
-
--sc-kit--icon--color: light-dark(#1f2937, #ffffff);
|
|
114
|
-
}
|
|
115
|
-
.media-item-view__action {
|
|
116
|
-
padding: 0.3125rem;
|
|
117
|
-
transition: transform 0.3s;
|
|
118
|
-
}
|
|
119
|
-
.media-item-view__action:hover {
|
|
120
|
-
transform: scale(1.2);
|
|
121
|
-
}
|
|
122
96
|
.media-item-view--clickable {
|
|
123
97
|
cursor: pointer;
|
|
124
|
-
}
|
|
125
|
-
.media-item-view:hover .media-item-view__actions {
|
|
126
|
-
opacity: 1;
|
|
127
98
|
}</style>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamscloud/embeddable",
|
|
3
|
-
"version": "16.0.7-
|
|
3
|
+
"version": "16.0.7-1772056193230",
|
|
4
4
|
"author": "StreamsCloud",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,10 +38,6 @@
|
|
|
38
38
|
"types": "./dist/articles/article/index.d.ts",
|
|
39
39
|
"svelte": "./dist/articles/article/index.js"
|
|
40
40
|
},
|
|
41
|
-
"./article-viewer": {
|
|
42
|
-
"types": "./dist/articles/article-viewer/index.d.ts",
|
|
43
|
-
"svelte": "./dist/articles/article-viewer/index.js"
|
|
44
|
-
},
|
|
45
41
|
"./external-api": {
|
|
46
42
|
"types": "./dist/external-api/index.d.ts",
|
|
47
43
|
"svelte": "./dist/external-api/index.js"
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ThemeValue } from '../../core/theme';
|
|
2
|
-
import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
|
|
3
|
-
export declare class ArticleViewerHostSettings {
|
|
4
|
-
locale: AppLocaleValue | undefined;
|
|
5
|
-
theme: ThemeValue | undefined;
|
|
6
|
-
constructor(init: {
|
|
7
|
-
locale?: AppLocaleValue;
|
|
8
|
-
theme?: ThemeValue;
|
|
9
|
-
} | undefined);
|
|
10
|
-
update: (data: {
|
|
11
|
-
locale?: AppLocaleValue;
|
|
12
|
-
theme?: ThemeValue;
|
|
13
|
-
} | undefined) => void;
|
|
14
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<script lang="ts">import {} from '../../ui/player/close-orchestrator';
|
|
2
|
-
import { ShadowRoot } from '../../ui/shadow-dom';
|
|
3
|
-
import ArticleViewerView from './article-viewer-view.svelte';
|
|
4
|
-
let { data, closeOrchestrator, viewerSettings } = $props();
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
|
-
<ShadowRoot locale={viewerSettings?.locale} theme={viewerSettings?.theme ?? 'light'} backgroundDisabled={true} backgroundImageUrl="not-applicable">
|
|
8
|
-
<ArticleViewerView data={data} closeOrchestrator={closeOrchestrator} />
|
|
9
|
-
</ShadowRoot>
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type ICloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
2
|
-
import type { ArticleViewerModel, ArticleViewerSettings } from './types';
|
|
3
|
-
type Props = {
|
|
4
|
-
data: ArticleViewerModel;
|
|
5
|
-
closeOrchestrator: ICloseOrchestrator;
|
|
6
|
-
viewerSettings?: ArticleViewerSettings;
|
|
7
|
-
};
|
|
8
|
-
declare const ArticleViewerProxy: import("svelte").Component<Props, {}, "">;
|
|
9
|
-
type ArticleViewerProxy = ReturnType<typeof ArticleViewerProxy>;
|
|
10
|
-
export default ArticleViewerProxy;
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
<script lang="ts">import { Article } from '../article';
|
|
2
|
-
import {} from '../../ui/player/close-orchestrator';
|
|
3
|
-
let { data, closeOrchestrator } = $props();
|
|
4
|
-
const handleCloseClick = () => {
|
|
5
|
-
closeOrchestrator.requestClose();
|
|
6
|
-
};
|
|
7
|
-
const handleKeydown = (event) => {
|
|
8
|
-
if (event.key === 'Escape' && closeOrchestrator.closeTriggerVisible) {
|
|
9
|
-
closeOrchestrator.requestClose();
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<svelte:window onkeydown={handleKeydown} />
|
|
15
|
-
|
|
16
|
-
<div class="article-viewer">
|
|
17
|
-
{#if closeOrchestrator.closeTriggerVisible}
|
|
18
|
-
<button type="button" class="article-viewer__close" aria-label="Close" onclick={handleCloseClick}>
|
|
19
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
|
20
|
-
<path
|
|
21
|
-
d="M4.397 4.554l.073-.084a.75.75 0 01.976-.073l.084.073L12 10.939l6.47-6.47a.75.75 0 111.06 1.061L13.061 12l6.47 6.47a.75.75 0 01.072.976l-.073.084a.75.75 0 01-.976.073l-.084-.073L12 13.061l-6.47 6.47a.75.75 0 01-1.06-1.061L10.939 12l-6.47-6.47a.75.75 0 01-.072-.976l.073-.084-.073.084z"
|
|
22
|
-
></path>
|
|
23
|
-
</svg>
|
|
24
|
-
</button>
|
|
25
|
-
{/if}
|
|
26
|
-
<div class="article-viewer__content">
|
|
27
|
-
<Article sections={data.sections} metadata={data.metadata} />
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<style>.article-viewer {
|
|
32
|
-
width: 100%;
|
|
33
|
-
min-width: 100%;
|
|
34
|
-
max-width: 100%;
|
|
35
|
-
height: 100%;
|
|
36
|
-
min-height: 100%;
|
|
37
|
-
max-height: 100%;
|
|
38
|
-
position: relative;
|
|
39
|
-
display: flex;
|
|
40
|
-
flex-direction: column;
|
|
41
|
-
}
|
|
42
|
-
.article-viewer__close {
|
|
43
|
-
position: absolute;
|
|
44
|
-
top: 0.75rem;
|
|
45
|
-
right: 0.75rem;
|
|
46
|
-
z-index: 10;
|
|
47
|
-
display: flex;
|
|
48
|
-
align-items: center;
|
|
49
|
-
justify-content: center;
|
|
50
|
-
width: 2.25rem;
|
|
51
|
-
height: 2.25rem;
|
|
52
|
-
border-radius: 50%;
|
|
53
|
-
border: none;
|
|
54
|
-
background: rgba(0, 0, 0, 0.4);
|
|
55
|
-
color: white;
|
|
56
|
-
cursor: pointer;
|
|
57
|
-
padding: 0;
|
|
58
|
-
}
|
|
59
|
-
.article-viewer__close:hover {
|
|
60
|
-
background: rgba(0, 0, 0, 0.6);
|
|
61
|
-
}
|
|
62
|
-
.article-viewer__content {
|
|
63
|
-
flex: 1;
|
|
64
|
-
overflow-y: auto;
|
|
65
|
-
--_cross-browser-scrollbar--thumb-color: var(--scrollbar--thumb-color, #7d7d7d);
|
|
66
|
-
--_cross-browser-scrollbar--track-color: var(--scrollbar--track-color, transparent);
|
|
67
|
-
}
|
|
68
|
-
.article-viewer__content::-webkit-scrollbar {
|
|
69
|
-
width: 6px;
|
|
70
|
-
height: 6px;
|
|
71
|
-
}
|
|
72
|
-
.article-viewer__content::-webkit-scrollbar-track {
|
|
73
|
-
background: var(--_cross-browser-scrollbar--track-color);
|
|
74
|
-
border-radius: 100vw;
|
|
75
|
-
}
|
|
76
|
-
.article-viewer__content::-webkit-scrollbar-thumb {
|
|
77
|
-
background: var(--_cross-browser-scrollbar--thumb-color);
|
|
78
|
-
border-radius: 100vw;
|
|
79
|
-
}
|
|
80
|
-
@supports (scrollbar-color: transparent transparent) {
|
|
81
|
-
.article-viewer__content {
|
|
82
|
-
scrollbar-color: var(--_cross-browser-scrollbar--thumb-color) var(--_cross-browser-scrollbar--track-color);
|
|
83
|
-
scrollbar-width: thin;
|
|
84
|
-
}
|
|
85
|
-
}</style>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type ICloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
2
|
-
import type { ArticleViewerModel } from './types';
|
|
3
|
-
type Props = {
|
|
4
|
-
data: ArticleViewerModel;
|
|
5
|
-
closeOrchestrator: ICloseOrchestrator;
|
|
6
|
-
};
|
|
7
|
-
declare const ArticleViewerView: import("svelte").Component<Props, {}, "">;
|
|
8
|
-
type ArticleViewerView = ReturnType<typeof ArticleViewerView>;
|
|
9
|
-
export default ArticleViewerView;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
<script lang="ts">import { CloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
2
|
-
import { createShadowRoot } from '../../ui/shadow-dom';
|
|
3
|
-
import { ArticleViewerHostSettings } from './article-viewer-host-settings.svelte';
|
|
4
|
-
import ArticleViewerProxy from './article-viewer-proxy.svelte';
|
|
5
|
-
import { mount, unmount, untrack } from 'svelte';
|
|
6
|
-
let { data, viewerSettings } = $props();
|
|
7
|
-
const settingsHolder = untrack(() => new ArticleViewerHostSettings(viewerSettings));
|
|
8
|
-
$effect(() => {
|
|
9
|
-
settingsHolder.update(viewerSettings);
|
|
10
|
-
});
|
|
11
|
-
const initHost = (node) => {
|
|
12
|
-
const shadowRoot = createShadowRoot(node);
|
|
13
|
-
const mounted = mount(ArticleViewerProxy, {
|
|
14
|
-
target: shadowRoot,
|
|
15
|
-
props: {
|
|
16
|
-
data,
|
|
17
|
-
viewerSettings: settingsHolder,
|
|
18
|
-
closeOrchestrator: new CloseOrchestrator({
|
|
19
|
-
closeFn: async () => {
|
|
20
|
-
await unmount(mounted);
|
|
21
|
-
},
|
|
22
|
-
canClose: false
|
|
23
|
-
})
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
return {
|
|
27
|
-
destroy: () => {
|
|
28
|
-
unmount(mounted);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
</script>
|
|
33
|
-
|
|
34
|
-
<div class="article-viewer-host" use:initHost></div>
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ArticleViewerModel } from './types';
|
|
2
|
-
import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
|
|
3
|
-
type Props = {
|
|
4
|
-
data: ArticleViewerModel;
|
|
5
|
-
viewerSettings?: {
|
|
6
|
-
locale?: AppLocaleValue;
|
|
7
|
-
theme?: 'light' | 'dark';
|
|
8
|
-
};
|
|
9
|
-
};
|
|
10
|
-
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
11
|
-
type Cmp = ReturnType<typeof Cmp>;
|
|
12
|
-
export default Cmp;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { ArticleViewerModel, ArticleViewerSettings } from './types';
|
|
2
|
-
export { default as ArticleViewer } from './cmp.article-viewer.svelte';
|
|
3
|
-
export type { ArticleViewerModel, ArticleViewerSettings } from './types';
|
|
4
|
-
/**
|
|
5
|
-
* Opens the article viewer as a full-screen modal.
|
|
6
|
-
*
|
|
7
|
-
* @param init Configuration options for the article viewer.
|
|
8
|
-
*
|
|
9
|
-
* @param {ArticleViewerModel} init.data
|
|
10
|
-
* Article data containing sections and metadata.
|
|
11
|
-
*
|
|
12
|
-
* @param {ArticleViewerSettings} [init.viewerSettings]
|
|
13
|
-
* Viewer UI settings.
|
|
14
|
-
* - {'en'|'no'} [locale='en'] — Localization for the viewer UI.
|
|
15
|
-
* - {'light'|'dark'} [theme='light'] — Theme for the viewer UI.
|
|
16
|
-
* - {boolean} [hideCloseButton] — If true, hides the close button.
|
|
17
|
-
*
|
|
18
|
-
* @param {{ closed?: () => void }} [init.on]
|
|
19
|
-
* Optional event handlers.
|
|
20
|
-
* @param {() => void} [init.on.closed]
|
|
21
|
-
* Called after the viewer is fully closed.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* import { openArticleViewer } from '@streamscloud/embeddable/article-viewer';
|
|
26
|
-
*
|
|
27
|
-
* openArticleViewer({
|
|
28
|
-
* data: {
|
|
29
|
-
* sections: articleSections,
|
|
30
|
-
* metadata: { displayDate: '2026-02-25' }
|
|
31
|
-
* },
|
|
32
|
-
* viewerSettings: { locale: 'en', theme: 'light' },
|
|
33
|
-
* on: { closed: () => console.log('Viewer closed') }
|
|
34
|
-
* });
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export declare const openArticleViewer: (init: {
|
|
38
|
-
data: ArticleViewerModel;
|
|
39
|
-
viewerSettings?: ArticleViewerSettings;
|
|
40
|
-
on?: {
|
|
41
|
-
closed?: () => void;
|
|
42
|
-
};
|
|
43
|
-
}) => void;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { CloseOrchestrator } from '../../ui/player/close-orchestrator';
|
|
2
|
-
import { ModalShadowHost } from '../../ui/shadow-dom';
|
|
3
|
-
import ArticleViewerProxy from './article-viewer-proxy.svelte';
|
|
4
|
-
import { mount, unmount } from 'svelte';
|
|
5
|
-
export { default as ArticleViewer } from './cmp.article-viewer.svelte';
|
|
6
|
-
/**
|
|
7
|
-
* Opens the article viewer as a full-screen modal.
|
|
8
|
-
*
|
|
9
|
-
* @param init Configuration options for the article viewer.
|
|
10
|
-
*
|
|
11
|
-
* @param {ArticleViewerModel} init.data
|
|
12
|
-
* Article data containing sections and metadata.
|
|
13
|
-
*
|
|
14
|
-
* @param {ArticleViewerSettings} [init.viewerSettings]
|
|
15
|
-
* Viewer UI settings.
|
|
16
|
-
* - {'en'|'no'} [locale='en'] — Localization for the viewer UI.
|
|
17
|
-
* - {'light'|'dark'} [theme='light'] — Theme for the viewer UI.
|
|
18
|
-
* - {boolean} [hideCloseButton] — If true, hides the close button.
|
|
19
|
-
*
|
|
20
|
-
* @param {{ closed?: () => void }} [init.on]
|
|
21
|
-
* Optional event handlers.
|
|
22
|
-
* @param {() => void} [init.on.closed]
|
|
23
|
-
* Called after the viewer is fully closed.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```ts
|
|
27
|
-
* import { openArticleViewer } from '@streamscloud/embeddable/article-viewer';
|
|
28
|
-
*
|
|
29
|
-
* openArticleViewer({
|
|
30
|
-
* data: {
|
|
31
|
-
* sections: articleSections,
|
|
32
|
-
* metadata: { displayDate: '2026-02-25' }
|
|
33
|
-
* },
|
|
34
|
-
* viewerSettings: { locale: 'en', theme: 'light' },
|
|
35
|
-
* on: { closed: () => console.log('Viewer closed') }
|
|
36
|
-
* });
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export const openArticleViewer = (init) => {
|
|
40
|
-
const { data, viewerSettings, on } = init;
|
|
41
|
-
const shadowHost = new ModalShadowHost();
|
|
42
|
-
let mounted = null;
|
|
43
|
-
const closeOrchestrator = new CloseOrchestrator({
|
|
44
|
-
closeFn: async () => {
|
|
45
|
-
await unmount(mounted);
|
|
46
|
-
shadowHost.remove();
|
|
47
|
-
on?.closed?.();
|
|
48
|
-
},
|
|
49
|
-
canClose: !viewerSettings?.hideCloseButton
|
|
50
|
-
});
|
|
51
|
-
mounted = mount(ArticleViewerProxy, {
|
|
52
|
-
target: shadowHost.shadowRoot,
|
|
53
|
-
props: {
|
|
54
|
-
data,
|
|
55
|
-
viewerSettings,
|
|
56
|
-
closeOrchestrator
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
shadowHost.attachToBody();
|
|
60
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ArticleMetadata, ArticleSectionModel } from '../article';
|
|
2
|
-
import type { ThemeValue } from '../../core/theme';
|
|
3
|
-
import type { AppLocaleValue } from '@streamscloud/kit/core/locale';
|
|
4
|
-
export type ArticleViewerModel = {
|
|
5
|
-
sections: ArticleSectionModel[];
|
|
6
|
-
metadata: ArticleMetadata;
|
|
7
|
-
};
|
|
8
|
-
export type ArticleViewerSettings = {
|
|
9
|
-
locale?: AppLocaleValue;
|
|
10
|
-
theme?: ThemeValue;
|
|
11
|
-
hideCloseButton?: boolean;
|
|
12
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|