@ndla/ui 46.1.0 → 47.1.0

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 (84) hide show
  1. package/es/Article/Article.js +7 -20
  2. package/es/Embed/AudioEmbed.js +6 -14
  3. package/es/Embed/BrightcoveEmbed.js +13 -5
  4. package/es/Embed/ConceptEmbed.js +16 -14
  5. package/es/Embed/ImageEmbed.js +11 -4
  6. package/es/Embed/conceptComponents.js +11 -12
  7. package/es/Footer/FooterLinks.js +6 -6
  8. package/es/FrontpageArticle/FrontpageArticle.js +8 -12
  9. package/es/LicenseByline/EmbedByline.js +7 -15
  10. package/es/Messages/MessageBanner.js +4 -13
  11. package/es/Messages/MessageBox.js +10 -20
  12. package/es/Navigation/NavigationTopicAbout.js +15 -17
  13. package/es/Notion/Notion.js +8 -7
  14. package/es/SearchTypeResult/SearchFieldHeader.js +4 -4
  15. package/es/ToolboxPage/ToolboxInfo.js +4 -13
  16. package/es/Topic/Topic.js +31 -37
  17. package/es/all.css +1 -1
  18. package/es/locale/messages-en.js +12 -0
  19. package/es/locale/messages-nb.js +12 -0
  20. package/es/locale/messages-nn.js +12 -0
  21. package/es/locale/messages-se.js +12 -0
  22. package/es/locale/messages-sma.js +12 -0
  23. package/lib/Article/Article.d.ts +2 -4
  24. package/lib/Article/Article.js +6 -19
  25. package/lib/Embed/AudioEmbed.js +6 -15
  26. package/lib/Embed/BrightcoveEmbed.js +12 -4
  27. package/lib/Embed/ConceptEmbed.js +15 -13
  28. package/lib/Embed/ImageEmbed.js +10 -3
  29. package/lib/Embed/conceptComponents.d.ts +1 -1
  30. package/lib/Embed/conceptComponents.js +11 -12
  31. package/lib/Footer/FooterLinks.js +6 -6
  32. package/lib/FrontpageArticle/FrontpageArticle.js +6 -10
  33. package/lib/LicenseByline/EmbedByline.d.ts +2 -2
  34. package/lib/LicenseByline/EmbedByline.js +8 -16
  35. package/lib/Messages/MessageBanner.d.ts +2 -1
  36. package/lib/Messages/MessageBanner.js +5 -13
  37. package/lib/Messages/MessageBox.d.ts +2 -1
  38. package/lib/Messages/MessageBox.js +11 -19
  39. package/lib/Navigation/NavigationTopicAbout.d.ts +2 -3
  40. package/lib/Navigation/NavigationTopicAbout.js +15 -17
  41. package/lib/Notion/Notion.js +7 -6
  42. package/lib/SearchTypeResult/SearchFieldHeader.js +4 -4
  43. package/lib/TagSelector/ariaMessages.d.ts +1 -1
  44. package/lib/ToolboxPage/ToolboxInfo.js +3 -13
  45. package/lib/Topic/Topic.d.ts +2 -3
  46. package/lib/Topic/Topic.js +30 -36
  47. package/lib/all.css +1 -1
  48. package/lib/locale/messages-en.d.ts +12 -0
  49. package/lib/locale/messages-en.js +12 -0
  50. package/lib/locale/messages-nb.d.ts +12 -0
  51. package/lib/locale/messages-nb.js +12 -0
  52. package/lib/locale/messages-nn.d.ts +12 -0
  53. package/lib/locale/messages-nn.js +12 -0
  54. package/lib/locale/messages-se.d.ts +12 -0
  55. package/lib/locale/messages-se.js +12 -0
  56. package/lib/locale/messages-sma.d.ts +12 -0
  57. package/lib/locale/messages-sma.js +12 -0
  58. package/lib/types.d.ts +1 -1
  59. package/package.json +25 -26
  60. package/src/Article/Article.tsx +5 -24
  61. package/src/Article/component.article.scss +4 -4
  62. package/src/Embed/AudioEmbed.tsx +5 -11
  63. package/src/Embed/BrightcoveEmbed.tsx +10 -7
  64. package/src/Embed/ConceptEmbed.stories.tsx +1 -1
  65. package/src/Embed/ConceptEmbed.tsx +9 -4
  66. package/src/Embed/ImageEmbed.tsx +12 -2
  67. package/src/Embed/conceptComponents.tsx +2 -3
  68. package/src/Footer/FooterLinks.tsx +1 -1
  69. package/src/FrontpageArticle/FrontpageArticle.tsx +6 -16
  70. package/src/LicenseByline/EmbedByline.tsx +4 -11
  71. package/src/Messages/MessageBanner.tsx +3 -8
  72. package/src/Messages/MessageBox.tsx +3 -8
  73. package/src/Navigation/NavigationTopicAbout.tsx +2 -5
  74. package/src/Notion/Notion.tsx +2 -2
  75. package/src/SearchTypeResult/SearchFieldHeader.tsx +4 -4
  76. package/src/TagSelector/ariaMessages.ts +1 -1
  77. package/src/ToolboxPage/ToolboxInfo.tsx +3 -19
  78. package/src/Topic/Topic.tsx +6 -15
  79. package/src/locale/messages-en.ts +13 -0
  80. package/src/locale/messages-nb.ts +13 -0
  81. package/src/locale/messages-nn.ts +13 -0
  82. package/src/locale/messages-se.ts +13 -0
  83. package/src/locale/messages-sma.ts +13 -0
  84. package/src/types.ts +1 -1
