@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
|
@@ -6,36 +6,36 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React, { ReactNode } from 'react';
|
|
9
|
+
import React, { ReactNode, useCallback, useEffect, useState } from 'react';
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
|
-
import
|
|
12
|
-
import { CopyButton, ButtonV2 } from '@ndla/button';
|
|
13
|
-
import { colors, fonts, spacing } from '@ndla/core';
|
|
14
|
-
import { copyTextToClipboard, printPage } from '@ndla/util';
|
|
11
|
+
import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
|
|
15
12
|
import { useTranslation } from 'react-i18next';
|
|
16
13
|
import { getLicenseByAbbreviation } from '@ndla/licenses';
|
|
17
|
-
import {
|
|
14
|
+
import { AccordionRoot, AccordionHeader, AccordionContent, AccordionItem } from '@ndla/accordion';
|
|
18
15
|
import { TFunction } from 'i18next';
|
|
16
|
+
import { FootNote } from '../types';
|
|
17
|
+
import ArticleFootNotes from './ArticleFootNotes';
|
|
18
|
+
import LicenseLink from '../LicenseByline/LicenseLink';
|
|
19
19
|
|
|
20
20
|
const Wrapper = styled.div`
|
|
21
21
|
margin-top: ${spacing.normal};
|
|
22
22
|
padding-top: ${spacing.normal};
|
|
23
23
|
padding-bottom: ${spacing.xsmall};
|
|
24
24
|
border-top: 1px solid ${colors.brand.greyLight};
|
|
25
|
-
${fonts.sizes('
|
|
25
|
+
${fonts.sizes('16px', '24px')};
|
|
26
26
|
font-family: ${fonts.sans};
|
|
27
27
|
color: ${colors.brand.greyDark};
|
|
28
28
|
`;
|
|
29
29
|
|
|
30
30
|
const TextWrapper = styled.div`
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
display: flex;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
width: 100%;
|
|
34
|
+
padding-bottom: ${spacing.mediumlarge};
|
|
35
|
+
${mq.range({ until: breakpoints.tabletWide })} {
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
flex-direction: column-reverse;
|
|
38
|
+
gap: ${spacing.xsmall};
|
|
39
39
|
}
|
|
40
40
|
`;
|
|
41
41
|
|
|
@@ -57,11 +57,8 @@ type Props = {
|
|
|
57
57
|
published: string;
|
|
58
58
|
license: string;
|
|
59
59
|
licenseBox?: ReactNode;
|
|
60
|
-
copyPageUrlLink?: string;
|
|
61
|
-
printUrl?: string;
|
|
62
60
|
locale?: string;
|
|
63
|
-
|
|
64
|
-
copySourceReference?: string;
|
|
61
|
+
footnotes?: FootNote[];
|
|
65
62
|
};
|
|
66
63
|
|
|
67
64
|
const renderContributors = (contributors: SupplierProps[] | AuthorProps[], t: TFunction) => {
|
|
@@ -85,133 +82,87 @@ const getSuppliersText = (suppliers: SupplierProps[], t: TFunction) => {
|
|
|
85
82
|
: t('article.supplierLabel', { name: renderContributors(suppliers, t), interpolation: { escapeValue: false } });
|
|
86
83
|
};
|
|
87
84
|
|
|
85
|
+
const LicenseWrapper = styled.div`
|
|
86
|
+
display: flex;
|
|
87
|
+
gap: ${spacing.small};
|
|
88
|
+
`;
|
|
89
|
+
|
|
90
|
+
const refRegexp = /note\d/;
|
|
91
|
+
const referencesAccordionId = 'references';
|
|
92
|
+
|
|
88
93
|
const ArticleByline = ({
|
|
89
94
|
authors = [],
|
|
90
95
|
suppliers = [],
|
|
91
|
-
|
|
96
|
+
footnotes,
|
|
97
|
+
license: licenseString,
|
|
92
98
|
licenseBox,
|
|
93
99
|
published,
|
|
94
|
-
copyPageUrlLink,
|
|
95
|
-
printUrl,
|
|
96
100
|
locale,
|
|
97
|
-
copyEmbedLink,
|
|
98
|
-
copySourceReference,
|
|
99
101
|
}: Props) => {
|
|
100
102
|
const { t } = useTranslation();
|
|
103
|
+
const [openAccordions, setOpenAccordions] = useState<string[]>([]);
|
|
104
|
+
|
|
105
|
+
const onHashChange = useCallback(
|
|
106
|
+
(e: HashChangeEvent) => {
|
|
107
|
+
const hash = e.newURL.split('#')[1];
|
|
108
|
+
if (hash.match(refRegexp) && !openAccordions.includes(referencesAccordionId)) {
|
|
109
|
+
setOpenAccordions([...openAccordions, referencesAccordionId]);
|
|
110
|
+
const el = document.getElementById(`#${hash}`);
|
|
111
|
+
el?.click();
|
|
112
|
+
el?.focus();
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
[openAccordions],
|
|
116
|
+
);
|
|
101
117
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const copyLicense = () => {
|
|
110
|
-
if (copySourceReference) {
|
|
111
|
-
copyTextToClipboard(copySourceReference);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
const copyEmbededLink = () => {
|
|
115
|
-
if (copyEmbedLink) {
|
|
116
|
-
copyTextToClipboard(copyEmbedLink);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
window.addEventListener('hashchange', onHashChange);
|
|
120
|
+
return () => window.removeEventListener('hashchange', onHashChange);
|
|
121
|
+
}, [onHashChange]);
|
|
122
|
+
|
|
123
|
+
const license = getLicenseByAbbreviation(licenseString, locale);
|
|
119
124
|
|
|
120
125
|
const showPrimaryContributors = suppliers.length > 0 || authors.length > 0;
|
|
121
126
|
const showSecondaryContributors = suppliers.length > 0 && authors.length > 0;
|
|
122
127
|
|
|
123
|
-
const buttonId = 'popupUseContent';
|
|
124
|
-
|
|
125
128
|
return (
|
|
126
129
|
<Wrapper>
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
)}
|
|
130
|
+
<TextWrapper>
|
|
131
|
+
<LicenseWrapper>
|
|
132
|
+
<LicenseLink license={license} />
|
|
133
|
+
{showPrimaryContributors && (
|
|
134
|
+
<PrimaryContributorsWrapper>
|
|
135
|
+
{authors.length > 0
|
|
136
|
+
? t('article.authorsLabel', {
|
|
137
|
+
names: renderContributors(authors, t),
|
|
138
|
+
interpolation: { escapeValue: false },
|
|
139
|
+
})
|
|
140
|
+
: getSuppliersText(suppliers, t)}
|
|
141
|
+
</PrimaryContributorsWrapper>
|
|
142
|
+
)}
|
|
143
|
+
</LicenseWrapper>
|
|
144
|
+
<div>
|
|
145
|
+
{t('article.lastUpdated')} {published}
|
|
146
|
+
</div>
|
|
147
|
+
</TextWrapper>
|
|
146
148
|
{showSecondaryContributors && <TextWrapper>{getSuppliersText(suppliers, t)}</TextWrapper>}
|
|
147
|
-
<
|
|
149
|
+
<AccordionRoot type="multiple" onValueChange={setOpenAccordions} value={openAccordions}>
|
|
148
150
|
{licenseBox && (
|
|
149
|
-
<
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
{t('article.useContent')}
|
|
154
|
-
</ButtonV2>
|
|
155
|
-
}
|
|
156
|
-
backgroundColor="white"
|
|
157
|
-
position="top"
|
|
158
|
-
size="medium"
|
|
159
|
-
>
|
|
160
|
-
{(onClose: () => void) => (
|
|
161
|
-
<>
|
|
162
|
-
<ModalHeader modifier="no-bottom-padding">
|
|
163
|
-
<ModalCloseButton onClick={onClose} title="Lukk" />
|
|
164
|
-
</ModalHeader>
|
|
165
|
-
<ModalBody>{licenseBox}</ModalBody>
|
|
166
|
-
</>
|
|
167
|
-
)}
|
|
168
|
-
</Modal>
|
|
169
|
-
)}
|
|
170
|
-
{copySourceReference && (
|
|
171
|
-
<CopyButton
|
|
172
|
-
size="small"
|
|
173
|
-
shape="pill"
|
|
174
|
-
variant="outline"
|
|
175
|
-
aria-live="assertive"
|
|
176
|
-
copyNode={t('license.hasCopiedTitle')}
|
|
177
|
-
data-copy-string={copySourceReference}
|
|
178
|
-
onClick={copyLicense}
|
|
179
|
-
>
|
|
180
|
-
{`${t('license.copy')} ${t('license.copyTitle').toLowerCase()}`}
|
|
181
|
-
</CopyButton>
|
|
151
|
+
<AccordionItem value="rulesForUse">
|
|
152
|
+
<AccordionHeader>{t('article.useContent')}</AccordionHeader>
|
|
153
|
+
<AccordionContent>{licenseBox}</AccordionContent>
|
|
154
|
+
</AccordionItem>
|
|
182
155
|
)}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
copyNode={t('article.copyPageLinkCopied')}
|
|
192
|
-
>
|
|
193
|
-
{t('article.copyPageLink')}
|
|
194
|
-
</CopyButton>
|
|
195
|
-
)}
|
|
196
|
-
{copyEmbedLink && (
|
|
197
|
-
<CopyButton
|
|
198
|
-
size="small"
|
|
199
|
-
shape="pill"
|
|
200
|
-
variant="outline"
|
|
201
|
-
aria-live="assertive"
|
|
202
|
-
copyNode={t('license.hasCopiedTitle')}
|
|
203
|
-
data-copy-string={copyEmbedLink}
|
|
204
|
-
onClick={copyEmbededLink}
|
|
205
|
-
>
|
|
206
|
-
{`${t('license.copy')} ${t('license.tabs.embedlink').toLowerCase()}`}
|
|
207
|
-
</CopyButton>
|
|
208
|
-
)}
|
|
209
|
-
{printUrl && (
|
|
210
|
-
<ButtonV2 size="small" shape="pill" variant="outline" onClick={() => printPage(printUrl)}>
|
|
211
|
-
{t('article.printPage')}
|
|
212
|
-
</ButtonV2>
|
|
156
|
+
|
|
157
|
+
{!!footnotes?.length && (
|
|
158
|
+
<AccordionItem value={referencesAccordionId}>
|
|
159
|
+
<AccordionHeader>Referanser</AccordionHeader>
|
|
160
|
+
<AccordionContent forceMount>
|
|
161
|
+
<ArticleFootNotes footNotes={footnotes} />
|
|
162
|
+
</AccordionContent>
|
|
163
|
+
</AccordionItem>
|
|
213
164
|
)}
|
|
214
|
-
</
|
|
165
|
+
</AccordionRoot>
|
|
215
166
|
</Wrapper>
|
|
216
167
|
);
|
|
217
168
|
};
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React from 'react';
|
|
10
|
+
import styled from '@emotion/styled';
|
|
11
|
+
import { colors, spacing } from '@ndla/core';
|
|
10
12
|
import { FootNote as FootNoteType } from '../types';
|
|
11
13
|
|
|
12
14
|
const citeDetailString = (description: string | undefined) => (description ? `${description}. ` : '');
|
|
@@ -15,14 +17,26 @@ type FootNoteProps = {
|
|
|
15
17
|
footNote: FootNoteType;
|
|
16
18
|
};
|
|
17
19
|
|
|
20
|
+
const Cite = styled.cite`
|
|
21
|
+
display: flex;
|
|
22
|
+
gap: ${spacing.small};
|
|
23
|
+
a {
|
|
24
|
+
box-shadow: none;
|
|
25
|
+
text-decoration: underline;
|
|
26
|
+
text-underline-offset: ${spacing.xxsmall};
|
|
27
|
+
&:hover,
|
|
28
|
+
&:focus-visible {
|
|
29
|
+
text-decoration: none;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
18
34
|
const FootNote = ({ footNote }: FootNoteProps) => (
|
|
19
|
-
<li
|
|
20
|
-
<
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</a>
|
|
25
|
-
</sup>
|
|
35
|
+
<li>
|
|
36
|
+
<Cite id={`note${footNote.ref}`}>
|
|
37
|
+
<a href={`#ref${footNote.ref}`} target="_self">
|
|
38
|
+
{footNote.ref}
|
|
39
|
+
</a>
|
|
26
40
|
{`«${footNote.title}». ${footNote.authors.join(' ')}. ${citeDetailString(footNote.edition)}${citeDetailString(
|
|
27
41
|
footNote.publisher,
|
|
28
42
|
)}${footNote.year}. `}
|
|
@@ -32,7 +46,7 @@ const FootNote = ({ footNote }: FootNoteProps) => (
|
|
|
32
46
|
{'.'}
|
|
33
47
|
</a>
|
|
34
48
|
) : null}
|
|
35
|
-
</
|
|
49
|
+
</Cite>
|
|
36
50
|
</li>
|
|
37
51
|
);
|
|
38
52
|
|
|
@@ -40,12 +54,21 @@ type ArticleFootNotesProps = {
|
|
|
40
54
|
footNotes: Array<FootNoteType>;
|
|
41
55
|
};
|
|
42
56
|
|
|
57
|
+
const FootnoteList = styled.ol`
|
|
58
|
+
margin: 0;
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
list-style: none;
|
|
62
|
+
padding: ${spacing.small};
|
|
63
|
+
color: ${colors.text.light};
|
|
64
|
+
`;
|
|
65
|
+
|
|
43
66
|
const ArticleFootNotes = ({ footNotes }: ArticleFootNotesProps) => (
|
|
44
|
-
<
|
|
67
|
+
<FootnoteList>
|
|
45
68
|
{footNotes.map((footNote) => (
|
|
46
69
|
<FootNote key={footNote.ref} footNote={footNote} />
|
|
47
70
|
))}
|
|
48
|
-
</
|
|
71
|
+
</FootnoteList>
|
|
49
72
|
);
|
|
50
73
|
|
|
51
74
|
export default ArticleFootNotes;
|
|
@@ -4,15 +4,6 @@
|
|
|
4
4
|
** Title has icon when article is a resource type
|
|
5
5
|
**/
|
|
6
6
|
|
|
7
|
-
@mixin contentList() {
|
|
8
|
-
ul:not([class]),
|
|
9
|
-
ul.o-list--two-columns,
|
|
10
|
-
ul.o-list--bullets,
|
|
11
|
-
ol {
|
|
12
|
-
@content;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
7
|
.c-article {
|
|
17
8
|
font-family: $font-serif;
|
|
18
9
|
background: $white;
|
|
@@ -33,58 +24,16 @@
|
|
|
33
24
|
margin-bottom: 29px;
|
|
34
25
|
}
|
|
35
26
|
}
|
|
36
|
-
p {
|
|
37
|
-
@include chinese() {
|
|
38
|
-
@include font-size(20px, 35px);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@include contentList() {
|
|
43
|
-
@include chinese() {
|
|
44
|
-
@include font-size(20px, 35px);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@include chinese() {
|
|
49
|
-
@include contentList() {
|
|
50
|
-
@include font-size(22px, 35px);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
p {
|
|
54
|
-
@include font-size(22px, 35px);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
27
|
|
|
58
28
|
@include mq(tablet) {
|
|
59
29
|
@include font-size(20px, 35px);
|
|
60
30
|
|
|
61
|
-
p {
|
|
62
|
-
@include chinese() {
|
|
63
|
-
@include font-size(22px, 35px);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
31
|
> section > p {
|
|
68
32
|
&:not([class]) {
|
|
69
33
|
margin-bottom: 35px;
|
|
70
34
|
}
|
|
71
35
|
}
|
|
72
36
|
|
|
73
|
-
@include contentList() {
|
|
74
|
-
@include chinese() {
|
|
75
|
-
@include font-size(22px, 35px);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
@include chinese() {
|
|
80
|
-
@include contentList() {
|
|
81
|
-
@include font-size(22px, 35px);
|
|
82
|
-
}
|
|
83
|
-
p {
|
|
84
|
-
@include font-size(22px, 35px);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
37
|
padding: 0 $spacing $spacing;
|
|
89
38
|
margin-bottom: $spacing--large;
|
|
90
39
|
margin-top: -$spacing * 6;
|
|
@@ -178,7 +127,7 @@
|
|
|
178
127
|
}
|
|
179
128
|
|
|
180
129
|
p {
|
|
181
|
-
@include
|
|
130
|
+
@include font-size(16px, 20px);
|
|
182
131
|
color: $text-light-color;
|
|
183
132
|
text-transform: uppercase;
|
|
184
133
|
margin-bottom: 0;
|
|
@@ -17,7 +17,7 @@ $highlight-color: $brand-grey--lighter;
|
|
|
17
17
|
display: block;
|
|
18
18
|
border-top: 2px solid $brand-grey--lighter;
|
|
19
19
|
color: gray;
|
|
20
|
-
@include
|
|
20
|
+
@include font-size(15px, 1.6);
|
|
21
21
|
}
|
|
22
22
|
.c-footnotes__item {
|
|
23
23
|
margin-bottom: $spacing--small;
|
|
@@ -37,7 +37,7 @@ $highlight-color: $brand-grey--lighter;
|
|
|
37
37
|
padding: 10px 15px;
|
|
38
38
|
box-shadow: none;
|
|
39
39
|
text-decoration: underline;
|
|
40
|
-
@include
|
|
40
|
+
@include font-size(15px, 1.6);
|
|
41
41
|
|
|
42
42
|
&:hover,
|
|
43
43
|
&:active,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
.c-aside {
|
|
7
7
|
position: relative;
|
|
8
8
|
margin: $spacing--large 0;
|
|
9
|
-
@include
|
|
9
|
+
@include font-size(16px, 1.5);
|
|
10
10
|
z-index: 1;
|
|
11
11
|
|
|
12
12
|
@include mq(tablet) {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
.c-aside h1 {
|
|
60
60
|
margin-top: 0;
|
|
61
61
|
margin-bottom: $spacing;
|
|
62
|
-
@include
|
|
62
|
+
@include font-size(22px, 34px);
|
|
63
63
|
font-weight: $font-weight-bold;
|
|
64
64
|
position: relative;
|
|
65
65
|
z-index: 2;
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
.c-aside h4,
|
|
71
71
|
.c-aside h5 {
|
|
72
72
|
display: block;
|
|
73
|
-
@include
|
|
73
|
+
@include font-size(16px, 1.5);
|
|
74
74
|
letter-spacing: 0.1em;
|
|
75
75
|
margin-top: $spacing;
|
|
76
76
|
margin-bottom: $spacing--small;
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React, { ReactNode,
|
|
9
|
+
import React, { ReactNode, useMemo, useState } from 'react';
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
11
|
import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
|
|
12
12
|
import { ButtonV2 } from '@ndla/button';
|
|
13
13
|
import { Cross as CrossIcon } from '@ndla/icons/action';
|
|
14
14
|
import { useTranslation } from 'react-i18next';
|
|
15
15
|
import SafeLink from '@ndla/safelink';
|
|
16
|
-
import shave from 'shave';
|
|
17
16
|
import Controls from './Controls';
|
|
18
17
|
import SpeechControl from './SpeechControl';
|
|
19
18
|
|
|
@@ -163,11 +162,7 @@ const TextVersionText = styled.div`
|
|
|
163
162
|
max-width: 670px;
|
|
164
163
|
`;
|
|
165
164
|
|
|
166
|
-
|
|
167
|
-
shave(el, 90, {
|
|
168
|
-
character: `... <a href="#" onclick="(function(e){e.preventDefault(); const parentNode = e.target.parentNode; parentNode.nextSibling.style.display = 'inline'; parentNode.remove();return false;})(arguments[0]);return false;">${readMoreLabel}</a>`,
|
|
169
|
-
});
|
|
170
|
-
};
|
|
165
|
+
const DESCRIPTION_MAX_LENGTH = 200;
|
|
171
166
|
|
|
172
167
|
type Props = {
|
|
173
168
|
src: string;
|
|
@@ -177,7 +172,7 @@ type Props = {
|
|
|
177
172
|
url?: string;
|
|
178
173
|
};
|
|
179
174
|
speech?: boolean;
|
|
180
|
-
description?:
|
|
175
|
+
description?: string;
|
|
181
176
|
textVersion?: ReactNode;
|
|
182
177
|
img?: {
|
|
183
178
|
url: string;
|
|
@@ -189,15 +184,8 @@ type Props = {
|
|
|
189
184
|
const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersion, staticRenderId }: Props) => {
|
|
190
185
|
const { t } = useTranslation();
|
|
191
186
|
const [showTextVersion, setShowTextVersion] = useState(false);
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
const readMoreDescriptionLabel = t('audio.readMoreDescriptionLabel');
|
|
195
|
-
|
|
196
|
-
useEffect(() => {
|
|
197
|
-
if (descriptionRef?.current) {
|
|
198
|
-
truncateDescription(descriptionRef.current, readMoreDescriptionLabel);
|
|
199
|
-
}
|
|
200
|
-
}, [readMoreDescriptionLabel]);
|
|
187
|
+
const [showFullDescription, setShowFullDescription] = useState(false);
|
|
188
|
+
const truncatedDescription = useMemo(() => description?.slice(0, DESCRIPTION_MAX_LENGTH), [description]);
|
|
201
189
|
|
|
202
190
|
if (speech) {
|
|
203
191
|
return (
|
|
@@ -244,13 +232,12 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
|
|
|
244
232
|
</TitleWrapper>
|
|
245
233
|
{description && (
|
|
246
234
|
<StyledDescription>
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
</div>
|
|
235
|
+
{showFullDescription || description.length < DESCRIPTION_MAX_LENGTH
|
|
236
|
+
? description
|
|
237
|
+
: `${truncatedDescription}...`}
|
|
238
|
+
<ButtonV2 variant="link" onClick={() => setShowFullDescription((p) => !p)}>
|
|
239
|
+
{t(`audio.${showFullDescription ? 'readLessDescriptionLabel' : 'readMoreDescriptionLabel'}`)}
|
|
240
|
+
</ButtonV2>
|
|
254
241
|
</StyledDescription>
|
|
255
242
|
)}
|
|
256
243
|
{textVersion && img && <TextVersionComponent />}
|
|
@@ -7,11 +7,16 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import ReactDOM from 'react-dom';
|
|
10
|
-
|
|
10
|
+
import shave from 'shave';
|
|
11
11
|
import Controls from './Controls';
|
|
12
12
|
import SpeechControl from './SpeechControl';
|
|
13
13
|
import { Locale } from '../types';
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
export const truncateDescription = (el: HTMLElement, readMoreLabel: string | null) => {
|
|
16
|
+
shave(el, 90, {
|
|
17
|
+
character: `... <a href="#" onclick="(function(e){e.preventDefault(); const parentNode = e.target.parentNode; parentNode.nextSibling.style.display = 'inline'; parentNode.remove();return false;})(arguments[0]);return false;">${readMoreLabel}</a>`,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
15
20
|
|
|
16
21
|
const forEachElement = (selector: string, callback: Function) => {
|
|
17
22
|
const nodeList = document.querySelectorAll(selector);
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '@ndla/icons/contentType';
|
|
14
14
|
|
|
15
15
|
import { MenuBook } from '@ndla/icons/action';
|
|
16
|
+
import { Concept, Media, SquareAudio, SquareVideo } from '@ndla/icons/editor';
|
|
16
17
|
|
|
17
18
|
import * as contentTypes from '../model/ContentType';
|
|
18
19
|
|
|
@@ -32,12 +33,8 @@ interface Props {
|
|
|
32
33
|
|
|
33
34
|
export const ContentTypeBadge = ({ type, background, title, size = 'small', border = true, className }: Props) => {
|
|
34
35
|
const modifiers = [type, size];
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
if (border) {
|
|
39
|
-
modifiers.push('border');
|
|
40
|
-
}
|
|
36
|
+
|
|
37
|
+
let embedResource = false;
|
|
41
38
|
|
|
42
39
|
let icon = null;
|
|
43
40
|
switch (type) {
|
|
@@ -68,9 +65,35 @@ export const ContentTypeBadge = ({ type, background, title, size = 'small', bord
|
|
|
68
65
|
case contentTypes.MULTIDISCIPLINARY_TOPIC:
|
|
69
66
|
icon = <MultidisciplinaryTopic />;
|
|
70
67
|
break;
|
|
68
|
+
case contentTypes.resourceTypeMapping.image:
|
|
69
|
+
icon = <Media />;
|
|
70
|
+
embedResource = true;
|
|
71
|
+
break;
|
|
72
|
+
case contentTypes.resourceTypeMapping.audio:
|
|
73
|
+
icon = <SquareAudio />;
|
|
74
|
+
embedResource = true;
|
|
75
|
+
break;
|
|
76
|
+
case contentTypes.resourceTypeMapping.video:
|
|
77
|
+
icon = <SquareVideo />;
|
|
78
|
+
embedResource = true;
|
|
79
|
+
break;
|
|
80
|
+
case contentTypes.resourceTypeMapping.concept:
|
|
81
|
+
icon = <Concept />;
|
|
82
|
+
embedResource = true;
|
|
83
|
+
break;
|
|
71
84
|
default:
|
|
72
85
|
break;
|
|
73
86
|
}
|
|
87
|
+
|
|
88
|
+
if (embedResource) {
|
|
89
|
+
modifiers.push('embed-resource');
|
|
90
|
+
}
|
|
91
|
+
if (background || embedResource) {
|
|
92
|
+
modifiers.push('background');
|
|
93
|
+
}
|
|
94
|
+
if (border) {
|
|
95
|
+
modifiers.push('border');
|
|
96
|
+
}
|
|
74
97
|
return <div {...classes('', modifiers, className)}>{icon}</div>;
|
|
75
98
|
};
|
|
76
99
|
|
|
@@ -6,10 +6,16 @@
|
|
|
6
6
|
justify-content: center;
|
|
7
7
|
border-radius: 100%;
|
|
8
8
|
&--border {
|
|
9
|
-
|
|
10
9
|
border: 2px solid $black;
|
|
11
10
|
}
|
|
12
11
|
|
|
12
|
+
&--embed-resource {
|
|
13
|
+
border-color: $brand-grey;
|
|
14
|
+
&.c-content-type-badge--background {
|
|
15
|
+
background: $brand-grey--light;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
&--subject-material {
|
|
14
20
|
border-color: $subject-material-dark;
|
|
15
21
|
|
|
@@ -165,9 +171,9 @@
|
|
|
165
171
|
background: $subjecttype-background;
|
|
166
172
|
}
|
|
167
173
|
}
|
|
168
|
-
&--multidisciplinary-topic{
|
|
174
|
+
&--multidisciplinary-topic {
|
|
169
175
|
&.c-content-type-badge--background {
|
|
170
|
-
background: #
|
|
176
|
+
background: #b9b37b;
|
|
171
177
|
}
|
|
172
178
|
}
|
|
173
179
|
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
}
|
|
18
18
|
&:not(&--large, &--fullscreen) {
|
|
19
19
|
h1 {
|
|
20
|
-
@include
|
|
20
|
+
@include font-size(22px, 26px);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
&--small-heading {
|
|
24
24
|
h1 {
|
|
25
|
-
@include
|
|
25
|
+
@include font-size(22px, 26px);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
@include mq(tablet) {
|
|
46
46
|
min-width: 20rem;
|
|
47
47
|
}
|
|
48
|
-
@include font-size(18px);
|
|
48
|
+
@include font-size(18px, 1.33);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
&--active &__content {
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
background: transparent;
|
|
91
91
|
border: none;
|
|
92
92
|
color: $brand-color;
|
|
93
|
-
@include font-size(
|
|
93
|
+
@include font-size(18px, 1.33);
|
|
94
94
|
font-weight: $font-weight-normal;
|
|
95
95
|
padding: 0;
|
|
96
96
|
box-shadow: $link;
|
|
@@ -124,7 +124,6 @@
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
|
|
128
127
|
&--fullscreen &__content {
|
|
129
128
|
@include mq(tablet) {
|
|
130
129
|
height: 100vh;
|