@ndla/ui 3.3.7 → 3.3.12

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 (115) hide show
  1. package/es/Article/Article.js +23 -1
  2. package/es/Article/ArticleNotions.js +80 -32
  3. package/es/Breadcrumb/Breadcrumb.js +2 -1
  4. package/es/Breadcrumblist/Breadcrumblist.js +14 -10
  5. package/es/CloseButton/CloseButton.js +62 -0
  6. package/es/CloseButton/index.js +9 -0
  7. package/es/Frontpage/FrontpageAllSubjects.js +7 -7
  8. package/es/Frontpage/FrontpageProgramMenu.js +10 -10
  9. package/es/MediaList/MediaList.js +22 -73
  10. package/es/MessageBox/MessageBox.js +146 -78
  11. package/es/MessageBox/MessageBoxTag.js +37 -0
  12. package/es/MessageBox/index.js +3 -1
  13. package/es/NDLAFilm/FilmSlideshow.js +214 -247
  14. package/es/NDLAFilm/NavigationArrow.js +13 -60
  15. package/es/NDLAFilm/SlideshowIndicator.js +16 -63
  16. package/es/NDLAFilm/interfaces.js +0 -0
  17. package/es/Programme/Programme.js +15 -8
  18. package/es/SearchTypeResult/SearchFieldHeader.js +5 -5
  19. package/es/SearchTypeResult/SearchHeader.js +9 -9
  20. package/es/SearchTypeResult/SearchItem.js +19 -19
  21. package/es/SearchTypeResult/SearchNotionItem.js +12 -12
  22. package/es/SearchTypeResult/SearchNotionsResult.js +9 -14
  23. package/es/Spinner/Spinner.js +3 -3
  24. package/es/index.js +2 -1
  25. package/es/locale/messages-en.js +10 -0
  26. package/es/locale/messages-nb.js +10 -0
  27. package/es/locale/messages-nn.js +10 -0
  28. package/lib/Article/Article.d.ts +3 -1
  29. package/lib/Article/Article.js +25 -3
  30. package/lib/Article/ArticleNotions.js +79 -30
  31. package/lib/Breadcrumb/Breadcrumb.js +2 -1
  32. package/lib/Breadcrumblist/Breadcrumblist.d.ts +2 -1
  33. package/lib/Breadcrumblist/Breadcrumblist.js +15 -10
  34. package/lib/CloseButton/CloseButton.d.ts +6 -0
  35. package/lib/CloseButton/CloseButton.js +69 -0
  36. package/lib/CloseButton/index.d.ts +9 -0
  37. package/lib/CloseButton/index.js +15 -0
  38. package/lib/Frontpage/FrontpageAllSubjects.d.ts +1 -1
  39. package/lib/Frontpage/FrontpageAllSubjects.js +7 -7
  40. package/lib/Frontpage/FrontpageProgramMenu.js +10 -10
  41. package/lib/MediaList/MediaList.d.ts +48 -0
  42. package/lib/MediaList/MediaList.js +24 -78
  43. package/lib/MediaList/index.d.ts +8 -0
  44. package/lib/MessageBox/MessageBox.d.ts +22 -6
  45. package/lib/MessageBox/MessageBox.js +146 -77
  46. package/lib/MessageBox/MessageBoxTag.d.ts +12 -0
  47. package/lib/MessageBox/MessageBoxTag.js +44 -0
  48. package/lib/MessageBox/index.d.ts +3 -1
  49. package/lib/MessageBox/index.js +22 -2
  50. package/lib/NDLAFilm/FilmSlideshow.d.ts +16 -0
  51. package/lib/NDLAFilm/FilmSlideshow.js +214 -248
  52. package/lib/NDLAFilm/NavigationArrow.d.ts +15 -0
  53. package/lib/NDLAFilm/NavigationArrow.js +20 -65
  54. package/lib/NDLAFilm/SlideshowIndicator.d.ts +15 -0
  55. package/lib/NDLAFilm/SlideshowIndicator.js +16 -69
  56. package/lib/NDLAFilm/interfaces.d.ts +10 -0
  57. package/lib/NDLAFilm/interfaces.js +1 -0
  58. package/lib/NDLAFilm/shapes.d.ts +15 -0
  59. package/lib/Programme/Programme.d.ts +2 -1
  60. package/lib/Programme/Programme.js +18 -9
  61. package/lib/SearchTypeResult/SearchFieldHeader.d.ts +3 -3
  62. package/lib/SearchTypeResult/SearchFieldHeader.js +5 -5
  63. package/lib/SearchTypeResult/SearchHeader.d.ts +3 -3
  64. package/lib/SearchTypeResult/SearchHeader.js +9 -9
  65. package/lib/SearchTypeResult/SearchItem.d.ts +2 -3
  66. package/lib/SearchTypeResult/SearchItem.js +19 -19
  67. package/lib/SearchTypeResult/SearchNotionItem.d.ts +1 -1
  68. package/lib/SearchTypeResult/SearchNotionItem.js +12 -12
  69. package/lib/SearchTypeResult/SearchNotionsResult.js +8 -13
  70. package/lib/SearchTypeResult/index.d.ts +1 -0
  71. package/lib/Spinner/Spinner.d.ts +3 -3
  72. package/lib/Spinner/Spinner.js +2 -2
  73. package/lib/index.d.ts +2 -1
  74. package/lib/index.js +23 -0
  75. package/lib/locale/messages-en.d.ts +10 -0
  76. package/lib/locale/messages-en.js +10 -0
  77. package/lib/locale/messages-nb.d.ts +10 -0
  78. package/lib/locale/messages-nb.js +10 -0
  79. package/lib/locale/messages-nn.d.ts +10 -0
  80. package/lib/locale/messages-nn.js +10 -0
  81. package/package.json +10 -10
  82. package/src/Article/Article.tsx +17 -0
  83. package/src/Article/ArticleNotions.tsx +10 -7
  84. package/src/Breadcrumb/Breadcrumb.tsx +1 -1
  85. package/src/Breadcrumblist/Breadcrumblist.tsx +5 -3
  86. package/src/CloseButton/CloseButton.tsx +40 -0
  87. package/src/CloseButton/index.ts +11 -0
  88. package/src/Frontpage/FrontpageAllSubjects.tsx +2 -2
  89. package/src/Frontpage/FrontpageProgramMenu.tsx +1 -0
  90. package/src/MediaList/MediaList.tsx +158 -0
  91. package/src/MediaList/{index.js → index.ts} +0 -0
  92. package/src/MessageBox/MessageBox.tsx +117 -96
  93. package/src/MessageBox/MessageBoxTag.tsx +35 -0
  94. package/src/MessageBox/index.ts +3 -1
  95. package/src/NDLAFilm/FilmSlideshow.tsx +265 -0
  96. package/src/NDLAFilm/NavigationArrow.tsx +42 -0
  97. package/src/NDLAFilm/SlideshowIndicator.tsx +40 -0
  98. package/src/NDLAFilm/interfaces.ts +10 -0
  99. package/src/NDLAFilm/{shapes.js → shapes.ts} +0 -0
  100. package/src/Programme/Programme.tsx +7 -3
  101. package/src/SearchTypeResult/SearchFieldHeader.tsx +3 -3
  102. package/src/SearchTypeResult/SearchHeader.tsx +3 -3
  103. package/src/SearchTypeResult/SearchItem.tsx +4 -5
  104. package/src/SearchTypeResult/SearchNotionItem.tsx +1 -2
  105. package/src/SearchTypeResult/SearchNotionsResult.tsx +3 -8
  106. package/src/SearchTypeResult/index.ts +2 -0
  107. package/src/Spinner/Spinner.tsx +9 -5
  108. package/src/index.ts +2 -1
  109. package/src/locale/messages-en.ts +14 -0
  110. package/src/locale/messages-nb.ts +14 -0
  111. package/src/locale/messages-nn.ts +14 -0
  112. package/src/MediaList/MediaList.jsx +0 -182
  113. package/src/NDLAFilm/FilmSlideshow.jsx +0 -277
  114. package/src/NDLAFilm/NavigationArrow.jsx +0 -46
  115. package/src/NDLAFilm/SlideshowIndicator.jsx +0 -43
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Copyright (c) 2016-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
10
+ // @ts-ignore
11
+ import { SwipeEventData, useSwipeable } from 'react-swipeable';
12
+ import BEMHelper from 'react-bem-helper';
13
+ import SafeLink from '@ndla/safelink';
14
+ import { OneColumn } from '../Layout';
15
+ import Spinner from '../Spinner';
16
+ import { NDLAMovie } from './interfaces';
17
+ import NavigationArrow from './NavigationArrow';
18
+ import SlideshowIndicator from './SlideshowIndicator';
19
+
20
+ interface Props {
21
+ autoSlide: boolean;
22
+ randomStart: boolean;
23
+ slideshow: NDLAMovie[];
24
+ slideInterval: number;
25
+ }
26
+
27
+ const classes = new BEMHelper({
28
+ name: 'film-slideshow',
29
+ prefix: 'c-',
30
+ });
31
+
32
+ const defaultTransitionSwipeEnd = 'transform 600ms cubic-bezier(0, 0.76, 0.09, 1)';
33
+ const defaultTransitionText = 'opacity 600ms ease';
34
+
35
+ const renderSlideItem = (slide: NDLAMovie) => (
36
+ <div
37
+ {...classes('item')}
38
+ key={slide.id}
39
+ role="img"
40
+ aria-label={(slide.metaImage && slide.metaImage.alt) || ''}
41
+ style={{
42
+ backgroundImage: `url(${(slide.metaImage && slide.metaImage.url) || ''})`,
43
+ }}
44
+ />
45
+ );
46
+
47
+ const FilmSlideshow = ({ autoSlide = false, slideshow = [], slideInterval = 5000 }: Props) => {
48
+ const [swipeDistance, setSwipeDistance] = useState(0);
49
+ const [slideIndex, setSlideIndex] = useState(0);
50
+ const [slideIndexTarget, setSlideIndexTarget] = useState(0);
51
+ const [animationComplete, setAnimationComplete] = useState(true);
52
+ const slideRef = useRef<HTMLDivElement>(null);
53
+ const slideText = useRef<HTMLDivElement>(null);
54
+ let timer = useRef<ReturnType<typeof setTimeout> | null>(null);
55
+
56
+ const gotoSlide = useCallback((indexTarget: number, useAnimation = false) => {
57
+ setSwipeDistance(0);
58
+ if (timer.current) {
59
+ clearTimeout(timer.current);
60
+ }
61
+ setSlideIndexTarget(indexTarget);
62
+ setAnimationComplete(!useAnimation);
63
+ }, []);
64
+
65
+ const onChangedSlide = () => {
66
+ if (!animationComplete) {
67
+ if (slideRef.current) {
68
+ slideRef.current.style.transition = 'none';
69
+ slideRef.current.style.transform = `translateX(${slideIndexTarget * 100}vw))`;
70
+ }
71
+
72
+ setAnimationComplete(true);
73
+ setSlideIndex(slideIndexTarget);
74
+ } else if (slideIndexTarget === -1) {
75
+ if (slideRef.current) {
76
+ // Go to last slide for continuous loop
77
+ slideRef.current.style.transition = 'none';
78
+ slideRef.current.style.transform = `translateX(${slideshow.length * 100}vw))`;
79
+ }
80
+
81
+ setSlideIndex(slideshow.length - 1);
82
+ setSlideIndexTarget(slideshow.length - 1);
83
+ setAnimationComplete(true);
84
+ } else if (slideIndexTarget === slideshow.length) {
85
+ if (slideRef.current) {
86
+ // Go to first slide for continuous loop
87
+ slideRef.current.style.transition = 'none';
88
+ slideRef.current.style.transform = `translateX(100vw))`;
89
+ }
90
+ setSlideIndex(0);
91
+ setSlideIndexTarget(0);
92
+ setAnimationComplete(true);
93
+ } else {
94
+ setAnimationComplete(true);
95
+ setSlideIndex(slideIndexTarget);
96
+ }
97
+ };
98
+
99
+ const onSwipeEnd = () => {
100
+ let slide;
101
+ if (swipeDistance > 40) {
102
+ slide = -1;
103
+ } else if (swipeDistance < -40) {
104
+ slide = 1;
105
+ } else {
106
+ slide = 0;
107
+ }
108
+ if (slideRef.current && slideText.current) {
109
+ slideRef.current.style.transition = defaultTransitionSwipeEnd;
110
+ slideText.current.style.transition = defaultTransitionText;
111
+ slideText.current.style.opacity = '1';
112
+ }
113
+ setSwipeDistance(0);
114
+
115
+ initTimer();
116
+
117
+ if (slide !== 0) {
118
+ setSlideIndex(slideIndex + slide);
119
+ setSlideIndexTarget(slideIndex + slide);
120
+ } else {
121
+ // Reset transfrom
122
+ if (slideRef.current) {
123
+ slideRef.current.style.transform = getSlidePosition(slideIndex + slide);
124
+ }
125
+ }
126
+ };
127
+
128
+ const onSwipe = (eventData: SwipeEventData) => {
129
+ if (eventData.dir === 'Up' || eventData.dir === 'Down') {
130
+ return;
131
+ }
132
+ if (timer.current) {
133
+ clearTimeout(timer.current);
134
+ }
135
+ setSwipeDistance(eventData.deltaX);
136
+ if (slideRef && slideRef.current) {
137
+ slideRef.current.style.transition = 'none';
138
+ slideRef.current.style.transform = getSlidePosition(slideIndexTarget);
139
+ }
140
+ const opacityText = 1 - Math.min(100, Math.abs(swipeDistance)) / 100;
141
+ if (slideText && slideText.current) {
142
+ slideText.current.style.transition = 'none';
143
+ slideText.current.style.opacity = opacityText.toString();
144
+ }
145
+ };
146
+
147
+ const onTransitionEnd = () => {
148
+ const slideshowLength = slideshow.length;
149
+ if (slideIndex === -1) {
150
+ if (slideRef.current) {
151
+ slideRef.current.style.transition = 'none';
152
+ slideRef.current.style.transform = getSlidePosition(slideshowLength - 1);
153
+ }
154
+ setSlideIndex(slideshowLength - 1);
155
+ setSlideIndexTarget(slideshowLength - 1);
156
+ } else if (slideIndex >= slideshowLength) {
157
+ if (slideRef.current) {
158
+ slideRef.current.style.transition = 'none';
159
+ slideRef.current.style.transform = getSlidePosition(0);
160
+ }
161
+ setSlideIndex(0);
162
+ setSlideIndexTarget(0);
163
+ }
164
+ };
165
+
166
+ const getSlidePosition = (target: number) => {
167
+ if (swipeDistance !== 0) {
168
+ return `translateX(calc(${swipeDistance}px -
169
+ ${(target + 1) * 100}vw))`;
170
+ }
171
+ return `translateX(-${(target + 1) * 100}vw)`;
172
+ };
173
+
174
+ const initTimer = useCallback(() => {
175
+ if (autoSlide) {
176
+ timer.current = setTimeout(() => {
177
+ gotoSlide(slideIndex + 1);
178
+ }, slideInterval);
179
+ }
180
+ }, [autoSlide, gotoSlide, slideInterval, slideIndex]);
181
+
182
+ useEffect(() => {
183
+ initTimer();
184
+ }, [initTimer]);
185
+
186
+ const handlers = useSwipeable({
187
+ onSwiped: onSwipeEnd,
188
+ onSwiping: onSwipe,
189
+ });
190
+
191
+ if (slideshow.length === 0) {
192
+ return (
193
+ <div>
194
+ <div {...classes('slideshow')}>
195
+ <Spinner inverted />
196
+ </div>
197
+ </div>
198
+ );
199
+ }
200
+
201
+ const slideshowWidth = `${(slideshow.length + 2) * 100}vw`;
202
+ let activeSlide = slideIndex;
203
+ if (activeSlide < 0) {
204
+ activeSlide = slideshow.length - 1;
205
+ } else if (activeSlide >= slideshow.length) {
206
+ activeSlide = 0;
207
+ }
208
+
209
+ return (
210
+ <section {...classes('')} {...handlers}>
211
+ <>
212
+ <div {...classes('slide-link-wrapper')}>
213
+ <OneColumn>
214
+ <SafeLink
215
+ to={slideshow[activeSlide].path}
216
+ {...classes('item-wrapper', 'text', {
217
+ out: !animationComplete,
218
+ })}>
219
+ <div {...classes('slide-info')} ref={slideText}>
220
+ <h1>{slideshow[activeSlide].title}</h1>
221
+ <p>{slideshow[activeSlide].metaDescription}</p>
222
+ </div>
223
+ </SafeLink>
224
+ </OneColumn>
225
+ </div>
226
+ <NavigationArrow
227
+ slideIndexTarget={slideIndexTarget > 0 ? slideIndexTarget - 1 : slideshow.length - 1}
228
+ gotoSlide={gotoSlide}
229
+ />
230
+ <NavigationArrow
231
+ slideIndexTarget={slideIndexTarget < slideshow.length - 1 ? slideIndexTarget + 1 : 0}
232
+ gotoSlide={gotoSlide}
233
+ rightArrow
234
+ />
235
+ {!animationComplete && (
236
+ <div
237
+ {...classes('item', 'fade-over')}
238
+ role="img"
239
+ onAnimationEnd={onChangedSlide}
240
+ style={{
241
+ backgroundImage: `url(${
242
+ (slideshow[activeSlide].metaImage && slideshow[activeSlide].metaImage.url) || ''
243
+ })`,
244
+ }}
245
+ />
246
+ )}
247
+ <div
248
+ ref={slideRef}
249
+ {...classes('item-wrapper')}
250
+ onTransitionEnd={onTransitionEnd}
251
+ style={{
252
+ width: slideshowWidth,
253
+ transform: getSlidePosition(slideIndex),
254
+ }}>
255
+ {renderSlideItem(slideshow[slideshow.length - 1])}
256
+ {slideshow.map(renderSlideItem)}
257
+ {renderSlideItem(slideshow[0])}
258
+ </div>
259
+ <SlideshowIndicator slideshow={slideshow} activeSlide={activeSlide} gotoSlide={gotoSlide} />
260
+ </>
261
+ </section>
262
+ );
263
+ };
264
+
265
+ export default FilmSlideshow;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) 2016-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import React from 'react';
10
+ import BEMHelper from 'react-bem-helper';
11
+ import { ChevronRight, ChevronLeft } from '@ndla/icons/common';
12
+
13
+ interface Props {
14
+ slideIndexTarget: number;
15
+ slideshowLength?: number;
16
+ gotoSlide: (indexTarget: number, useAnimation: boolean) => void;
17
+ rightArrow?: boolean;
18
+ }
19
+
20
+ const classes = new BEMHelper({
21
+ name: 'film-slideshow',
22
+ prefix: 'c-',
23
+ });
24
+
25
+ const NavigationArrow = ({ slideIndexTarget, gotoSlide, rightArrow }: Props) => {
26
+ const Chevron = rightArrow ? ChevronRight : ChevronLeft;
27
+
28
+ return (
29
+ <div {...classes('navigation-arrows', rightArrow ? 'right' : '')}>
30
+ <button
31
+ type="button"
32
+ tabIndex={-1}
33
+ onClick={() => {
34
+ gotoSlide(slideIndexTarget, true);
35
+ }}>
36
+ <Chevron />
37
+ </button>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export default NavigationArrow;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright (c) 2019-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import React from 'react';
10
+ import BEMHelper from 'react-bem-helper';
11
+ import { NDLAMovie } from './interfaces';
12
+
13
+ interface Props {
14
+ slideshow: NDLAMovie[];
15
+ activeSlide: number;
16
+ gotoSlide: (indexTarget: number, useAnimation: boolean) => void;
17
+ }
18
+
19
+ const classes = new BEMHelper({
20
+ name: 'film-slideshow',
21
+ prefix: 'c-',
22
+ });
23
+
24
+ const SlideshowIndicator = ({ slideshow, activeSlide, gotoSlide }: Props) => {
25
+ return (
26
+ <div {...classes('indicator-wrapper')}>
27
+ {slideshow.map((slide, index) => (
28
+ <button
29
+ key={`indicator_${index}`}
30
+ type="button"
31
+ {...classes('indicator-dot', index === activeSlide ? 'active' : '')}
32
+ onClick={() => gotoSlide(index, true)}>
33
+ <span />
34
+ </button>
35
+ ))}
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default SlideshowIndicator;
@@ -0,0 +1,10 @@
1
+ export interface NDLAMovie {
2
+ id: string;
3
+ metaDescription: string;
4
+ title: string;
5
+ metaImage: {
6
+ url: string;
7
+ alt: string;
8
+ };
9
+ path: string;
10
+ }
File without changes
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
2
  import styled from '@emotion/styled';
3
3
  import { breakpoints, mq, spacing } from '@ndla/core';
4
+ import { useTranslation } from 'react-i18next';
4
5
  import LayoutItem, { OneColumn } from '../Layout';
5
- import { NavigationHeading } from '../Navigation';
6
6
  import ProgrammeSubjects from './ProgrammeSubjects';
7
7
  import { GradesProps } from './ProgrammeSubjects';
8
-
8
+ import MessageBox from '../MessageBox/MessageBox';
9
+ import { NavigationHeading } from '..';
9
10
  const StyledWrapper = styled.div`
10
11
  display: flex;
11
12
  flex-direction: column;
@@ -63,9 +64,11 @@ const SubjectsWrapper = styled.div`
63
64
  type Props = GradesProps & {
64
65
  heading?: string;
65
66
  image?: string;
67
+ messageBoxText?: string;
66
68
  };
67
69
 
68
- export const Programme = ({ heading, image, grades, selectedGrade, onChangeGrade }: Props) => {
70
+ export const Programme = ({ heading, image, grades, selectedGrade, onChangeGrade, messageBoxText }: Props) => {
71
+ const { t } = useTranslation();
69
72
  return (
70
73
  <StyledWrapper>
71
74
  <StyledBackground image={image} />
@@ -74,6 +77,7 @@ export const Programme = ({ heading, image, grades, selectedGrade, onChangeGrade
74
77
  <LayoutItem layout="extend">
75
78
  <StyledContentWrapper>
76
79
  <NavigationHeading>{heading}</NavigationHeading>
80
+ {messageBoxText && <MessageBox>{t(messageBoxText)}</MessageBox>}
77
81
  <SubjectsWrapper>
78
82
  <ProgrammeSubjects grades={grades} selectedGrade={selectedGrade} onChangeGrade={onChangeGrade} />
79
83
  </SubjectsWrapper>
@@ -6,7 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import React, { useEffect, useRef, useState } from 'react';
9
+ import React, { FormEvent, useEffect, useRef, useState } from 'react';
10
10
  import styled from '@emotion/styled';
11
11
  import { colors, breakpoints, mq } from '@ndla/core';
12
12
  // @ts-ignore
@@ -76,8 +76,8 @@ const SearchInput = styled.input`
76
76
  `;
77
77
 
78
78
  type Props = {
79
- onSubmit: (event: {}) => void;
80
- value: string;
79
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
80
+ value?: string;
81
81
  onChange: (value: string) => void;
82
82
  filters?: PopupFilterProps;
83
83
  activeFilters?: {
@@ -6,7 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import React from 'react';
9
+ import React, { FormEvent } from 'react';
10
10
  import styled from '@emotion/styled';
11
11
  import { breakpoints, fonts, mq, spacing } from '@ndla/core';
12
12
 
@@ -75,7 +75,7 @@ type Props = {
75
75
  searchPhrase?: string;
76
76
  searchPhraseSuggestion?: string;
77
77
  searchPhraseSuggestionOnClick?: () => void;
78
- searchValue: string;
78
+ searchValue?: string;
79
79
  filters?: PopupFilterProps;
80
80
  activeFilters?: {
81
81
  filters: FilterProps[];
@@ -83,7 +83,7 @@ type Props = {
83
83
  };
84
84
  competenceGoals?: CompetenceGoalsItemType[];
85
85
  onSearchValueChange: (value: string) => void;
86
- onSubmit: () => void;
86
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
87
87
  noResults?: boolean;
88
88
  };
89
89
 
@@ -203,12 +203,11 @@ type context = {
203
203
  };
204
204
 
205
205
  export type SearchItemType = {
206
- id: string;
206
+ id: string | number;
207
207
  title: string;
208
208
  url: string;
209
209
  ingress: string;
210
- contexts: context[];
211
- image: React.ReactNode | null;
210
+ contexts?: context[];
212
211
  img?: { url: string; alt: string };
213
212
  labels?: string[];
214
213
  children?: React.ReactNode;
@@ -220,7 +219,7 @@ type Props = {
220
219
  const SearchItem = ({ item, type }: Props) => {
221
220
  const { t } = useTranslation();
222
221
  const { title, url, ingress, contexts, img = null, labels = [] } = item;
223
- const mainContext = contexts[0];
222
+ const mainContext = contexts?.[0];
224
223
 
225
224
  const Breadcrumb = ({ breadcrumb, children }: { breadcrumb: string[]; children?: React.ReactNode }) => (
226
225
  <BreadcrumbPath>
@@ -268,7 +267,7 @@ const SearchItem = ({ item, type }: Props) => {
268
267
  {item.children}
269
268
  <ItemText>{parse(ingress)}</ItemText>
270
269
  {mainContext && <Breadcrumb breadcrumb={mainContext.breadcrumb} />}
271
- {contexts.length > 1 && (
270
+ {contexts && contexts.length > 1 && (
272
271
  <ContextsWrapper>
273
272
  <Modal
274
273
  activateButton={
@@ -48,7 +48,6 @@ const ItemWrapper = styled.div<ItemWrapperProps>`
48
48
  const TextWrapper = styled.div``;
49
49
  const DescriptionWrapper = styled.div`
50
50
  ${fonts.sizes('18px', '26px')};
51
- font-family: ${fonts.serif};
52
51
  `;
53
52
 
54
53
  const MediaWrapper = styled.div`
@@ -121,7 +120,7 @@ const AuthorsWrapper = styled.div`
121
120
  `;
122
121
 
123
122
  export type SearchNotionItemProps = {
124
- id: string;
123
+ id: string | number;
125
124
  title: string;
126
125
  text: React.ReactNode;
127
126
  image?: { url: string; alt: string };
@@ -10,7 +10,8 @@ import React from 'react';
10
10
  import styled from '@emotion/styled';
11
11
  import { fonts, mq, breakpoints, spacing } from '@ndla/core';
12
12
  // @ts-ignore
13
- import Button from '@ndla/button';
13
+ import { ModalCloseButton } from '@ndla/modal';
14
+ // @ts-ignore
14
15
  import { withTranslation, WithTranslation } from 'react-i18next';
15
16
  import SearchNotionItem, { SearchNotionItemProps } from './SearchNotionItem';
16
17
 
@@ -47,10 +48,6 @@ const HeadingCount = styled.span`
47
48
  text-transform: lowercase;
48
49
  `;
49
50
 
50
- const ButtonRemoveText = styled.span`
51
- ${fonts.sizes('18px', '22px')};
52
- `;
53
-
54
51
  type Props = {
55
52
  items: SearchNotionItemProps[];
56
53
  totalCount: number;
@@ -65,9 +62,7 @@ const SearchNotionsResult = ({ items, totalCount, onRemove, renderMarkdown, t }:
65
62
  {t(`searchPage.resultType.notionsHeading`)}
66
63
  <HeadingCount>{t(`searchPage.resultType.hits`, { count: totalCount })}</HeadingCount>
67
64
  </Heading>
68
- <Button onClick={onRemove} link>
69
- <ButtonRemoveText>{t(`searchPage.resultType.notionsRemove`)}</ButtonRemoveText>
70
- </Button>
65
+ <ModalCloseButton onClick={onRemove} />
71
66
  </HeadingWrapper>
72
67
  {items.map((item) => (
73
68
  <SearchNotionItem key={item.id} {...item} renderMarkdown={renderMarkdown} />
@@ -12,4 +12,6 @@ import SearchFieldHeader from './SearchFieldHeader';
12
12
  import SearchNotionsResult from './SearchNotionsResult';
13
13
  import SearchSubjectResult from './SearchSubjectResult';
14
14
 
15
+ export type { ContentType } from './SearchTypeResult';
16
+
15
17
  export { SearchTypeResult, SearchHeader, SearchFieldHeader, SearchNotionsResult, SearchSubjectResult };
@@ -8,23 +8,27 @@
8
8
 
9
9
  import React from 'react';
10
10
  import styled from '@emotion/styled';
11
- import { spacing, colors, SpacingNames } from '@ndla/core';
11
+ import { colors, spacing, SpacingNames } from '@ndla/core';
12
12
 
13
13
  interface Props {
14
+ size?: SpacingNames;
15
+ margin?: string;
16
+ inverted?: boolean;
17
+ }
18
+
19
+ interface StyledProps extends Props {
14
20
  size: SpacingNames;
15
- margin: string;
16
- inverted: boolean;
17
21
  }
18
22
 
19
- const SpinnerDiv = styled('div')<Props>`
23
+ const SpinnerDiv = styled('div')<StyledProps>`
20
24
  border: calc(${(props) => spacing[props.size]} / 6.5) solid rgba(0, 0, 0, 0.1);
21
25
  border-bottom-color: ${(props) => (props.inverted ? '#fff' : colors.brand.primary)};
22
26
  border-radius: 50%;
23
27
  animation: spinnerAnimation 0.7s linear infinite;
24
28
  height: ${(props) => spacing[props.size]};
25
29
  width: ${(props) => spacing[props.size]};
26
- display: block;
27
30
  margin: ${(props) => props.margin};
31
+ display: block;
28
32
  @keyframes spinnerAnimation {
29
33
  0% {
30
34
  transform: rotate(0deg);
package/src/index.ts CHANGED
@@ -115,8 +115,9 @@ export { default as CreatedBy } from './CreatedBy';
115
115
 
116
116
  export { default as Breadcrumblist } from './Breadcrumblist';
117
117
 
118
- export { MessageBox } from './MessageBox';
118
+ export { MessageBox, MessageBoxTag, MessageBoxType } from './MessageBox';
119
119
 
120
+ export { CloseButton } from './CloseButton';
120
121
  export { default as AudioPlayer, initAudioPlayers } from './AudioPlayer';
121
122
 
122
123
  export { NavigationHeading, NavigationBox, NavigationTopicAbout } from './Navigation';
@@ -313,6 +313,20 @@ const messages = {
313
313
  h5p: 'Interactive',
314
314
  },
315
315
  },
316
+ messageBoxInfo: {
317
+ outdatedCoursePlan:
318
+ 'This course is not updated to the current curriculum. Follow this link to find the updated version of the course: ',
319
+ updateBrowser:
320
+ 'Your browser is outdated. Update it, or find a safe and updated browser on https://browsehappy.com.',
321
+ noContent: 'We are sorry, but we do not yet offer any program courses.',
322
+ feide: 'This resource is accessible only to teachers who are logged in with Feide.',
323
+ resources:
324
+ 'This is not a complete course produced by NDLA, but a collection of resources we hope you will find useful.',
325
+ beta: 'This course is in beta.',
326
+ outdatedSubject: 'This topic is part of a course that is not updated to the current curriculum.',
327
+ newVersion:
328
+ 'This learning resource is not updated to the current curriculum. You can find an updated version here: ',
329
+ },
316
330
  article: {
317
331
  edition: 'Edition',
318
332
  publisher: 'Publisher',
@@ -312,6 +312,20 @@ const messages = {
312
312
  h5p: 'Interaktiv',
313
313
  },
314
314
  },
315
+ messageBoxInfo: {
316
+ outdatedCoursePlan:
317
+ 'Dette faget følger en utgått læreplan. Gå til faget som er oppdatert etter gjeldende læreplan:',
318
+ updateBrowser:
319
+ 'Nettleseren din er utdatert. Oppdater den, eller finn en trygg og oppdatert nettleser på https://browsehappy.com.',
320
+ noContent: 'Vi har dessverre ikke noen programfag ennå.',
321
+ feide: 'Denne ressursen er bare tilgjengelig for lærere som er pålogget med Feide.',
322
+ resources:
323
+ 'Dette er ikke et komplett læremiddel produsert av NDLA, men ei ressurssamling som vi håper kan være nyttig for deg.',
324
+ beta: 'Dette faget er i betaversjon.',
325
+ outdatedSubject: 'Dette emnet hører til et fag som ikke er oppdatert etter gjeldende læreplan.',
326
+ newVersion:
327
+ 'Denne læringsressursen er ikke oppdatert etter gjeldende læreplan. Du finner en oppdatert versjon her: ',
328
+ },
315
329
  article: {
316
330
  lastUpdated: 'Sist oppdatert',
317
331
  edition: 'Utgave',
@@ -313,6 +313,20 @@ const messages = {
313
313
  h5p: 'Interaktiv',
314
314
  },
315
315
  },
316
+ messageBoxInfo: {
317
+ outdatedCoursePlan:
318
+ 'Dette faget følgjer ein utgått læreplan. Gå til faget som er oppdatert etter gjeldande læreplan: ',
319
+ updateBrowser:
320
+ 'Nettlesaren din er utdatert. Oppdater han, eller finn ein trygg og oppdatert nettlesar på https://browsehappy.com. ',
321
+ noContent: 'Vi har dessverre ikkje nokon programfag enno.',
322
+ feide: 'Denne ressursen er berre tilgjengeleg for lærarar som er pålogga med Feide.',
323
+ resources:
324
+ 'Dette er ikkje eit komplett læremiddel produsert av NDLA, men ei ressurssamling som vi håper kan vere nyttig for deg.',
325
+ beta: 'Dette faget er i betaversjon.',
326
+ outdatedSubject: 'Dette emnet høyrer til eit fag som ikkje er oppdatert etter gjeldande læreplan.',
327
+ newVersion:
328
+ 'Denne læringsressursen er ikkje oppdatert etter gjeldande læreplan. Du finn ein oppdatert versjon her: ',
329
+ },
316
330
  article: {
317
331
  lastUpdated: 'Sist oppdatert',
318
332
  edition: 'Utgåve',