@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.
Files changed (174) hide show
  1. package/es/Article/Article.js +7 -13
  2. package/es/Article/ArticleByline.js +79 -123
  3. package/es/Article/ArticleFootNotes.js +16 -11
  4. package/es/AudioPlayer/AudioPlayer.js +33 -35
  5. package/es/AudioPlayer/initAudioPlayers.js +6 -1
  6. package/es/ContentTypeBadge/ContentTypeBadge.js +27 -6
  7. package/es/Embed/AudioEmbed.js +44 -188
  8. package/es/Embed/BrightcoveEmbed.js +32 -127
  9. package/es/Embed/ConceptEmbed.js +53 -75
  10. package/es/Embed/EmbedErrorPlaceholder.js +41 -0
  11. package/es/Embed/ExternalEmbed.js +5 -12
  12. package/es/Embed/H5pEmbed.js +5 -15
  13. package/es/Embed/IframeEmbed.js +4 -4
  14. package/es/Embed/ImageEmbed.js +41 -153
  15. package/es/Embed/RelatedContentEmbed.js +3 -3
  16. package/es/Embed/conceptComponents.js +62 -228
  17. package/es/Embed/types.js +1 -0
  18. package/es/KeyFigure/KeyFigure.js +57 -0
  19. package/es/{KeyPerformanceIndicator → KeyFigure}/index.js +1 -1
  20. package/es/LicenseByline/EmbedByline.js +33 -8
  21. package/es/LicenseByline/LicenseDescription.js +16 -14
  22. package/es/List/OrderedList.js +48 -0
  23. package/es/List/UnOrderedList.js +36 -0
  24. package/es/List/index.js +10 -0
  25. package/es/Navigation/NavigationBox.js +41 -48
  26. package/es/Navigation/NavigationHeading.js +18 -29
  27. package/es/Notion/Notion.js +5 -5
  28. package/es/Resource/ListResource.js +9 -9
  29. package/es/Resource/resourceComponents.js +12 -11
  30. package/es/Typography/Heading.js +38 -0
  31. package/es/Typography/index.js +9 -0
  32. package/es/all.css +1 -1
  33. package/es/index.js +4 -2
  34. package/es/locale/messages-en.js +6 -2
  35. package/es/locale/messages-nb.js +6 -2
  36. package/es/locale/messages-nn.js +6 -2
  37. package/es/locale/messages-se.js +6 -2
  38. package/es/locale/messages-sma.js +6 -2
  39. package/es/model/ContentType.js +7 -1
  40. package/lib/Article/Article.d.ts +1 -3
  41. package/lib/Article/Article.js +7 -13
  42. package/lib/Article/ArticleByline.d.ts +3 -5
  43. package/lib/Article/ArticleByline.js +83 -126
  44. package/lib/Article/ArticleFootNotes.js +16 -11
  45. package/lib/AudioPlayer/AudioPlayer.d.ts +1 -2
  46. package/lib/AudioPlayer/AudioPlayer.js +33 -36
  47. package/lib/AudioPlayer/initAudioPlayers.d.ts +1 -0
  48. package/lib/AudioPlayer/initAudioPlayers.js +9 -3
  49. package/lib/ContentTypeBadge/ContentTypeBadge.js +27 -6
  50. package/lib/Embed/AudioEmbed.d.ts +3 -2
  51. package/lib/Embed/AudioEmbed.js +53 -192
  52. package/lib/Embed/BrightcoveEmbed.d.ts +3 -1
  53. package/lib/Embed/BrightcoveEmbed.js +32 -126
  54. package/lib/Embed/ConceptEmbed.d.ts +7 -2
  55. package/lib/Embed/ConceptEmbed.js +51 -73
  56. package/lib/Embed/EmbedErrorPlaceholder.d.ts +17 -0
  57. package/lib/Embed/EmbedErrorPlaceholder.js +48 -0
  58. package/lib/Embed/ExternalEmbed.js +5 -11
  59. package/lib/Embed/H5pEmbed.js +5 -14
  60. package/lib/Embed/IframeEmbed.d.ts +2 -2
  61. package/lib/Embed/IframeEmbed.js +4 -4
  62. package/lib/Embed/ImageEmbed.d.ts +3 -10
  63. package/lib/Embed/ImageEmbed.js +48 -161
  64. package/lib/Embed/RelatedContentEmbed.js +3 -3
  65. package/lib/Embed/conceptComponents.d.ts +4 -2
  66. package/lib/Embed/conceptComponents.js +67 -231
  67. package/lib/Embed/index.d.ts +1 -0
  68. package/lib/Embed/types.d.ts +14 -0
  69. package/lib/Embed/types.js +5 -0
  70. package/lib/KeyFigure/KeyFigure.d.ts +10 -0
  71. package/lib/KeyFigure/KeyFigure.js +62 -0
  72. package/lib/KeyFigure/index.d.ts +1 -0
  73. package/lib/KeyFigure/index.js +13 -0
  74. package/lib/LicenseByline/EmbedByline.d.ts +10 -2
  75. package/lib/LicenseByline/EmbedByline.js +32 -7
  76. package/lib/LicenseByline/LicenseDescription.d.ts +3 -1
  77. package/lib/LicenseByline/LicenseDescription.js +14 -13
  78. package/lib/List/OrderedList.d.ts +15 -0
  79. package/lib/List/OrderedList.js +56 -0
  80. package/lib/List/UnOrderedList.d.ts +10 -0
  81. package/lib/List/UnOrderedList.js +43 -0
  82. package/lib/List/index.d.ts +9 -0
  83. package/lib/List/index.js +20 -0
  84. package/lib/Navigation/NavigationBox.js +40 -47
  85. package/lib/Navigation/NavigationHeading.js +17 -28
  86. package/lib/Notion/Notion.js +5 -5
  87. package/lib/Resource/ListResource.js +8 -8
  88. package/lib/Resource/resourceComponents.js +12 -11
  89. package/lib/Typography/Heading.d.ts +26 -0
  90. package/lib/Typography/Heading.js +45 -0
  91. package/lib/Typography/index.d.ts +8 -0
  92. package/lib/Typography/index.js +13 -0
  93. package/lib/all.css +1 -1
  94. package/lib/index.d.ts +4 -1
  95. package/lib/index.js +23 -3
  96. package/lib/locale/messages-en.d.ts +4 -0
  97. package/lib/locale/messages-en.js +6 -2
  98. package/lib/locale/messages-nb.d.ts +4 -0
  99. package/lib/locale/messages-nb.js +6 -2
  100. package/lib/locale/messages-nn.d.ts +4 -0
  101. package/lib/locale/messages-nn.js +6 -2
  102. package/lib/locale/messages-se.d.ts +4 -0
  103. package/lib/locale/messages-se.js +6 -2
  104. package/lib/locale/messages-sma.d.ts +4 -0
  105. package/lib/locale/messages-sma.js +6 -2
  106. package/lib/model/ContentType.d.ts +1 -0
  107. package/lib/model/ContentType.js +9 -2
  108. package/package.json +15 -15
  109. package/src/Article/Article.tsx +1 -8
  110. package/src/Article/ArticleByline.tsx +78 -127
  111. package/src/Article/ArticleFootNotes.tsx +33 -10
  112. package/src/Article/component.article.scss +1 -52
  113. package/src/Article/component.footnotes.scss +2 -2
  114. package/src/Aside/component.aside.scss +3 -3
  115. package/src/AudioPlayer/AudioPlayer.tsx +11 -24
  116. package/src/AudioPlayer/initAudioPlayers.tsx +7 -2
  117. package/src/ContentTypeBadge/ContentTypeBadge.tsx +29 -6
  118. package/src/ContentTypeBadge/component.content-type-badge.scss +9 -3
  119. package/src/Dialog/component.dialog.scss +4 -5
  120. package/src/Embed/AudioEmbed.stories.tsx +5 -3
  121. package/src/Embed/AudioEmbed.tsx +45 -192
  122. package/src/Embed/BrightcoveEmbed.stories.tsx +5 -1
  123. package/src/Embed/BrightcoveEmbed.tsx +24 -98
  124. package/src/Embed/ConceptEmbed.stories.tsx +5 -0
  125. package/src/Embed/ConceptEmbed.tsx +43 -54
  126. package/src/Embed/EmbedErrorPlaceholder.tsx +59 -0
  127. package/src/Embed/ExternalEmbed.stories.tsx +86 -0
  128. package/src/Embed/ExternalEmbed.tsx +3 -8
  129. package/src/Embed/H5pEmbed.stories.tsx +92 -0
  130. package/src/Embed/H5pEmbed.tsx +3 -11
  131. package/src/Embed/IframeEmbed.stories.tsx +130 -0
  132. package/src/Embed/IframeEmbed.tsx +3 -3
  133. package/src/Embed/ImageEmbed.stories.tsx +3 -1
  134. package/src/Embed/ImageEmbed.tsx +21 -116
  135. package/src/Embed/RelatedContentEmbed.tsx +3 -1
  136. package/src/Embed/conceptComponents.tsx +67 -257
  137. package/src/Embed/index.ts +1 -0
  138. package/src/Embed/types.ts +12 -0
  139. package/src/FactBox/component.factbox.scss +3 -3
  140. package/src/Figure/component.figure-license.scss +4 -4
  141. package/src/Figure/component.figure.scss +1 -1
  142. package/src/KeyFigure/KeyFigure.stories.tsx +36 -0
  143. package/src/{KeyPerformanceIndicator/KeyPerformanceIndicator.tsx → KeyFigure/KeyFigure.tsx} +9 -7
  144. package/src/{KeyPerformanceIndicator → KeyFigure}/index.ts +1 -1
  145. package/src/LicenseByline/EmbedByline.stories.tsx +1 -0
  146. package/src/LicenseByline/EmbedByline.tsx +57 -9
  147. package/src/LicenseByline/LicenseDescription.tsx +9 -3
  148. package/src/List/OrderedList.tsx +115 -0
  149. package/src/List/UnOrderedList.tsx +49 -0
  150. package/src/List/index.ts +10 -0
  151. package/src/MediaList/component.medialist.scss +2 -2
  152. package/src/Navigation/NavigationBox.tsx +10 -14
  153. package/src/Navigation/NavigationHeading.tsx +15 -24
  154. package/src/Notion/Notion.tsx +1 -1
  155. package/src/RelatedArticleList/component.related-articles.scss +3 -13
  156. package/src/Resource/ListResource.tsx +6 -2
  157. package/src/Resource/resourceComponents.tsx +4 -2
  158. package/src/Table/component.tables.scss +0 -46
  159. package/src/Translation/component.translation.scss +3 -5
  160. package/src/Typography/Heading.tsx +96 -0
  161. package/src/Typography/index.ts +9 -0
  162. package/src/index.ts +5 -1
  163. package/src/locale/messages-en.ts +4 -0
  164. package/src/locale/messages-nb.ts +4 -0
  165. package/src/locale/messages-nn.ts +4 -0
  166. package/src/locale/messages-se.ts +4 -0
  167. package/src/locale/messages-sma.ts +4 -0
  168. package/src/model/ContentType.ts +7 -0
  169. package/es/KeyPerformanceIndicator/KeyPerformanceIndicator.js +0 -57
  170. package/lib/KeyPerformanceIndicator/KeyPerformanceIndicator.d.ts +0 -8
  171. package/lib/KeyPerformanceIndicator/KeyPerformanceIndicator.js +0 -62
  172. package/lib/KeyPerformanceIndicator/index.d.ts +0 -1
  173. package/lib/KeyPerformanceIndicator/index.js +0 -13
  174. 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 Modal, { ModalHeader, ModalBody, ModalCloseButton } from '@ndla/modal';
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 { LicenseByline } from '@ndla/notion';
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('14px', '18px')};
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
- margin-top: 10px;
32
- `;
33
-
34
- const ButtonWrapper = styled.div`
35
- margin-top: 18px;
36
- button {
37
- margin-bottom: 10px;
38
- margin-right: 16px;
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
- copyEmbedLink?: string;
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
- license,
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
- const copyLinkHandler = () => {
103
- if (copyPageUrlLink) {
104
- copyTextToClipboard(copyPageUrlLink);
105
- }
106
- };
107
- const licenseRights = getLicenseByAbbreviation(license, locale).rights;
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
- <div>
128
- {t('article.lastUpdated')} {published}
129
- </div>
130
- {(showPrimaryContributors || licenseRights.length > 0) && (
131
- <TextWrapper>
132
- <LicenseByline licenseRights={licenseRights}>
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
- </LicenseByline>
144
- </TextWrapper>
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
- <ButtonWrapper>
149
+ <AccordionRoot type="multiple" onValueChange={setOpenAccordions} value={openAccordions}>
148
150
  {licenseBox && (
149
- <Modal
150
- labelledBy={buttonId}
151
- activateButton={
152
- <ButtonV2 id={buttonId} size="small" shape="pill" variant="outline">
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
- {copyPageUrlLink && (
184
- <CopyButton
185
- onClick={copyLinkHandler}
186
- size="small"
187
- shape="pill"
188
- variant="outline"
189
- aria-live="assertive"
190
- data-copy-string={copyPageUrlLink}
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
- </ButtonWrapper>
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 className="c-footnotes__item">
20
- <cite className="c-footnotes__cite" id={`note${footNote.ref}`}>
21
- <sup>
22
- <a href={`#ref${footNote.ref}`} target="_self">
23
- {footNote.ref}
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
- </cite>
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
- <ol className="c-footnotes">
67
+ <FootnoteList>
45
68
  {footNotes.map((footNote) => (
46
69
  <FootNote key={footNote.ref} footNote={footNote} />
47
70
  ))}
48
- </ol>
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 inuit-font-size(16px, 20px);
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 inuit-font-size(15px);
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 inuit-font-size(15px);
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 inuit-font-size(16px);
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 inuit-font-size(22px, 34px);
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 inuit-font-size(16px);
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, useEffect, useRef, useState } from 'react';
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
- export const truncateDescription = (el: HTMLElement, readMoreLabel: string | null) => {
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?: ReactNode;
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 descriptionRef = useRef<HTMLDivElement>(null);
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
- <div
248
- ref={descriptionRef}
249
- data-audio-player-description={1}
250
- data-read-more-text={t('audio.readMoreDescriptionLabel')}
251
- >
252
- {description}
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
- import { truncateDescription } from './AudioPlayer';
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
- if (background) {
36
- modifiers.push('background');
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: #B9B37B;
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 inuit-font-size(22px, 26px);
20
+ @include font-size(22px, 26px);
21
21
  }
22
22
  }
23
23
  &--small-heading {
24
24
  h1 {
25
- @include inuit-font-size(22px, 26px);
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(20px);
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;