@@ -221,6 +221,18 @@ declare const messages: {
221
221
  text: string;
222
222
  };
223
223
  };
224
+ myProfile: {
225
+ title: string;
226
+ disclaimerTitle: string;
227
+ disclaimerText: string;
228
+ preferenceTitle: string;
229
+ preferenceText: string;
230
+ editButtonText: string;
231
+ radioButtonText: {
232
+ option1: string;
233
+ option2: string;
234
+ };
235
+ };
224
236
  resource: {
225
237
  add: string;
226
238
  remove: string;
@@ -1227,6 +1227,18 @@ var messages = _objectSpread(_objectSpread({
1227
1227
  text: 'When you save a resource, you will have the option to tag it with a keyword. This tag can be used to find the resource across folders. By selecting <strong>My tags</strong> on the menu to the left, you will see all the tags your have used. You can also see which resources are tagget with which keyword.'
1228
1228
  }
1229
1229
  },
1230
+ myProfile: {
1231
+ title: 'My Profile',
1232
+ disclaimerTitle: 'Where is my picture and name used?',
1233
+ disclaimerText: 'Your picture and name are displayed when you participate in discussions in the arena.',
1234
+ preferenceTitle: 'Choose whether you want to display name when sharing a folder',
1235
+ preferenceText: 'Here you can choose whether you want to display your name when you share a folder. The selected option applies to all your folders and can be changed later. If you later change the option, your name will appear on all your shared folders.',
1236
+ editButtonText: 'Change profile picture',
1237
+ radioButtonText: {
1238
+ option1: 'Show my name when I share a folder',
1239
+ option2: 'Do not show my name when I share a folder'
1240
+ }
1241
+ },
1230
1242
  resource: {
1231
1243
  add: 'Add folder/tag',
1232
1244
  remove: 'Remove',
@@ -221,6 +221,18 @@ declare const messages: {
221
221
  text: string;
222
222
  };
223
223
  };
224
+ myProfile: {
225
+ title: string;
226
+ disclaimerTitle: string;
227
+ disclaimerText: string;
228
+ preferenceTitle: string;
229
+ preferenceText: string;
230
+ editButtonText: string;
231
+ radioButtonText: {
232
+ option1: string;
233
+ option2: string;
234
+ };
235
+ };
224
236
  resource: {
225
237
  add: string;
226
238
  remove: string;
@@ -1225,6 +1225,18 @@ var messages = _objectSpread(_objectSpread({
1225
1225
  text: 'Når du lagrer en ressurs, får du mulighet til å markere ressursen med en emneknagg. Emneknaggen er et nøkkelord du kan bruke til å finne tilbake til ressurser på tvers av mapper. Du finner alle emneknaggene du har brukt, ved å velge <strong>Mine emneknagger</strong> i venstremenyen. Her kan du også se hvilke ressurser du har markert med hvilken emneknagg.'
1226
1226
  }
1227
1227
  },
1228
+ myProfile: {
1229
+ title: 'Min Profil',
1230
+ disclaimerTitle: 'Hvor brukes bildet og navnet mitt?',
1231
+ disclaimerText: 'Bilde og navn vises når du deltar i diskusjoner i arenaen.',
1232
+ preferenceTitle: 'Velg om du vil vise navn når du deler en mappe',
1233
+ preferenceText: 'Her kan du selv velge om du vil vise navnet ditt når du deler en mappe. Valget gjelder for alle mappene dine og kan endres senere. Dersom du endrer vil navnet ditt vises på alle dine delte mapper.',
1234
+ editButtonText: 'Endre profilbilde',
1235
+ radioButtonText: {
1236
+ option1: 'Vis navnet mitt når jeg deler en mappe',
1237
+ option2: 'Ikke vis navnet mitt når jeg deler mappe'
1238
+ }
1239
+ },
1228
1240
  resource: {
1229
1241
  add: 'Legg til mappe/emneknagg',
1230
1242
  remove: 'Fjern',
@@ -221,6 +221,18 @@ declare const messages: {
221
221
  text: string;
222
222
  };
223
223
  };
224
+ myProfile: {
225
+ title: string;
226
+ disclaimerTitle: string;
227
+ disclaimerText: string;
228
+ preferenceTitle: string;
229
+ preferenceText: string;
230
+ editButtonText: string;
231
+ radioButtonText: {
232
+ option1: string;
233
+ option2: string;
234
+ };
235
+ };
224
236
  resource: {
225
237
  add: string;
226
238
  remove: string;
@@ -1225,6 +1225,18 @@ var messages = _objectSpread(_objectSpread({
1225
1225
  text: 'Når du lagrar ein ressurs, får du høve til å markere ressursen med ein emneknagg. Emneknaggen er eit nøkkelord du kan bruke til å finne tilbake til ressursar på tvers av mapper. Du finn alle emneknaggane du har brukt, ved å velje <strong>Mine emneknaggar</strong> i venstremenyen. Her kan du også sjå kva for ressursar du har merkt med kva knagg.'
1226
1226
  }
1227
1227
  },
1228
+ myProfile: {
1229
+ title: 'Min Profil',
1230
+ disclaimerTitle: 'Kvar blir biletet og namnet mitt brukt?',
1231
+ disclaimerText: 'Bilete og namn vert vist når du deltek i diskusjonar i arenaen.',
1232
+ preferenceTitle: 'Vel om du vil vise namn når du deler ei mappe',
1233
+ preferenceText: 'Her kan du sjølv velje om du vil vise namnet ditt når du deler ei mappe. Valet gjeld for alle mappene dine og kan endrast seinare. Dersom du endrar vil namnet ditt visast på alle dine delte mapper.',
1234
+ editButtonText: 'Endre profilbilete',
1235
+ radioButtonText: {
1236
+ option1: 'Vis namnet mitt når eg deler ei mappe',
1237
+ option2: 'Ikkje vis namnet mitt når eg deler mappe'
1238
+ }
1239
+ },
1228
1240
  resource: {
1229
1241
  add: 'Legg til mappe/emneknagg',
1230
1242
  remove: 'Fjern',
@@ -221,6 +221,18 @@ declare const messages: {
221
221
  text: string;
222
222
  };
223
223
  };
224
+ myProfile: {
225
+ title: string;
226
+ disclaimerTitle: string;
227
+ disclaimerText: string;
228
+ preferenceTitle: string;
229
+ preferenceText: string;
230
+ editButtonText: string;
231
+ radioButtonText: {
232
+ option1: string;
233
+ option2: string;
234
+ };
235
+ };
224
236
  resource: {
225
237
  add: string;
226
238
  remove: string;
@@ -1225,6 +1225,18 @@ var messages = _objectSpread(_objectSpread({
1225
1225
  text: 'Go vurket muhtin resurssa de lea vejolaš merket resurssa fáddágilkoriin. Fáddágilkor lea čoavddasátni man sáhtát geavahit gávdnan dihte ruovttoluotta resurssaide máhpaid rastá. Gávnnat buot fáddágilkoriid maid leat geavahan go válljet mu fáddágilkoriid gurut bealde fálus. Das oainnát maiddái maid resurssaid don leat merken juohke fáddágilkoriin.'
1226
1226
  }
1227
1227
  },
1228
+ myProfile: {
1229
+ title: 'Mu profiila',
1230
+ disclaimerTitle: 'Gos geavahit mu gova ja mu nama?',
1231
+ disclaimerText: 'Govva ja namma čájehuvvojit go searvat digaštallamii arenain.',
1232
+ preferenceTitle: 'Vállje jos namma čájehuvvo máhpa juohkkedettiin',
1233
+ preferenceText: 'Dás válljet jos iežat namma čájehuvvo juohkkedettiin máhpa. Dát molssaeaktu guoská buot máhpaide ja sáhttá rievdaduvvot maŋŋil. Jos rievdadat dán, de čájehuvvo du namma buot juogaduvvon máhpain.',
1234
+ editButtonText: 'Rievdat profiilagova',
1235
+ radioButtonText: {
1236
+ option1: 'Čájet mu nama máhpa juohkkedettiin',
1237
+ option2: 'Ale čájet mu nama máhpa juohkkedettiin'
1238
+ }
1239
+ },
1228
1240
  resource: {
1229
1241
  add: 'Lasit máhpa/fáddágilkora',
1230
1242
  remove: 'Sihko',
@@ -221,6 +221,18 @@ declare const messages: {
221
221
  text: string;
222
222
  };
223
223
  };
224
+ myProfile: {
225
+ title: string;
226
+ disclaimerTitle: string;
227
+ disclaimerText: string;
228
+ preferenceTitle: string;
229
+ preferenceText: string;
230
+ editButtonText: string;
231
+ radioButtonText: {
232
+ option1: string;
233
+ option2: string;
234
+ };
235
+ };
224
236
  resource: {
225
237
  add: string;
226
238
  remove: string;
@@ -1225,6 +1225,18 @@ var messages = _objectSpread(_objectSpread({
1225
1225
  text: 'Når du lagrar ein ressurs, får du høve til å markere ressursen med ein emneknagg. Emneknaggen er eit nøkkelord du kan bruke til å finne tilbake til ressursar på tvers av mapper. Du finn alle emneknaggane du har brukt, ved å velje <strong>Mine emneknaggar</strong> i venstremenyen. Her kan du også sjå kva for ressursar du har merkt med kva knagg.'
1226
1226
  }
1227
1227
  },
1228
+ myProfile: {
1229
+ title: 'Mov Profijle',
1230
+ disclaimerTitle: 'Gusnie guvvie jïh nomme åtnasuvvieh?',
1231
+ disclaimerText: 'Guvvie jïh nomme våajnoes sjidtieh gosse meatan digkiedimmesne sijjesne.',
1232
+ preferenceTitle: 'Sjïehtedh jis edtja nommem vuesiehtidh gosse maabpam juekedh',
1233
+ preferenceText: 'Daesnie jïjtje veeljh mejtie sïjhth dov nommem vuesiehtidh gosse maabpam juekedh . Daate veeljeme lea gaajhkine dov maabpojne, jïh maahta dam mænngan jarkelidh. Jis jeatjahdahtah , dov nomme sæjhta våajnoes årrodh gaajhkine dov joekedamme maabpojne.',
1234
+ editButtonText: 'Naemhtie profijleguvviem jarkelidh',
1235
+ radioButtonText: {
1236
+ option1: 'Vuesehth mov nommem gosse maabpam juekieh',
1237
+ option2: 'Aellieh mov nommem vuesehth gosse maabpam juekieh'
1238
+ }
1239
+ },
1228
1240
  resource: {
1229
1241
  add: 'Legg til mappe/emneknagg',
1230
1242
  remove: 'Fjern',
package/lib/types.d.ts CHANGED
@@ -57,7 +57,7 @@ export interface FootNote {
57
57
  }
58
58
  export interface Article {
59
59
  title: string;
60
- introduction: string;
60
+ introduction: ReactNode;
61
61
  content: ReactNode;
62
62
  footNotes: Array<FootNote>;
63
63
  copyright?: Copyright;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ndla/ui",
3
- "version": "46.1.0",
3
+ "version": "47.1.0",
4
4
  "description": "UI component library for NDLA.",
5
5
  "license": "GPL-3.0",
6
6
  "main": "lib/index.js",
@@ -31,43 +31,42 @@
31
31
  "types"
32
32
  ],
33
33
  "dependencies": {
34
- "@ndla/accordion": "^2.2.25",
35
- "@ndla/button": "^11.0.10",
36
- "@ndla/carousel": "^4.0.3",
37
- "@ndla/core": "^4.1.9",
38
- "@ndla/dropdown-menu": "^1.0.7",
39
- "@ndla/forms": "^5.0.0",
40
- "@ndla/hooks": "^2.1.0",
41
- "@ndla/icons": "^4.0.9",
34
+ "@ndla/accordion": "^2.2.27",
35
+ "@ndla/button": "^12.0.1",
36
+ "@ndla/carousel": "^4.0.4",
37
+ "@ndla/core": "^4.2.0",
38
+ "@ndla/dropdown-menu": "^1.0.9",
39
+ "@ndla/forms": "^5.0.2",
40
+ "@ndla/hooks": "^2.1.1",
41
+ "@ndla/icons": "^4.0.10",
42
42
  "@ndla/licenses": "^7.1.4",
43
- "@ndla/modal": "^4.0.10",
44
- "@ndla/notion": "^6.0.0",
45
- "@ndla/safelink": "^4.1.24",
46
- "@ndla/select": "^2.4.16",
47
- "@ndla/switch": "^1.1.14",
48
- "@ndla/tabs": "^3.0.10",
49
- "@ndla/tooltip": "^4.1.21",
50
- "@ndla/typography": "^0.2.1",
51
- "@ndla/util": "^3.2.0",
52
- "@radix-ui/react-popover": "^1.0.6",
43
+ "@ndla/modal": "^5.0.1",
44
+ "@ndla/notion": "^6.0.2",
45
+ "@ndla/safelink": "^4.1.26",
46
+ "@ndla/select": "^3.0.1",
47
+ "@ndla/switch": "^1.1.15",
48
+ "@ndla/tabs": "^3.0.11",
49
+ "@ndla/tooltip": "^5.0.1",
50
+ "@ndla/typography": "^0.2.2",
51
+ "@ndla/util": "^4.0.0",
52
+ "@radix-ui/react-popover": "^1.0.7",
53
53
  "@radix-ui/react-radio-group": "^1.1.3",
54
54
  "@radix-ui/react-slider": "^1.1.2",
55
55
  "date-fns": "^2.30.0",
56
- "html-react-parser": "^3.0.8",
57
- "i18next-browser-languagedetector": "^6.1.1",
56
+ "html-react-parser": "^4.2.2",
57
+ "i18next-browser-languagedetector": "^7.1.0",
58
58
  "react-bem-helper": "1.4.1",
59
59
  "react-device-detect": "^2.2.3",
60
60
  "react-select": "^5.7.5",
61
- "react-swipeable": "^7.0.0",
62
- "remarkable": "^2.0.1"
61
+ "react-swipeable": "^7.0.0"
63
62
  },
64
63
  "peerDependencies": {
65
64
  "@emotion/react": "^11.10.4",
66
65
  "@emotion/styled": "^11.10.4",
67
- "i18next": "^21.9.2",
66
+ "i18next": "^23.5.1",
68
67
  "lodash": "^4.17.20",
69
68
  "react": ">= 16.8.0",
70
- "react-i18next": "^11.18.6"
69
+ "react-i18next": "^13.3.0"
71
70
  },
72
71
  "devDependencies": {
73
72
  "@ndla/types-backend": "^0.2.21",
@@ -81,5 +80,5 @@
81
80
  "publishConfig": {
82
81
  "access": "public"
83
82
  },
84
- "gitHead": "444537e1bc636e9ed92272c88da91c83932b9a53"
83
+ "gitHead": "79769e1b2806335328635dda5e33e7d02b8868d7"
85
84
  }
@@ -8,13 +8,12 @@
8
8
 
9
9
  import { ReactNode, useEffect, useRef, useState, forwardRef } from 'react';
10
10
  import BEMHelper from 'react-bem-helper';
11
- import parse from 'html-react-parser';
12
11
  import styled from '@emotion/styled';
13
12
 
14
13
  import { useIntersectionObserver } from '@ndla/hooks';
15
14
  import { resizeObserver } from '@ndla/util';
16
15
  import { spacing, spacingUnit, mq, breakpoints } from '@ndla/core';
17
- import { Heading } from '@ndla/typography';
16
+ import { Heading, Text } from '@ndla/typography';
18
17
  import { Article as ArticleType } from '../types';
19
18
  import ArticleByline from './ArticleByline';
20
19
  import LayoutItem from '../Layout';
@@ -72,29 +71,15 @@ export const ArticleTitle = ({ children, icon, label, id, lang }: ArticleTitlePr
72
71
 
73
72
  type ArticleIntroductionProps = {
74
73
  children: ReactNode;
75
- renderMarkdown: (text: string) => string;
76
74
  lang?: string;
77
75
  };
78
76
 
79
- export const ArticleIntroduction = ({
80
- children,
81
- lang,
82
- renderMarkdown = (text) => {
83
- return text;
84
- },
85
- }: ArticleIntroductionProps) => {
86
- if (typeof children === 'string') {
87
- return (
88
- <div className="article_introduction" lang={lang}>
89
- {parse(renderMarkdown(children))}
90
- </div>
91
- );
92
- }
77
+ export const ArticleIntroduction = ({ children, lang }: ArticleIntroductionProps) => {
93
78
  if (children) {
94
79
  return (
95
- <div className="article_introduction" lang={lang}>
80
+ <Text textStyle="ingress" element="div" lang={lang}>
96
81
  {children}
97
- </div>
82
+ </Text>
98
83
  );
99
84
  }
100
85
  return null;
@@ -135,7 +120,6 @@ type Props = {
135
120
  messageBoxLinks?: [];
136
121
  competenceGoals?: ReactNode;
137
122
  id: string;
138
- renderMarkdown: (text: string) => string;
139
123
  notions?: ReactNode;
140
124
  accessMessage?: string;
141
125
  lang?: string;
@@ -164,7 +148,6 @@ export const Article = ({
164
148
  competenceGoals,
165
149
  id,
166
150
  notions,
167
- renderMarkdown,
168
151
  accessMessage,
169
152
  heartButton,
170
153
  contentTransformed,
@@ -217,9 +200,7 @@ export const Article = ({
217
200
  <ArticleTitle id={id} icon={icon} label={messages.label} lang={lang}>
218
201
  {title}
219
202
  </ArticleTitle>
220
- <ArticleIntroduction renderMarkdown={renderMarkdown} lang={lang}>
221
- {introduction}
222
- </ArticleIntroduction>
203
+ <ArticleIntroduction lang={lang}>{introduction}</ArticleIntroduction>
223
204
  </ArticleHeaderWrapper>
224
205
  </LayoutItem>
225
206
  <LayoutItem layout="center">
@@ -26,7 +26,7 @@
26
26
  }
27
27
 
28
28
  @include mq(tablet) {
29
- @include font-size(20px, 35px);
29
+ @include font-size(18px, 29px);
30
30
 
31
31
  > section > p {
32
32
  &:not([class]) {
@@ -120,14 +120,14 @@
120
120
  }
121
121
  }
122
122
 
123
- padding: 0 0 $spacing--small 0;
123
+ padding: 0 0 $spacing 0;
124
124
 
125
125
  @include mq(tablet) {
126
- padding: 0 0 $spacing 0;
126
+ padding: 0 0 $spacing--medium 0;
127
127
  }
128
128
 
129
129
  p {
130
- @include font-size(16px, 20px);
130
+ @include font-size(18px, 24px);
131
131
  color: $text-light-color;
132
132
  text-transform: uppercase;
133
133
  margin-bottom: 0;
@@ -8,8 +8,6 @@
8
8
 
9
9
  import { AudioMetaData, ImageMetaData } from '@ndla/types-embed';
10
10
  import { COPYRIGHTED } from '@ndla/licenses';
11
- //@ts-ignore
12
- import { Remarkable } from 'remarkable';
13
11
  import AudioPlayer from '../AudioPlayer';
14
12
  import { Figure } from '../Figure';
15
13
  import { Author } from './ImageEmbed';
@@ -29,12 +27,6 @@ export const getFirstNonEmptyLicenseCredits = (authors: {
29
27
  processors: Author[];
30
28
  }) => Object.values(authors).find((i) => i.length > 0) ?? [];
31
29
 
32
- const renderMarkdown = (text: string) => {
33
- const md = new Remarkable();
34
- const rendered = md.render(text);
35
- return <span dangerouslySetInnerHTML={{ __html: rendered }} />;
36
- };
37
-
38
30
  const imageMetaToMockEmbed = (
39
31
  imageMeta: Extract<AudioMetaData, { status: 'success' }>,
40
32
  ): Extract<ImageMetaData, { status: 'success' }> => ({
@@ -62,8 +54,6 @@ const AudioEmbed = ({ embed, heartButton: HeartButton, lang }: Props) => {
62
54
 
63
55
  const subtitle = data.series ? { title: data.series.title.title, url: `/podkast/${data.series.id}` } : undefined;
64
56
 
65
- const textVersion = data.manuscript?.manuscript.length ? renderMarkdown(data.manuscript.manuscript) : undefined;
66
-
67
57
  const coverPhoto = data.podcastMeta?.coverPhoto;
68
58
 
69
59
  const img = coverPhoto && { url: coverPhoto.url, alt: coverPhoto.altText };
@@ -74,7 +64,11 @@ const AudioEmbed = ({ embed, heartButton: HeartButton, lang }: Props) => {
74
64
  description={data.podcastMeta?.introduction ?? ''}
75
65
  img={img}
76
66
  src={data.audioFile.url}
77
- textVersion={textVersion}
67
+ textVersion={
68
+ data.manuscript?.manuscript.length ? (
69
+ <span dangerouslySetInnerHTML={{ __html: data.manuscript.manuscript }} />
70
+ ) : undefined
71
+ }
78
72
  title={data.title.title}
79
73
  subtitle={subtitle}
80
74
  />
@@ -10,7 +10,8 @@ import sortBy from 'lodash/sortBy';
10
10
  import styled from '@emotion/styled';
11
11
  import { spacing } from '@ndla/core';
12
12
  import { COPYRIGHTED } from '@ndla/licenses';
13
- import { useEffect, useRef, useState } from 'react';
13
+ import { useEffect, useMemo, useRef, useState } from 'react';
14
+ import parse from 'html-react-parser';
14
15
  import { BrightcoveEmbedData, BrightcoveMetaData, BrightcoveVideoSource } from '@ndla/types-embed';
15
16
  import { useTranslation } from 'react-i18next';
16
17
  import { ButtonV2 } from '@ndla/button';
@@ -62,6 +63,13 @@ const BrightcoveEmbed = ({ embed, isConcept, heartButton: HeartButton }: Props)
62
63
  const iframeRef = useRef<HTMLIFrameElement>(null);
63
64
  const { embedData } = embed;
64
65
  const fallbackTitle = `${t('embed.type.video')}: ${embedData.videoid}`;
66
+ const parsedDescription = useMemo(() => {
67
+ if (embed.embedData.caption) {
68
+ return parse(embed.embedData.caption);
69
+ } else if (embed.status === 'success' && embed.data.description) {
70
+ return parse(embed.data.description);
71
+ }
72
+ }, [embed]);
65
73
 
66
74
  useEffect(() => {
67
75
  const iframe = iframeRef.current;
@@ -108,12 +116,7 @@ const BrightcoveEmbed = ({ embed, isConcept, heartButton: HeartButton }: Props)
108
116
  allowFullScreen
109
117
  />
110
118
  </div>
111
- <EmbedByline
112
- type="video"
113
- copyright={data.copyright!}
114
- description={embedData.caption ?? data.description ?? ''}
115
- bottomRounded
116
- >
119
+ <EmbedByline type="video" copyright={data.copyright!} description={parsedDescription} bottomRounded>
117
120
  {!!linkedVideoId && (
118
121
  <LinkedVideoButton
119
122
  variant="outline"
@@ -46,7 +46,7 @@ const conceptMetaData: ConceptData['concept'] = {
46
46
  title: { title: 'skin – formasjonsskade', language: 'nb' },
47
47
  content: {
48
48
  content:
49
- 'Ordet «skin» er engelsk og brukes om formasjonsskade som oppstår i boreprosessen i området som grenser inn til brønnen. Skaden er størst i området nærmest hullet, men den kan bre seg utover et stykke fra brønnen. Skin forteller om bergartens permeabilitet i reservoarsonen. \n\nHullveggen skades både av borekronen, små partikler og væsken som brukes i brønnen.\n\nSkaden i bergarten gir dårligere forhold for oljen som skal strømme til brønnen. Gangene i bergarten plugges, og det oppstår et trykkfall som reduserer produksjonstrykket i brønnen.\n\nDet er viktig å redusere omfanget av skaden ved å velge væsker som passer godt til bergartsegenskapene, og å bore med en borekrone som skader minst mulig.\n\nSkader som er dannet av borevæske, kan repareres ved å syrebehandle hullets overflate.\n',
49
+ ' <p>Ordet «skin» er engelsk og brukes om formasjonsskade som oppstår i boreprosessen i området som grenser inn til brønnen. Skaden er størst i området nærmest hullet, men den kan bre seg utover et stykke fra brønnen. Skin forteller om bergartens permeabilitet i reservoarsonen.</p> <p>Hullveggen skades både av borekronen, små partikler og væsken som brukes i brønnen.</p> <p>Skaden i bergarten gir dårligere forhold for oljen som skal strømme til brønnen. Gangene i bergarten plugges, og det oppstår et trykkfall som reduserer produksjonstrykket i brønnen.</p> <p>Det er viktig å redusere omfanget av skaden ved å velge væsker som passer godt til bergartsegenskapene, og å bore med en borekrone som skader minst mulig.</p> <p>Skader som er dannet av borevæske, kan repareres ved å syrebehandle hullets overflate.</p>',
50
50
  language: 'nb',
51
51
  },
52
52
  copyright: {
@@ -6,7 +6,8 @@
6
6
  *
7
7
  */
8
8
 
9
- import { ReactElement, ReactNode, useCallback, useRef, useState } from 'react';
9
+ import { ReactElement, ReactNode, useCallback, useMemo, useRef, useState } from 'react';
10
+ import parse from 'html-react-parser';
10
11
  import { useTranslation } from 'react-i18next';
11
12
  import styled from '@emotion/styled';
12
13
  import { isMobile } from 'react-device-detect';
@@ -92,6 +93,10 @@ const StyledButton = styled.button`
92
93
  `;
93
94
 
94
95
  export const ConceptEmbed = ({ embed, fullWidth, heartButton: HeartButton }: Props) => {
96
+ const parsedContent = useMemo(() => {
97
+ if (embed.status === 'error' || !embed.data.concept.content) return undefined;
98
+ return parse(embed.data.concept.content.content);
99
+ }, [embed]);
95
100
  if (embed.status === 'error' && embed.embedData.type === 'inline') {
96
101
  return <span>{embed.embedData.linkText}</span>;
97
102
  } else if (embed.status === 'error') {
@@ -107,7 +112,7 @@ export const ConceptEmbed = ({ embed, fullWidth, heartButton: HeartButton }: Pro
107
112
  <BlockConcept
108
113
  fullWidth={fullWidth}
109
114
  title={concept.title}
110
- content={concept.content?.content}
115
+ content={parsedContent}
111
116
  metaImage={concept.metaImage}
112
117
  copyright={concept.copyright}
113
118
  source={concept.source}
@@ -122,7 +127,7 @@ export const ConceptEmbed = ({ embed, fullWidth, heartButton: HeartButton }: Pro
122
127
  return (
123
128
  <InlineConcept
124
129
  title={concept.title}
125
- content={concept.content?.content}
130
+ content={parsedContent}
126
131
  metaImage={concept.metaImage}
127
132
  copyright={concept.copyright}
128
133
  source={concept.source}
@@ -138,7 +143,7 @@ export const ConceptEmbed = ({ embed, fullWidth, heartButton: HeartButton }: Pro
138
143
  return (
139
144
  <ConceptNotionV2
140
145
  title={concept.title}
141
- content={concept.content?.content}
146
+ content={parsedContent}
142
147
  metaImage={concept.metaImage}
143
148
  copyright={concept.copyright}
144
149
  source={concept.source}
@@ -8,7 +8,8 @@
8
8
 
9
9
  import { ImageEmbedData, ImageMetaData } from '@ndla/types-embed';
10
10
  import { useTranslation } from 'react-i18next';
11
- import { MouseEventHandler, useState } from 'react';
11
+ import { MouseEventHandler, useMemo, useState } from 'react';
12
+ import parse from 'html-react-parser';
12
13
  import { ExpandTwoArrows } from '@ndla/icons/action';
13
14
  import { COPYRIGHTED } from '@ndla/licenses';
14
15
  import { ArrowCollapse, ChevronDown, ChevronUp } from '@ndla/icons/common';
@@ -106,6 +107,15 @@ const expandedSizes = '(min-width: 1024px) 1024px, 100vw';
106
107
  const ImageEmbed = ({ embed, previewAlt, heartButton: HeartButton, inGrid, path }: Props) => {
107
108
  const [isBylineHidden, setIsBylineHidden] = useState(hideByline(embed.embedData.size));
108
109
  const [imageSizes, setImageSizes] = useState<string | undefined>(undefined);
110
+
111
+ const parsedDescription = useMemo(() => {
112
+ if (embed.embedData.caption) {
113
+ return parse(embed.embedData.caption);
114
+ } else if (embed.status === 'success' && embed.data.caption.caption) {
115
+ return parse(embed.data.caption.caption);
116
+ }
117
+ }, [embed]);
118
+
109
119
  if (embed.status === 'error') {
110
120
  const { align, size } = embed.embedData;
111
121
  const figureType = getFigureType(size, align);
@@ -158,7 +168,7 @@ const ImageEmbed = ({ embed, previewAlt, heartButton: HeartButton, inGrid, path
158
168
  <EmbedByline
159
169
  type="image"
160
170
  copyright={data.copyright}
161
- description={embedData.caption ?? data.caption.caption}
171
+ description={parsedDescription}
162
172
  bottomRounded
163
173
  visibleAlt={previewAlt ? embed.embedData.alt : ''}
164
174
  inGrid={inGrid}
@@ -11,7 +11,6 @@ import { ConceptData, ConceptVisualElementMeta } from '@ndla/types-embed';
11
11
  import { useTranslation } from 'react-i18next';
12
12
  import { css } from '@emotion/react';
13
13
  import { breakpoints, colors, fonts, misc, mq, spacing } from '@ndla/core';
14
- import { parseMarkdown } from '@ndla/util';
15
14
  import styled from '@emotion/styled';
16
15
  import { COPYRIGHTED } from '@ndla/licenses';
17
16
  import { Copyright } from '../types';
@@ -26,7 +25,7 @@ export type ConceptType = 'concept' | 'gloss';
26
25
 
27
26
  export interface ConceptNotionData {
28
27
  title: ConceptData['concept']['title'];
29
- content?: string;
28
+ content?: ReactNode;
30
29
  metaImage?: {
31
30
  url?: string;
32
31
  alt?: string;
@@ -210,7 +209,7 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
210
209
  ) : visualElement?.resource === 'external' ? (
211
210
  <ExternalEmbed embed={visualElement} />
212
211
  ) : null}
213
- <NotionDialogText>{parseMarkdown(content ?? '', 'body')}</NotionDialogText>
212
+ {content && <NotionDialogText>{content}</NotionDialogText>}
214
213
  </StyledNotionDialogContent>
215
214
  {tags && (
216
215
  <ListWrapper>
@@ -106,7 +106,7 @@ const FooterLinks = ({ links }: FooterLinksProps) => {
106
106
  {commonLinks.map((link) => (
107
107
  <div key={link.url}>
108
108
  <StyledSafeLink
109
- key={t<string>(`footer.ndlaLinks.${link.key}`)}
109
+ key={t(`footer.ndlaLinks.${link.key}`)}
110
110
  aria-label={t(`footer.ndlaLinks.${link.key}`)}
111
111
  to={link.url}
112
112
  target="_blank"
@@ -7,9 +7,9 @@
7
7
  */
8
8
 
9
9
  import { CSSProperties, ReactNode, useMemo } from 'react';
10
- import { breakpoints, fonts, mq, spacing, spacingUnit } from '@ndla/core';
10
+ import { spacing, spacingUnit } from '@ndla/core';
11
11
  import styled from '@emotion/styled';
12
- import { Heading } from '@ndla/typography';
12
+ import { Heading, Text } from '@ndla/typography';
13
13
  import { Article } from '../types';
14
14
  import { ArticleByline } from '../Article';
15
15
  import { useMastheadHeight } from '../Masthead';
@@ -56,18 +56,6 @@ const StyledArticle = styled.article`
56
56
  }
57
57
  `;
58
58
 
59
- const StyledIntroduction = styled.div`
60
- font-weight: ${fonts.weight.light};
61
- font-family: ${fonts.sans};
62
- margin-top: ${spacing.small};
63
- ${fonts.sizes('22px', '30px')};
64
-
65
- ${mq.range({ from: breakpoints.tablet })} {
66
- margin-top: ${spacing.mediumlarge};
67
- ${fonts.sizes('26px', '36px')};
68
- }
69
- `;
70
-
71
59
  export const FrontpageArticle = ({ article, id, isWide, licenseBox }: Props) => {
72
60
  const { height = 0 } = useMastheadHeight();
73
61
  const cssVars = useMemo(() => ({ '--masthead-height': `${height}px` } as unknown as CSSProperties), [height]);
@@ -83,10 +71,12 @@ export const FrontpageArticle = ({ article, id, isWide, licenseBox }: Props) =>
83
71
 
84
72
  return (
85
73
  <StyledArticle style={cssVars}>
86
- <Heading id={id} headingStyle="h1" element="h1" margin="normal" tabIndex={-1}>
74
+ <Heading id={id} headingStyle="h1-resource" element="h1" margin="normal" tabIndex={-1}>
87
75
  {title}
88
76
  </Heading>
89
- <StyledIntroduction>{introduction}</StyledIntroduction>
77
+ <Text textStyle="ingress" element="div">
78
+ {introduction}
79
+ </Text>
90
80
  {content}
91
81
  <ArticleByline accordionHeaderVariant={'white'} licenseBox={licenseBox} displayByline={false} />
92
82
  </StyledArticle>