@ndla/ui 36.0.2 → 37.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/Article/Article.js +7 -13
- package/es/Article/ArticleByline.js +79 -123
- package/es/Article/ArticleFootNotes.js +16 -11
- package/es/AudioPlayer/AudioPlayer.js +33 -35
- package/es/AudioPlayer/initAudioPlayers.js +6 -1
- package/es/ContentTypeBadge/ContentTypeBadge.js +27 -6
- package/es/Embed/AudioEmbed.js +44 -188
- package/es/Embed/BrightcoveEmbed.js +32 -127
- package/es/Embed/ConceptEmbed.js +53 -75
- package/es/Embed/EmbedErrorPlaceholder.js +41 -0
- package/es/Embed/ExternalEmbed.js +5 -12
- package/es/Embed/H5pEmbed.js +5 -15
- package/es/Embed/IframeEmbed.js +4 -4
- package/es/Embed/ImageEmbed.js +41 -153
- package/es/Embed/RelatedContentEmbed.js +3 -3
- package/es/Embed/conceptComponents.js +62 -228
- package/es/Embed/types.js +1 -0
- package/es/KeyFigure/KeyFigure.js +57 -0
- package/es/{KeyPerformanceIndicator → KeyFigure}/index.js +1 -1
- package/es/LicenseByline/EmbedByline.js +33 -8
- package/es/LicenseByline/LicenseDescription.js +16 -14
- package/es/List/OrderedList.js +48 -0
- package/es/List/UnOrderedList.js +36 -0
- package/es/List/index.js +10 -0
- package/es/Navigation/NavigationBox.js +41 -48
- package/es/Navigation/NavigationHeading.js +18 -29
- package/es/Notion/Notion.js +5 -5
- package/es/Resource/ListResource.js +9 -9
- package/es/Resource/resourceComponents.js +12 -11
- package/es/Typography/Heading.js +38 -0
- package/es/Typography/index.js +9 -0
- package/es/all.css +1 -1
- package/es/index.js +4 -2
- package/es/locale/messages-en.js +6 -2
- package/es/locale/messages-nb.js +6 -2
- package/es/locale/messages-nn.js +6 -2
- package/es/locale/messages-se.js +6 -2
- package/es/locale/messages-sma.js +6 -2
- package/es/model/ContentType.js +7 -1
- package/lib/Article/Article.d.ts +1 -3
- package/lib/Article/Article.js +7 -13
- package/lib/Article/ArticleByline.d.ts +3 -5
- package/lib/Article/ArticleByline.js +83 -126
- package/lib/Article/ArticleFootNotes.js +16 -11
- package/lib/AudioPlayer/AudioPlayer.d.ts +1 -2
- package/lib/AudioPlayer/AudioPlayer.js +33 -36
- package/lib/AudioPlayer/initAudioPlayers.d.ts +1 -0
- package/lib/AudioPlayer/initAudioPlayers.js +9 -3
- package/lib/ContentTypeBadge/ContentTypeBadge.js +27 -6
- package/lib/Embed/AudioEmbed.d.ts +3 -2
- package/lib/Embed/AudioEmbed.js +53 -192
- package/lib/Embed/BrightcoveEmbed.d.ts +3 -1
- package/lib/Embed/BrightcoveEmbed.js +32 -126
- package/lib/Embed/ConceptEmbed.d.ts +7 -2
- package/lib/Embed/ConceptEmbed.js +51 -73
- package/lib/Embed/EmbedErrorPlaceholder.d.ts +17 -0
- package/lib/Embed/EmbedErrorPlaceholder.js +48 -0
- package/lib/Embed/ExternalEmbed.js +5 -11
- package/lib/Embed/H5pEmbed.js +5 -14
- package/lib/Embed/IframeEmbed.d.ts +2 -2
- package/lib/Embed/IframeEmbed.js +4 -4
- package/lib/Embed/ImageEmbed.d.ts +3 -10
- package/lib/Embed/ImageEmbed.js +48 -161
- package/lib/Embed/RelatedContentEmbed.js +3 -3
- package/lib/Embed/conceptComponents.d.ts +4 -2
- package/lib/Embed/conceptComponents.js +67 -231
- package/lib/Embed/index.d.ts +1 -0
- package/lib/Embed/types.d.ts +14 -0
- package/lib/Embed/types.js +5 -0
- package/lib/KeyFigure/KeyFigure.d.ts +10 -0
- package/lib/KeyFigure/KeyFigure.js +62 -0
- package/lib/KeyFigure/index.d.ts +1 -0
- package/lib/KeyFigure/index.js +13 -0
- package/lib/LicenseByline/EmbedByline.d.ts +10 -2
- package/lib/LicenseByline/EmbedByline.js +32 -7
- package/lib/LicenseByline/LicenseDescription.d.ts +3 -1
- package/lib/LicenseByline/LicenseDescription.js +14 -13
- package/lib/List/OrderedList.d.ts +15 -0
- package/lib/List/OrderedList.js +56 -0
- package/lib/List/UnOrderedList.d.ts +10 -0
- package/lib/List/UnOrderedList.js +43 -0
- package/lib/List/index.d.ts +9 -0
- package/lib/List/index.js +20 -0
- package/lib/Navigation/NavigationBox.js +40 -47
- package/lib/Navigation/NavigationHeading.js +17 -28
- package/lib/Notion/Notion.js +5 -5
- package/lib/Resource/ListResource.js +8 -8
- package/lib/Resource/resourceComponents.js +12 -11
- package/lib/Typography/Heading.d.ts +26 -0
- package/lib/Typography/Heading.js +45 -0
- package/lib/Typography/index.d.ts +8 -0
- package/lib/Typography/index.js +13 -0
- package/lib/all.css +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +23 -3
- package/lib/locale/messages-en.d.ts +4 -0
- package/lib/locale/messages-en.js +6 -2
- package/lib/locale/messages-nb.d.ts +4 -0
- package/lib/locale/messages-nb.js +6 -2
- package/lib/locale/messages-nn.d.ts +4 -0
- package/lib/locale/messages-nn.js +6 -2
- package/lib/locale/messages-se.d.ts +4 -0
- package/lib/locale/messages-se.js +6 -2
- package/lib/locale/messages-sma.d.ts +4 -0
- package/lib/locale/messages-sma.js +6 -2
- package/lib/model/ContentType.d.ts +1 -0
- package/lib/model/ContentType.js +9 -2
- package/package.json +15 -15
- package/src/Article/Article.tsx +1 -8
- package/src/Article/ArticleByline.tsx +78 -127
- package/src/Article/ArticleFootNotes.tsx +33 -10
- package/src/Article/component.article.scss +1 -52
- package/src/Article/component.footnotes.scss +2 -2
- package/src/Aside/component.aside.scss +3 -3
- package/src/AudioPlayer/AudioPlayer.tsx +11 -24
- package/src/AudioPlayer/initAudioPlayers.tsx +7 -2
- package/src/ContentTypeBadge/ContentTypeBadge.tsx +29 -6
- package/src/ContentTypeBadge/component.content-type-badge.scss +9 -3
- package/src/Dialog/component.dialog.scss +4 -5
- package/src/Embed/AudioEmbed.stories.tsx +5 -3
- package/src/Embed/AudioEmbed.tsx +45 -192
- package/src/Embed/BrightcoveEmbed.stories.tsx +5 -1
- package/src/Embed/BrightcoveEmbed.tsx +24 -98
- package/src/Embed/ConceptEmbed.stories.tsx +5 -0
- package/src/Embed/ConceptEmbed.tsx +43 -54
- package/src/Embed/EmbedErrorPlaceholder.tsx +59 -0
- package/src/Embed/ExternalEmbed.stories.tsx +86 -0
- package/src/Embed/ExternalEmbed.tsx +3 -8
- package/src/Embed/H5pEmbed.stories.tsx +92 -0
- package/src/Embed/H5pEmbed.tsx +3 -11
- package/src/Embed/IframeEmbed.stories.tsx +130 -0
- package/src/Embed/IframeEmbed.tsx +3 -3
- package/src/Embed/ImageEmbed.stories.tsx +3 -1
- package/src/Embed/ImageEmbed.tsx +21 -116
- package/src/Embed/RelatedContentEmbed.tsx +3 -1
- package/src/Embed/conceptComponents.tsx +67 -257
- package/src/Embed/index.ts +1 -0
- package/src/Embed/types.ts +12 -0
- package/src/FactBox/component.factbox.scss +3 -3
- package/src/Figure/component.figure-license.scss +4 -4
- package/src/Figure/component.figure.scss +1 -1
- package/src/KeyFigure/KeyFigure.stories.tsx +36 -0
- package/src/{KeyPerformanceIndicator/KeyPerformanceIndicator.tsx → KeyFigure/KeyFigure.tsx} +9 -7
- package/src/{KeyPerformanceIndicator → KeyFigure}/index.ts +1 -1
- package/src/LicenseByline/EmbedByline.stories.tsx +1 -0
- package/src/LicenseByline/EmbedByline.tsx +57 -9
- package/src/LicenseByline/LicenseDescription.tsx +9 -3
- package/src/List/OrderedList.tsx +115 -0
- package/src/List/UnOrderedList.tsx +49 -0
- package/src/List/index.ts +10 -0
- package/src/MediaList/component.medialist.scss +2 -2
- package/src/Navigation/NavigationBox.tsx +10 -14
- package/src/Navigation/NavigationHeading.tsx +15 -24
- package/src/Notion/Notion.tsx +1 -1
- package/src/RelatedArticleList/component.related-articles.scss +3 -13
- package/src/Resource/ListResource.tsx +6 -2
- package/src/Resource/resourceComponents.tsx +4 -2
- package/src/Table/component.tables.scss +0 -46
- package/src/Translation/component.translation.scss +3 -5
- package/src/Typography/Heading.tsx +96 -0
- package/src/Typography/index.ts +9 -0
- package/src/index.ts +5 -1
- package/src/locale/messages-en.ts +4 -0
- package/src/locale/messages-nb.ts +4 -0
- package/src/locale/messages-nn.ts +4 -0
- package/src/locale/messages-se.ts +4 -0
- package/src/locale/messages-sma.ts +4 -0
- package/src/model/ContentType.ts +7 -0
- package/es/KeyPerformanceIndicator/KeyPerformanceIndicator.js +0 -57
- package/lib/KeyPerformanceIndicator/KeyPerformanceIndicator.d.ts +0 -8
- package/lib/KeyPerformanceIndicator/KeyPerformanceIndicator.js +0 -62
- package/lib/KeyPerformanceIndicator/index.d.ts +0 -1
- package/lib/KeyPerformanceIndicator/index.js +0 -13
- package/src/KeyPerformanceIndicator/KeyPerformanceIndicator.stories.tsx +0 -79
|
@@ -12,6 +12,7 @@ import { ImageEmbedData } from '@ndla/types-embed';
|
|
|
12
12
|
import { IImageMetaInformationV2 } from '@ndla/types-backend/build/image-api';
|
|
13
13
|
import ImageEmbed from './ImageEmbed';
|
|
14
14
|
import { defaultParameters } from '../../../../stories/defaults';
|
|
15
|
+
import StoryFavoriteButton from '../../../../stories/StoryFavoriteButton';
|
|
15
16
|
|
|
16
17
|
const embedData: ImageEmbedData = {
|
|
17
18
|
resource: 'image',
|
|
@@ -59,7 +60,6 @@ const meta: Meta<typeof ImageEmbed> = {
|
|
|
59
60
|
component: ImageEmbed,
|
|
60
61
|
tags: ['autodocs'],
|
|
61
62
|
args: {
|
|
62
|
-
articlePath: undefined,
|
|
63
63
|
previewAlt: true,
|
|
64
64
|
},
|
|
65
65
|
decorators: [
|
|
@@ -82,6 +82,7 @@ export default meta;
|
|
|
82
82
|
|
|
83
83
|
export const ImageEmbedStory: StoryObj<typeof ImageEmbed> = {
|
|
84
84
|
args: {
|
|
85
|
+
heartButton: StoryFavoriteButton,
|
|
85
86
|
embed: {
|
|
86
87
|
resource: 'image',
|
|
87
88
|
status: 'success',
|
|
@@ -94,6 +95,7 @@ export const ImageEmbedStory: StoryObj<typeof ImageEmbed> = {
|
|
|
94
95
|
|
|
95
96
|
export const Failed: StoryObj<typeof ImageEmbed> = {
|
|
96
97
|
args: {
|
|
98
|
+
heartButton: StoryFavoriteButton,
|
|
97
99
|
embed: {
|
|
98
100
|
resource: 'image',
|
|
99
101
|
status: 'error',
|
package/src/Embed/ImageEmbed.tsx
CHANGED
|
@@ -7,25 +7,21 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import isNumber from 'lodash/isNumber';
|
|
10
|
-
import styled from '@emotion/styled';
|
|
11
|
-
import { figureApa7CopyString, getGroupedContributorDescriptionList, getLicenseByAbbreviation } from '@ndla/licenses';
|
|
12
10
|
import { ImageEmbedData, ImageMetaData } from '@ndla/types-embed';
|
|
13
11
|
import { useTranslation } from 'react-i18next';
|
|
14
|
-
import { ModalV2 } from '@ndla/modal';
|
|
15
|
-
import { SafeLinkButton } from '@ndla/safelink';
|
|
16
12
|
import { MouseEventHandler, useState } from 'react';
|
|
17
|
-
import { ButtonV2, CopyButton } from '@ndla/button';
|
|
18
13
|
import { ExpandTwoArrows } from '@ndla/icons/action';
|
|
19
14
|
import { ArrowCollapse, ChevronDown, ChevronUp } from '@ndla/icons/common';
|
|
20
|
-
import { Figure,
|
|
15
|
+
import { Figure, FigureType } from '../Figure';
|
|
21
16
|
import Image, { ImageLink } from '../Image';
|
|
22
|
-
import {
|
|
23
|
-
import
|
|
17
|
+
import { EmbedByline } from '../LicenseByline';
|
|
18
|
+
import EmbedErrorPlaceholder from './EmbedErrorPlaceholder';
|
|
19
|
+
import { HeartButtonType } from './types';
|
|
24
20
|
|
|
25
21
|
interface Props {
|
|
26
22
|
embed: ImageMetaData;
|
|
27
|
-
articlePath?: string;
|
|
28
23
|
previewAlt?: boolean;
|
|
24
|
+
heartButton?: HeartButtonType;
|
|
29
25
|
}
|
|
30
26
|
|
|
31
27
|
export interface Author {
|
|
@@ -100,38 +96,20 @@ const getCrop = (data: ImageEmbedData) => {
|
|
|
100
96
|
return undefined;
|
|
101
97
|
};
|
|
102
98
|
|
|
103
|
-
const StyledSpan = styled.span`
|
|
104
|
-
font-style: italic;
|
|
105
|
-
color: grey;
|
|
106
|
-
`;
|
|
107
|
-
|
|
108
99
|
const expandedSizes = '(min-width: 1024px) 1024px, 100vw';
|
|
109
100
|
|
|
110
|
-
const ImageEmbed = ({ embed,
|
|
111
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
101
|
+
const ImageEmbed = ({ embed, previewAlt, heartButton: HeartButton }: Props) => {
|
|
112
102
|
const [isBylineHidden, setIsBylineHidden] = useState(hideByline(embed.embedData.size));
|
|
113
103
|
const [imageSizes, setImageSizes] = useState<string | undefined>(undefined);
|
|
114
|
-
const { t, i18n } = useTranslation();
|
|
115
104
|
if (embed.status === 'error') {
|
|
116
105
|
const { align, size } = embed.embedData;
|
|
117
106
|
const figureType = getFigureType(size, align);
|
|
118
|
-
return
|
|
119
|
-
<Figure type={figureType}>
|
|
120
|
-
<div className="c-figure__img">
|
|
121
|
-
<img alt={t('image.error.url')} src={errorSvgSrc} />
|
|
122
|
-
</div>
|
|
123
|
-
<figcaption>{t('image.error.caption')}</figcaption>
|
|
124
|
-
</Figure>
|
|
125
|
-
);
|
|
107
|
+
return <EmbedErrorPlaceholder type={'image'} figureType={figureType} />;
|
|
126
108
|
}
|
|
127
109
|
|
|
128
110
|
const { data, embedData, seq } = embed;
|
|
129
111
|
|
|
130
|
-
const authors = getLicenseCredits(data.copyright);
|
|
131
|
-
|
|
132
112
|
const altText = embedData.alt || '';
|
|
133
|
-
const caption = embedData.caption || '';
|
|
134
|
-
const license = getLicenseByAbbreviation(data.copyright.license.license, i18n.language);
|
|
135
113
|
|
|
136
114
|
const figureType = getFigureType(embedData.size, embedData.align);
|
|
137
115
|
const sizes = getSizes(embedData.size, embedData.align);
|
|
@@ -139,29 +117,22 @@ const ImageEmbed = ({ embed, articlePath, previewAlt }: Props) => {
|
|
|
139
117
|
const focalPoint = getFocalPoint(embedData);
|
|
140
118
|
const crop = getCrop(embedData);
|
|
141
119
|
|
|
142
|
-
const contributors = getGroupedContributorDescriptionList(data.copyright, i18n.language).map((item) => ({
|
|
143
|
-
name: item.description,
|
|
144
|
-
type: item.label,
|
|
145
|
-
}));
|
|
146
|
-
|
|
147
120
|
const figureId = `figure-${seq}-${data.id}`;
|
|
148
121
|
|
|
149
|
-
const { creators, rightsholders, processors } = authors;
|
|
150
|
-
const captionAuthors = creators.length || rightsholders.length ? [...creators, ...rightsholders] : processors;
|
|
151
122
|
return (
|
|
152
123
|
<Figure
|
|
153
124
|
id={figureId}
|
|
154
125
|
type={imageSizes ? undefined : figureType}
|
|
155
126
|
className={imageSizes ? 'c-figure--right expanded' : ''}
|
|
156
127
|
>
|
|
157
|
-
<ImageWrapper src={data.imageUrl} crop={crop} size={embedData.size}>
|
|
128
|
+
<ImageWrapper src={data.image.imageUrl} crop={crop} size={embedData.size}>
|
|
158
129
|
<Image
|
|
159
130
|
focalPoint={focalPoint}
|
|
160
|
-
contentType={data.contentType}
|
|
131
|
+
contentType={data.image.contentType}
|
|
161
132
|
crop={crop}
|
|
162
133
|
sizes={imageSizes ?? sizes}
|
|
163
134
|
alt={altText}
|
|
164
|
-
src={data.imageUrl}
|
|
135
|
+
src={data.image.imageUrl}
|
|
165
136
|
expandButton={
|
|
166
137
|
<ExpandButton
|
|
167
138
|
size={embedData.size}
|
|
@@ -173,43 +144,17 @@ const ImageEmbed = ({ embed, articlePath, previewAlt }: Props) => {
|
|
|
173
144
|
}
|
|
174
145
|
/>
|
|
175
146
|
</ImageWrapper>
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
licenseRights={license.rights}
|
|
189
|
-
authors={captionAuthors}
|
|
190
|
-
locale={i18n.language}
|
|
191
|
-
>
|
|
192
|
-
<ModalV2 controlled isOpen={isOpen} onClose={() => setIsOpen(false)} labelledBy="license-dialog-rules-heading">
|
|
193
|
-
{(close) => (
|
|
194
|
-
<FigureLicenseDialogContent
|
|
195
|
-
title={data.title.title}
|
|
196
|
-
license={license}
|
|
197
|
-
onClose={close}
|
|
198
|
-
authors={contributors}
|
|
199
|
-
origin={data.copyright.origin}
|
|
200
|
-
locale={i18n.language}
|
|
201
|
-
type="image"
|
|
202
|
-
>
|
|
203
|
-
<ImageLicenseButtons
|
|
204
|
-
articlePath={articlePath}
|
|
205
|
-
title={data.title.title}
|
|
206
|
-
imageUrl={data.imageUrl}
|
|
207
|
-
copyright={data.copyright}
|
|
208
|
-
/>
|
|
209
|
-
</FigureLicenseDialogContent>
|
|
210
|
-
)}
|
|
211
|
-
</ModalV2>
|
|
212
|
-
</FigureCaption>
|
|
147
|
+
{isBylineHidden || (isSmall(embedData.size) && !imageSizes) ? null : (
|
|
148
|
+
<EmbedByline
|
|
149
|
+
type="image"
|
|
150
|
+
copyright={data.copyright}
|
|
151
|
+
description={embedData.caption ?? data.caption.caption}
|
|
152
|
+
bottomRounded
|
|
153
|
+
visibleAlt={previewAlt ? embed.embedData.alt : ''}
|
|
154
|
+
>
|
|
155
|
+
{HeartButton && <HeartButton embed={embed} />}
|
|
156
|
+
</EmbedByline>
|
|
157
|
+
)}
|
|
213
158
|
</Figure>
|
|
214
159
|
);
|
|
215
160
|
};
|
|
@@ -229,46 +174,6 @@ const hideByline = (size?: string): boolean => {
|
|
|
229
174
|
return !!size && size.endsWith('-hide-byline');
|
|
230
175
|
};
|
|
231
176
|
|
|
232
|
-
interface ImageLicenseButtonsProps {
|
|
233
|
-
imageUrl: string;
|
|
234
|
-
title?: string;
|
|
235
|
-
articlePath?: string;
|
|
236
|
-
copyright?: Partial<Copyright>;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export const ImageLicenseButtons = ({ imageUrl, title, articlePath, copyright }: ImageLicenseButtonsProps) => {
|
|
240
|
-
const { t, i18n } = useTranslation();
|
|
241
|
-
if (!copyright?.license?.license || copyright?.license?.license === 'COPYRIGHTED') return null;
|
|
242
|
-
|
|
243
|
-
const copyString = figureApa7CopyString(
|
|
244
|
-
title,
|
|
245
|
-
undefined,
|
|
246
|
-
imageUrl,
|
|
247
|
-
articlePath,
|
|
248
|
-
copyright,
|
|
249
|
-
copyright?.license?.license,
|
|
250
|
-
'',
|
|
251
|
-
t,
|
|
252
|
-
i18n.language,
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
return (
|
|
256
|
-
<>
|
|
257
|
-
<CopyButton
|
|
258
|
-
variant="outline"
|
|
259
|
-
onClick={() => navigator.clipboard.writeText(copyString)}
|
|
260
|
-
copyNode={t('license.hasCopiedTitle')}
|
|
261
|
-
aria-live="assertive"
|
|
262
|
-
>
|
|
263
|
-
{t('license.copyTitle')}
|
|
264
|
-
</CopyButton>
|
|
265
|
-
<SafeLinkButton to={`${imageUrl}?download=true`} download variant="outline">
|
|
266
|
-
{t('image.download')}
|
|
267
|
-
</SafeLinkButton>
|
|
268
|
-
</>
|
|
269
|
-
);
|
|
270
|
-
};
|
|
271
|
-
|
|
272
177
|
const ImageWrapper = ({ src, crop, size, children }: ImageWrapperProps) => {
|
|
273
178
|
const { t } = useTranslation();
|
|
274
179
|
if (isSmall(size) || hideByline(size)) {
|
|
@@ -30,7 +30,9 @@ const RelatedContentEmbed = ({ embed, isOembed, subject, ndlaFrontendDomain }: P
|
|
|
30
30
|
const typeId = data.resource?.resourceTypes.find((rt) => contentTypeMapping[rt.id])?.id;
|
|
31
31
|
const type = typeId ? contentTypeMapping[typeId] : undefined;
|
|
32
32
|
const path =
|
|
33
|
-
data.resource?.paths.find((p) => p.split('/')[1] === subject?.replace('urn:', '')) ??
|
|
33
|
+
data.resource?.paths.find((p) => p.split('/')[1] === subject?.replace('urn:', '')) ??
|
|
34
|
+
data.resource?.path ??
|
|
35
|
+
`/article/${embedData.articleId}`;
|
|
34
36
|
return (
|
|
35
37
|
<RelatedArticleV2
|
|
36
38
|
title={data.article.title?.title ?? ''}
|
|
@@ -6,28 +6,24 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { forwardRef, ReactNode, RefAttributes
|
|
9
|
+
import { forwardRef, ReactNode, RefAttributes } from 'react';
|
|
10
10
|
import { ConceptVisualElementMeta } from '@ndla/types-embed';
|
|
11
11
|
import { useTranslation } from 'react-i18next';
|
|
12
|
-
import { Root, Item, Header, Trigger, Content } from '@radix-ui/react-accordion';
|
|
13
|
-
import { getGroupedContributorDescriptionList, getLicenseByAbbreviation, getLicenseCredits } from '@ndla/licenses';
|
|
14
12
|
import { css } from '@emotion/react';
|
|
15
|
-
import { ButtonV2 } from '@ndla/button';
|
|
16
13
|
import { breakpoints, colors, fonts, misc, mq, spacing } from '@ndla/core';
|
|
17
|
-
import { ChevronDown } from '@ndla/icons/common';
|
|
18
14
|
import { parseMarkdown } from '@ndla/util';
|
|
19
15
|
import styled from '@emotion/styled';
|
|
20
|
-
import { NotionDialogContent,
|
|
21
|
-
import { Figure, FigureCaption } from '../Figure';
|
|
22
|
-
import { NotionVisualElementType } from '../Notion';
|
|
23
|
-
import { classLicenses, FigureLicenseByline, FigureLicenseCta } from '../Figure/FigureLicense';
|
|
16
|
+
import { NotionDialogContent, NotionDialogText } from '@ndla/notion';
|
|
24
17
|
import { Copyright } from '../types';
|
|
25
|
-
import
|
|
18
|
+
import ImageEmbed from './ImageEmbed';
|
|
19
|
+
import BrightcoveEmbed from './BrightcoveEmbed';
|
|
20
|
+
import H5pEmbed from './H5pEmbed';
|
|
21
|
+
import { ExternalEmbed, HeartButtonType, IframeEmbed } from '.';
|
|
22
|
+
import { EmbedByline } from '../LicenseByline';
|
|
26
23
|
|
|
27
24
|
export interface ConceptNotionData {
|
|
28
25
|
title: string;
|
|
29
26
|
content?: string;
|
|
30
|
-
articlePath?: string;
|
|
31
27
|
metaImage?: {
|
|
32
28
|
url?: string;
|
|
33
29
|
alt?: string;
|
|
@@ -44,42 +40,13 @@ interface ConceptNotionProps extends RefAttributes<HTMLDivElement>, ConceptNotio
|
|
|
44
40
|
inPopover?: boolean;
|
|
45
41
|
tags?: string[];
|
|
46
42
|
subjects?: string[];
|
|
43
|
+
heartButton?: HeartButtonType;
|
|
44
|
+
conceptHeartButton?: ReactNode;
|
|
47
45
|
}
|
|
48
46
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (visualElement.resource === 'image') {
|
|
55
|
-
return {
|
|
56
|
-
resource: visualElement.resource,
|
|
57
|
-
title: visualElement.data.title.title,
|
|
58
|
-
copyright: visualElement.data.copyright,
|
|
59
|
-
image: { src: visualElement.data.imageUrl, alt: visualElement.data.alttext.alttext },
|
|
60
|
-
url: visualElement.data.imageUrl,
|
|
61
|
-
};
|
|
62
|
-
} else if (visualElement.resource === 'brightcove') {
|
|
63
|
-
return {
|
|
64
|
-
resource: visualElement.resource,
|
|
65
|
-
title: visualElement.data.name,
|
|
66
|
-
url: `https://players.brightcove.net/${visualElement.embedData.account}/${visualElement.embedData.player}_default/index.html?videoId=${visualElement.embedData.videoid}`,
|
|
67
|
-
copyright: visualElement.data.copyright,
|
|
68
|
-
};
|
|
69
|
-
} else if (visualElement.resource === 'external' || visualElement.resource === 'iframe') {
|
|
70
|
-
return {
|
|
71
|
-
resource: visualElement.resource,
|
|
72
|
-
url: visualElement.embedData.url,
|
|
73
|
-
title: visualElement.embedData.url,
|
|
74
|
-
};
|
|
75
|
-
} else {
|
|
76
|
-
return {
|
|
77
|
-
resource: visualElement.resource,
|
|
78
|
-
url: visualElement.data.h5pUrl,
|
|
79
|
-
title: visualElement.embedData.title,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
};
|
|
47
|
+
const ContentPadding = styled.div`
|
|
48
|
+
padding: ${spacing.normal};
|
|
49
|
+
`;
|
|
83
50
|
|
|
84
51
|
const notionContentCss = css`
|
|
85
52
|
@keyframes animateIn {
|
|
@@ -95,7 +62,6 @@ const notionContentCss = css`
|
|
|
95
62
|
|
|
96
63
|
animation-name: animateIn;
|
|
97
64
|
animation-duration: 300ms;
|
|
98
|
-
padding: ${spacing.normal};
|
|
99
65
|
background-color: white;
|
|
100
66
|
z-index: 1;
|
|
101
67
|
box-shadow: 0 0 30px rgba(0, 0, 0, 0.2);
|
|
@@ -115,11 +81,6 @@ const notionContentCss = css`
|
|
|
115
81
|
}
|
|
116
82
|
`;
|
|
117
83
|
|
|
118
|
-
const StyledIframe = styled.iframe<{ type?: string }>`
|
|
119
|
-
height: auto;
|
|
120
|
-
min-height: ${(p) => p.type === 'video' && '400px'};
|
|
121
|
-
`;
|
|
122
|
-
|
|
123
84
|
const NotionHeader = styled.div`
|
|
124
85
|
display: flex;
|
|
125
86
|
align-items: center;
|
|
@@ -141,72 +102,6 @@ const NotionHeader = styled.div`
|
|
|
141
102
|
}
|
|
142
103
|
`;
|
|
143
104
|
|
|
144
|
-
const StyledAccordionContent = styled(Content)`
|
|
145
|
-
background-color: ${colors.brand.lighter};
|
|
146
|
-
padding: ${spacing.small};
|
|
147
|
-
border-radius: ${misc.borderRadius};
|
|
148
|
-
overflow: hidden;
|
|
149
|
-
&[data-state='open'] {
|
|
150
|
-
animation: slideDown 300ms ease-out;
|
|
151
|
-
}
|
|
152
|
-
&[data-state='closed'] {
|
|
153
|
-
animation: slideUp 300ms ease-out;
|
|
154
|
-
}
|
|
155
|
-
@keyframes slideDown {
|
|
156
|
-
from {
|
|
157
|
-
height: 0;
|
|
158
|
-
}
|
|
159
|
-
to {
|
|
160
|
-
height: var(--radix-accordion-content-height);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
@keyframes slideUp {
|
|
164
|
-
from {
|
|
165
|
-
height: var(--radix-accordion-content-height);
|
|
166
|
-
}
|
|
167
|
-
to {
|
|
168
|
-
height: 0;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
`;
|
|
172
|
-
|
|
173
|
-
const StyledRoot = styled(Root)`
|
|
174
|
-
border-bottom: 1px solid ${colors.brand.greyLight};
|
|
175
|
-
`;
|
|
176
|
-
|
|
177
|
-
const StyledFigure = styled(Figure)`
|
|
178
|
-
&& {
|
|
179
|
-
margin: ${spacing.normal} 0;
|
|
180
|
-
}
|
|
181
|
-
padding-bottom: 0;
|
|
182
|
-
`;
|
|
183
|
-
|
|
184
|
-
const StyledFigureCaption = styled(FigureCaption)`
|
|
185
|
-
border-bottom: 0;
|
|
186
|
-
|
|
187
|
-
h3 {
|
|
188
|
-
margin: 0;
|
|
189
|
-
}
|
|
190
|
-
`;
|
|
191
|
-
|
|
192
|
-
const StyledSpan = styled.span`
|
|
193
|
-
font-style: italic;
|
|
194
|
-
color: grey;
|
|
195
|
-
`;
|
|
196
|
-
|
|
197
|
-
const StyledAccordionTrigger = styled(ButtonV2)`
|
|
198
|
-
color: ${colors.brand.primary};
|
|
199
|
-
border-color: ${colors.brand.primary};
|
|
200
|
-
&[data-state='open'] {
|
|
201
|
-
svg {
|
|
202
|
-
transform: rotate(180deg);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
svg {
|
|
206
|
-
transition: transform 300ms;
|
|
207
|
-
}
|
|
208
|
-
`;
|
|
209
|
-
|
|
210
105
|
const ListWrapper = styled.div`
|
|
211
106
|
display: flex;
|
|
212
107
|
gap: ${spacing.small};
|
|
@@ -215,6 +110,13 @@ const ListWrapper = styled.div`
|
|
|
215
110
|
|
|
216
111
|
const StyledNotionDialogContent = styled(NotionDialogContent)`
|
|
217
112
|
padding-top: ${spacing.small};
|
|
113
|
+
.c-figure {
|
|
114
|
+
left: unset !important;
|
|
115
|
+
width: 100% !important;
|
|
116
|
+
padding: 0;
|
|
117
|
+
margin: 0;
|
|
118
|
+
padding-bottom: ${spacing.normal};
|
|
119
|
+
}
|
|
218
120
|
`;
|
|
219
121
|
|
|
220
122
|
const StyledList = styled.ul`
|
|
@@ -237,7 +139,6 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
|
|
|
237
139
|
(
|
|
238
140
|
{
|
|
239
141
|
visualElement,
|
|
240
|
-
articlePath,
|
|
241
142
|
title,
|
|
242
143
|
content,
|
|
243
144
|
source,
|
|
@@ -247,154 +148,63 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
|
|
|
247
148
|
previewAlt,
|
|
248
149
|
tags,
|
|
249
150
|
subjects,
|
|
151
|
+
heartButton,
|
|
152
|
+
conceptHeartButton,
|
|
250
153
|
...rest
|
|
251
154
|
},
|
|
252
155
|
ref,
|
|
253
156
|
) => {
|
|
254
|
-
const { t
|
|
255
|
-
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
256
|
-
|
|
257
|
-
useEffect(() => {
|
|
258
|
-
const iframe = iframeRef.current;
|
|
259
|
-
if (iframe) {
|
|
260
|
-
const [width, height] = [parseInt(iframe.width), parseInt(iframe.height)];
|
|
261
|
-
iframe.style.aspectRatio = `${width ? width : 16}/${height ? height : 9}`;
|
|
262
|
-
iframe.width = '';
|
|
263
|
-
iframe.height = '';
|
|
264
|
-
}
|
|
265
|
-
}, []);
|
|
266
|
-
|
|
267
|
-
const licenseCredits = getLicenseCredits(copyright);
|
|
268
|
-
const { creators, rightsholders, processors } = licenseCredits;
|
|
269
|
-
const authors = creators.length || rightsholders.length ? creators.concat(rightsholders) : processors;
|
|
157
|
+
const { t } = useTranslation();
|
|
270
158
|
|
|
271
|
-
const visualElementType =
|
|
272
|
-
visualElement?.embedData.resource === 'brightcove' ? 'video' : visualElement?.embedData.resource;
|
|
273
|
-
|
|
274
|
-
const notionVisualElement = visualElement ? getConceptVisualElement(visualElement) : undefined;
|
|
275
|
-
const visualElementLicense = getLicenseByAbbreviation(
|
|
276
|
-
notionVisualElement?.copyright?.license?.license ?? '',
|
|
277
|
-
i18n.language,
|
|
278
|
-
);
|
|
279
|
-
const visualElementLicenseCredits = getLicenseCredits(notionVisualElement?.copyright);
|
|
280
|
-
const visualElementAuthors =
|
|
281
|
-
visualElementLicenseCredits.creators.length || visualElementLicenseCredits.rightsholders.length
|
|
282
|
-
? visualElementLicenseCredits.creators.concat(visualElementLicenseCredits.rightsholders)
|
|
283
|
-
: visualElementLicenseCredits.processors;
|
|
284
|
-
const visualElementGroupedAuthors = getGroupedContributorDescriptionList(
|
|
285
|
-
visualElementLicenseCredits,
|
|
286
|
-
i18n.language,
|
|
287
|
-
).map((item) => ({
|
|
288
|
-
name: item.description,
|
|
289
|
-
type: item.label,
|
|
290
|
-
}));
|
|
291
159
|
return (
|
|
292
160
|
<div css={inPopover ? notionContentCss : undefined} {...rest} ref={ref}>
|
|
293
|
-
<
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
{
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
{
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
reuseLabel={t('reuse')}
|
|
324
|
-
authors={visualElementAuthors}
|
|
325
|
-
licenseRights={visualElementLicense.rights}
|
|
326
|
-
>
|
|
327
|
-
{visualElementLicense.abbreviation && (
|
|
328
|
-
<Header>
|
|
329
|
-
<Trigger asChild>
|
|
330
|
-
<StyledAccordionTrigger variant="outline" shape="pill" size="small" colorTheme="lighter">
|
|
331
|
-
{t('license.info')}
|
|
332
|
-
<ChevronDown />
|
|
333
|
-
</StyledAccordionTrigger>
|
|
334
|
-
</Trigger>
|
|
335
|
-
</Header>
|
|
336
|
-
)}
|
|
337
|
-
</StyledFigureCaption>
|
|
338
|
-
<StyledAccordionContent>
|
|
339
|
-
<div {...classLicenses()}>
|
|
340
|
-
<h1 {...classLicenses('title')}>{t(`license.${visualElementType}.rules`)}</h1>
|
|
341
|
-
<FigureLicenseByline
|
|
342
|
-
license={visualElementLicense}
|
|
343
|
-
messages={{
|
|
344
|
-
learnAboutLicenses: t('license.learnMore'),
|
|
345
|
-
}}
|
|
346
|
-
locale={i18n.language}
|
|
347
|
-
/>
|
|
348
|
-
<FigureLicenseCta
|
|
349
|
-
authors={visualElementGroupedAuthors}
|
|
350
|
-
title={notionVisualElement?.title}
|
|
351
|
-
origin={notionVisualElement?.copyright?.origin}
|
|
352
|
-
messages={{ source: t('source'), title: t('title') }}
|
|
353
|
-
>
|
|
354
|
-
{visualElementType === 'image' ? (
|
|
355
|
-
<ImageLicenseButtons
|
|
356
|
-
imageUrl={notionVisualElement.image?.src ?? ''}
|
|
357
|
-
title={notionVisualElement.title}
|
|
358
|
-
copyright={notionVisualElement.copyright}
|
|
359
|
-
articlePath={articlePath}
|
|
360
|
-
/>
|
|
361
|
-
) : null}
|
|
362
|
-
</FigureLicenseCta>
|
|
363
|
-
</div>
|
|
364
|
-
</StyledAccordionContent>
|
|
365
|
-
</Item>
|
|
366
|
-
</StyledRoot>
|
|
367
|
-
)}
|
|
368
|
-
</StyledFigure>
|
|
161
|
+
<ContentPadding>
|
|
162
|
+
<NotionHeader>
|
|
163
|
+
<h1>
|
|
164
|
+
{title} {<small>{t('searchPage.resultType.notionsHeading')}</small>}
|
|
165
|
+
</h1>
|
|
166
|
+
{closeButton}
|
|
167
|
+
</NotionHeader>
|
|
168
|
+
<StyledNotionDialogContent>
|
|
169
|
+
{visualElement?.resource === 'image' ? (
|
|
170
|
+
<ImageEmbed embed={visualElement} heartButton={heartButton} />
|
|
171
|
+
) : visualElement?.resource === 'brightcove' ? (
|
|
172
|
+
<BrightcoveEmbed embed={visualElement} heartButton={heartButton} />
|
|
173
|
+
) : visualElement?.resource === 'h5p' ? (
|
|
174
|
+
<H5pEmbed embed={visualElement} />
|
|
175
|
+
) : visualElement?.resource === 'iframe' ? (
|
|
176
|
+
<IframeEmbed embed={visualElement} />
|
|
177
|
+
) : visualElement?.resource === 'external' ? (
|
|
178
|
+
<ExternalEmbed embed={visualElement} />
|
|
179
|
+
) : null}
|
|
180
|
+
<NotionDialogText>{parseMarkdown(content ?? '', 'body')}</NotionDialogText>
|
|
181
|
+
</StyledNotionDialogContent>
|
|
182
|
+
{tags && (
|
|
183
|
+
<ListWrapper>
|
|
184
|
+
{`${t('notions.tags')}:`}
|
|
185
|
+
<StyledList>
|
|
186
|
+
{tags.map((tag, index) => (
|
|
187
|
+
<li key={index}>{tag}</li>
|
|
188
|
+
))}
|
|
189
|
+
</StyledList>
|
|
190
|
+
</ListWrapper>
|
|
369
191
|
)}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
<StyledList>
|
|
386
|
-
{subjects.map((subject, index) => (
|
|
387
|
-
<li key={index}>{subject}</li>
|
|
388
|
-
))}
|
|
389
|
-
</StyledList>
|
|
390
|
-
</ListWrapper>
|
|
192
|
+
{subjects && (
|
|
193
|
+
<ListWrapper>
|
|
194
|
+
{`${t('notions.usedIn')}:`}
|
|
195
|
+
<StyledList>
|
|
196
|
+
{subjects.map((subject, index) => (
|
|
197
|
+
<li key={index}>{subject}</li>
|
|
198
|
+
))}
|
|
199
|
+
</StyledList>
|
|
200
|
+
</ListWrapper>
|
|
201
|
+
)}
|
|
202
|
+
</ContentPadding>
|
|
203
|
+
{copyright && (
|
|
204
|
+
<EmbedByline copyright={copyright} type="concept">
|
|
205
|
+
{conceptHeartButton}
|
|
206
|
+
</EmbedByline>
|
|
391
207
|
)}
|
|
392
|
-
|
|
393
|
-
<NotionDialogLicenses
|
|
394
|
-
authors={authors.map((a) => a.name)}
|
|
395
|
-
license={copyright?.license?.license ?? ''}
|
|
396
|
-
source={parseMarkdown(source ?? '', 'body')}
|
|
397
|
-
/>
|
|
398
208
|
</div>
|
|
399
209
|
);
|
|
400
210
|
},
|
package/src/Embed/index.ts
CHANGED
|
@@ -19,3 +19,4 @@ export { default as ConceptEmbed } from './ConceptEmbed';
|
|
|
19
19
|
export { ConceptNotionV2 } from './conceptComponents';
|
|
20
20
|
export { default as ConceptListEmbed } from './ConceptListEmbed';
|
|
21
21
|
export { default as UnknownEmbed } from './UnknownEmbed';
|
|
22
|
+
export type { HeartButtonType } from './types';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2023-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ElementType } from 'react';
|
|
10
|
+
import { EmbedMetaData } from '@ndla/types-embed';
|
|
11
|
+
|
|
12
|
+
export type HeartButtonType = ElementType<{ embed: Extract<EmbedMetaData, { status: 'success' }> }>;
|