@ndla/ui 34.0.1 → 34.1.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/Figure/Figure.js +3 -2
- package/es/FileList/File.js +6 -6
- package/es/LanguageSelector/LanguageSelector.js +68 -99
- package/es/NDLAFilm/AboutNdlaFilm.js +13 -12
- package/es/NDLAFilm/AllMoviesAlphabetically.js +79 -144
- package/es/NDLAFilm/FilmContentCard.js +41 -26
- package/es/NDLAFilm/FilmContentCardTags.js +5 -3
- package/es/NDLAFilm/FilmMovieList.js +13 -8
- package/es/NDLAFilm/FilmMovieSearch.js +6 -5
- package/es/NDLAFilm/FilmSlideshow.js +44 -20
- package/es/NDLAFilm/filmStyles.js +2 -2
- package/es/ResourceGroup/ResourceItem.js +72 -48
- package/es/Search/ActiveFilterContent.js +6 -5
- package/es/Search/ContentTypeResult.js +6 -3
- package/es/SearchTypeResult/ActiveFilterContent.js +9 -10
- package/es/Topic/Topic.js +171 -213
- package/es/all.css +1 -1
- package/es/locale/messages-en.js +3 -1
- package/es/locale/messages-nb.js +3 -1
- package/es/locale/messages-nn.js +7 -5
- package/es/locale/messages-se.js +2 -0
- package/es/locale/messages-sma.js +3 -1
- package/lib/Figure/Figure.d.ts +2 -1
- package/lib/Figure/Figure.js +3 -2
- package/lib/FileList/File.js +6 -6
- package/lib/LanguageSelector/LanguageSelector.d.ts +6 -15
- package/lib/LanguageSelector/LanguageSelector.js +65 -99
- package/lib/NDLAFilm/AboutNdlaFilm.js +11 -14
- package/lib/NDLAFilm/AllMoviesAlphabetically.d.ts +1 -2
- package/lib/NDLAFilm/AllMoviesAlphabetically.js +77 -142
- package/lib/NDLAFilm/FilmContentCard.d.ts +7 -0
- package/lib/NDLAFilm/FilmContentCard.js +41 -26
- package/lib/NDLAFilm/FilmContentCardTags.d.ts +2 -1
- package/lib/NDLAFilm/FilmContentCardTags.js +5 -3
- package/lib/NDLAFilm/FilmMovieList.js +12 -7
- package/lib/NDLAFilm/FilmMovieSearch.js +5 -4
- package/lib/NDLAFilm/FilmSlideshow.js +44 -20
- package/lib/NDLAFilm/filmStyles.js +2 -2
- package/lib/Resource/resourceComponents.d.ts +1 -1
- package/lib/ResourceGroup/ResourceItem.d.ts +2 -2
- package/lib/ResourceGroup/ResourceItem.js +72 -48
- package/lib/Search/ActiveFilterContent.d.ts +1 -1
- package/lib/Search/ActiveFilterContent.js +9 -5
- package/lib/Search/ContentTypeResult.js +6 -3
- package/lib/SearchTypeResult/ActiveFilterContent.d.ts +1 -1
- package/lib/SearchTypeResult/ActiveFilterContent.js +12 -10
- package/lib/Topic/Topic.js +170 -215
- package/lib/all.css +1 -1
- package/lib/locale/messages-en.d.ts +2 -0
- package/lib/locale/messages-en.js +3 -1
- package/lib/locale/messages-nb.d.ts +2 -0
- package/lib/locale/messages-nb.js +3 -1
- package/lib/locale/messages-nn.d.ts +4 -2
- package/lib/locale/messages-nn.js +7 -5
- package/lib/locale/messages-se.d.ts +2 -0
- package/lib/locale/messages-se.js +2 -0
- package/lib/locale/messages-sma.d.ts +2 -0
- package/lib/locale/messages-sma.js +3 -1
- package/package.json +15 -14
- package/src/Figure/Figure.tsx +6 -2
- package/src/FileList/File.tsx +4 -4
- package/src/LanguageSelector/LanguageSelector.stories.tsx +48 -0
- package/src/LanguageSelector/LanguageSelector.tsx +71 -149
- package/src/NDLAFilm/AboutNdlaFilm.tsx +11 -14
- package/src/NDLAFilm/AllMoviesAlphabetically.tsx +44 -160
- package/src/NDLAFilm/FilmContentCard.tsx +40 -21
- package/src/NDLAFilm/FilmContentCardTags.tsx +3 -2
- package/src/NDLAFilm/FilmMovieList.tsx +14 -7
- package/src/NDLAFilm/FilmMovieSearch.tsx +2 -2
- package/src/NDLAFilm/FilmSlideshow.tsx +49 -40
- package/src/NDLAFilm/filmStyles.ts +1 -1
- package/src/ResourceGroup/ResourceItem.tsx +79 -94
- package/src/Search/ActiveFilterContent.tsx +4 -3
- package/src/Search/ContentTypeResult.tsx +3 -1
- package/src/SearchTypeResult/ActiveFilterContent.tsx +7 -8
- package/src/Topic/Topic.tsx +166 -193
- package/src/locale/messages-en.ts +3 -1
- package/src/locale/messages-nb.ts +3 -1
- package/src/locale/messages-nn.ts +5 -4
- package/src/locale/messages-se.ts +2 -0
- package/src/locale/messages-sma.ts +3 -1
- package/src/main.scss +0 -1
- package/es/LanguageSelector/LanguageSelectorContent.js +0 -61
- package/es/Subject/SubjectCarousel.js +0 -133
- package/lib/LanguageSelector/LanguageSelectorContent.d.ts +0 -15
- package/lib/LanguageSelector/LanguageSelectorContent.js +0 -68
- package/lib/Subject/SubjectCarousel.d.ts +0 -18
- package/lib/Subject/SubjectCarousel.js +0 -138
- package/src/LanguageSelector/LanguageSelectorContent.tsx +0 -80
- package/src/NDLAFilm/component.film-movielist.scss +0 -105
- package/src/Subject/SubjectCarousel.tsx +0 -162
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import styled from '@emotion/styled';
|
|
4
|
-
import
|
|
5
|
-
import { colors, spacing,
|
|
4
|
+
import { ModalHeader, ModalBody, ModalCloseButton, ModalV2 } from '@ndla/modal';
|
|
5
|
+
import { colors, spacing, mq, breakpoints } from '@ndla/core';
|
|
6
6
|
import { ButtonV2 as Button } from '@ndla/button';
|
|
7
|
-
import { OneColumn } from '..';
|
|
8
7
|
import VisualElement from './VisualElement';
|
|
9
8
|
|
|
10
9
|
const StyledAside = styled.aside`
|
|
@@ -15,9 +14,7 @@ const StyledAside = styled.aside`
|
|
|
15
14
|
> div {
|
|
16
15
|
padding: ${spacing.normal};
|
|
17
16
|
width: 50%;
|
|
18
|
-
|
|
19
|
-
@include font-size(22px, 26px);
|
|
20
|
-
font-weight: ${fonts.weight.bold};
|
|
17
|
+
h2 {
|
|
21
18
|
text-transform: uppercase;
|
|
22
19
|
letter-spacing: 0.05em;
|
|
23
20
|
color: #fff;
|
|
@@ -25,7 +22,6 @@ const StyledAside = styled.aside`
|
|
|
25
22
|
}
|
|
26
23
|
}
|
|
27
24
|
button {
|
|
28
|
-
text-align: left;
|
|
29
25
|
color: #fff;
|
|
30
26
|
&:hover,
|
|
31
27
|
&:focus {
|
|
@@ -58,25 +54,26 @@ interface Props {
|
|
|
58
54
|
|
|
59
55
|
const AboutNdlaFilm = ({ aboutNDLAVideo, moreAboutNdlaFilm }: Props) => {
|
|
60
56
|
const { t } = useTranslation();
|
|
57
|
+
const titleId = 'about-ndla-film-title';
|
|
61
58
|
return (
|
|
62
59
|
<div className="o-wrapper">
|
|
63
|
-
<StyledAside>
|
|
60
|
+
<StyledAside aria-labelledby={titleId}>
|
|
64
61
|
<div>
|
|
65
62
|
<VisualElement visualElement={aboutNDLAVideo.visualElement} />
|
|
66
63
|
</div>
|
|
67
64
|
<div>
|
|
68
|
-
<
|
|
65
|
+
<h2 id={titleId}>{aboutNDLAVideo.title}</h2>
|
|
69
66
|
<p>{aboutNDLAVideo.description}</p>
|
|
70
|
-
<
|
|
67
|
+
<ModalV2 size="full" activateButton={<Button variant="link">{t('ndlaFilm.about.more')}</Button>}>
|
|
71
68
|
{(onClose) => (
|
|
72
|
-
|
|
69
|
+
<>
|
|
73
70
|
<ModalHeader>
|
|
74
|
-
<ModalCloseButton onClick={onClose}
|
|
71
|
+
<ModalCloseButton onClick={onClose} />
|
|
75
72
|
</ModalHeader>
|
|
76
73
|
<ModalBody>{moreAboutNdlaFilm}</ModalBody>
|
|
77
|
-
|
|
74
|
+
</>
|
|
78
75
|
)}
|
|
79
|
-
</
|
|
76
|
+
</ModalV2>
|
|
80
77
|
</div>
|
|
81
78
|
</StyledAside>
|
|
82
79
|
</div>
|
|
@@ -6,22 +6,20 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React, {
|
|
10
|
-
import { isIE, browserVersion } from 'react-device-detect';
|
|
9
|
+
import React, { RefObject, useMemo, useRef } from 'react';
|
|
11
10
|
import styled from '@emotion/styled';
|
|
12
|
-
import {
|
|
13
|
-
import throttle from 'lodash/throttle';
|
|
14
|
-
import { breakpoints, mq, spacing, spacingUnit, colors, fonts, animations } from '@ndla/core';
|
|
11
|
+
import { breakpoints, mq, spacing, spacingUnit, colors } from '@ndla/core';
|
|
15
12
|
import SafeLink from '@ndla/safelink';
|
|
13
|
+
import groupBy from 'lodash/groupBy';
|
|
14
|
+
import sortBy from 'lodash/sortBy';
|
|
15
|
+
import { useTranslation } from 'react-i18next';
|
|
16
16
|
import { makeSrcQueryString } from '../Image';
|
|
17
17
|
import { MovieType } from './types';
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
const IMAGE_WIDTH = 143;
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
color:
|
|
23
|
-
margin: ${spacing.large} 0 ${spacingUnit * 0.75}px;
|
|
24
|
-
${fonts.sizes(26, 1.1)};
|
|
21
|
+
const Letter = styled.h2`
|
|
22
|
+
color: ${colors.white};
|
|
25
23
|
${mq.range({ from: breakpoints.tablet })} {
|
|
26
24
|
text-indent: ${spacingUnit * 0.75}px;
|
|
27
25
|
}
|
|
@@ -39,29 +37,12 @@ const StyledWrapper = styled.section`
|
|
|
39
37
|
max-width: 100%;
|
|
40
38
|
margin: ${spacing.large} auto;
|
|
41
39
|
padding: 0 ${spacing.normal};
|
|
42
|
-
display: flex;
|
|
43
|
-
flex-direction: column;
|
|
44
40
|
`;
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const MovieItem = styled.div<MovieItemProps>`
|
|
51
|
-
margin: 0 0 ${spacingUnit * 0.75}px;
|
|
52
|
-
display: inline-flex;
|
|
53
|
-
&:last-child {
|
|
54
|
-
margin-bottom: ${spacing.large};
|
|
55
|
-
}
|
|
56
|
-
opacity: 0;
|
|
57
|
-
transform: translateY(${spacing.xsmall});
|
|
58
|
-
transition: all ${animations.durations.slow} ease;
|
|
59
|
-
${(props: MovieItemProps) =>
|
|
60
|
-
props.inView &&
|
|
61
|
-
css`
|
|
62
|
-
opacity: 1;
|
|
63
|
-
transform: translateY(0);
|
|
64
|
-
`};
|
|
42
|
+
const MovieItem = styled.div`
|
|
43
|
+
display: flex;
|
|
44
|
+
gap: ${spacing.small};
|
|
45
|
+
color: ${colors.white};
|
|
65
46
|
`;
|
|
66
47
|
|
|
67
48
|
const MovieTextWrapper = styled.div`
|
|
@@ -71,57 +52,23 @@ const MovieTextWrapper = styled.div`
|
|
|
71
52
|
flex: 1;
|
|
72
53
|
`;
|
|
73
54
|
|
|
74
|
-
|
|
75
|
-
backgroundImage?: string | null;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const MovieImage = styled.div<movieImageType>`
|
|
55
|
+
const MovieImage = styled.img`
|
|
79
56
|
width: 104px;
|
|
80
57
|
height: 80px;
|
|
81
|
-
background-color: ${colors.ndlaFilm.filmColorLight};
|
|
82
|
-
${(props: movieImageType) =>
|
|
83
|
-
props.backgroundImage !== null &&
|
|
84
|
-
css`
|
|
85
|
-
background-image: url(${props.backgroundImage});
|
|
86
|
-
`}
|
|
87
|
-
background-size: cover;
|
|
88
|
-
background-position: center center;
|
|
89
|
-
margin: 0 ${spacingUnit * 0.75}px 0 0;
|
|
90
58
|
${mq.range({ from: breakpoints.tablet })} {
|
|
91
|
-
margin-left: ${spacingUnit * 0.75}px;
|
|
92
59
|
width: ${IMAGE_WIDTH}px;
|
|
93
60
|
height: 90px;
|
|
94
61
|
}
|
|
95
|
-
position: relative;
|
|
96
|
-
&:after {
|
|
97
|
-
content: '';
|
|
98
|
-
position: absolute;
|
|
99
|
-
z-index: 1;
|
|
100
|
-
background: ${colors.ndlaFilm.filmColor};
|
|
101
|
-
opacity: 0;
|
|
102
|
-
left: 0;
|
|
103
|
-
right: 0;
|
|
104
|
-
bottom: 0;
|
|
105
|
-
top: 0;
|
|
106
|
-
}
|
|
107
62
|
`;
|
|
108
63
|
|
|
109
64
|
const MovieTitle = styled.h3`
|
|
110
|
-
color:
|
|
111
|
-
margin: 0
|
|
112
|
-
${fonts.sizes(18, 1.3)};
|
|
113
|
-
${mq.range({ from: breakpoints.tablet })} {
|
|
114
|
-
${fonts.sizes(20, 1.3)};
|
|
115
|
-
}
|
|
65
|
+
color: ${colors.white};
|
|
66
|
+
margin: 0;
|
|
116
67
|
`;
|
|
117
68
|
|
|
118
69
|
const MovieDescription = styled.p`
|
|
119
70
|
color: ${colors.brand.greyLighter};
|
|
120
71
|
margin: 0;
|
|
121
|
-
${fonts.sizes(14, 1.5)};
|
|
122
|
-
${mq.range({ from: breakpoints.tablet })} {
|
|
123
|
-
${fonts.sizes(16, 1.5)};
|
|
124
|
-
}
|
|
125
72
|
overflow: hidden;
|
|
126
73
|
text-overflow: ellipsis;
|
|
127
74
|
display: -webkit-box;
|
|
@@ -129,18 +76,10 @@ const MovieDescription = styled.p`
|
|
|
129
76
|
-webkit-line-clamp: 2;
|
|
130
77
|
`;
|
|
131
78
|
|
|
132
|
-
|
|
133
|
-
isIE11: boolean;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const StyledSafeLink = styled(SafeLink)<isIEProps>`
|
|
79
|
+
const StyledSafeLink = styled(SafeLink)`
|
|
137
80
|
box-shadow: none;
|
|
138
81
|
display: flex;
|
|
139
|
-
${
|
|
140
|
-
props.isIE11 &&
|
|
141
|
-
css`
|
|
142
|
-
flex: 1;
|
|
143
|
-
`}
|
|
82
|
+
gap: ${spacing.small};
|
|
144
83
|
&:hover,
|
|
145
84
|
&:focus {
|
|
146
85
|
${MovieTitle} {
|
|
@@ -158,97 +97,42 @@ const StyledSafeLink = styled(SafeLink)<isIEProps>`
|
|
|
158
97
|
|
|
159
98
|
interface Props {
|
|
160
99
|
movies: MovieType[];
|
|
161
|
-
locale: string;
|
|
162
100
|
}
|
|
163
101
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
102
|
+
const MovieGroup = styled.section`
|
|
103
|
+
display: flex;
|
|
104
|
+
flex-direction: column;
|
|
105
|
+
gap: ${spacing.normal};
|
|
106
|
+
`;
|
|
167
107
|
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
};
|
|
177
|
-
}
|
|
108
|
+
const groupMovies = (movies: MovieType[]) => {
|
|
109
|
+
const sortedMovies = sortBy(movies, (m) => m.title);
|
|
110
|
+
const grouped = groupBy(sortedMovies, (movie) => {
|
|
111
|
+
const firstChar = movie.title[0]?.toUpperCase();
|
|
112
|
+
const isLetter = firstChar?.match(/[A-Z\WÆØÅ]+/);
|
|
113
|
+
return isLetter ? firstChar : '#';
|
|
114
|
+
});
|
|
115
|
+
return Object.entries(grouped).map(([letter, movies]) => ({ letter, movies }));
|
|
178
116
|
};
|
|
179
117
|
|
|
180
|
-
const AllMoviesAlphabetically = ({ movies
|
|
181
|
-
const
|
|
118
|
+
const AllMoviesAlphabetically = ({ movies }: Props) => {
|
|
119
|
+
const groupedMovies = useMemo(() => groupMovies(movies), [movies]);
|
|
120
|
+
const { t } = useTranslation();
|
|
182
121
|
// Split into Letters.
|
|
183
|
-
let previousLetter = '';
|
|
184
122
|
const wrapperRef: RefObject<HTMLElement> = useRef(null);
|
|
185
|
-
const [visibleImages, setVisibleImages] = useState<visibleImagesProps>({});
|
|
186
|
-
|
|
187
|
-
const scrollEvent = () => {
|
|
188
|
-
hasForEachPolyfill();
|
|
189
|
-
const updates: visibleImagesProps = {};
|
|
190
|
-
const allChildren: NodeListOf<HTMLElement> | null =
|
|
191
|
-
wrapperRef.current && wrapperRef.current.querySelectorAll('[role=img]');
|
|
192
|
-
const windowInnerHeight = window.innerHeight;
|
|
193
|
-
if (allChildren) {
|
|
194
|
-
let started: boolean = false;
|
|
195
|
-
let ended: boolean = false;
|
|
196
|
-
allChildren.forEach((el: HTMLElement, index: number) => {
|
|
197
|
-
if (!ended) {
|
|
198
|
-
const rect: ClientRect = el.getBoundingClientRect();
|
|
199
|
-
if (!started) {
|
|
200
|
-
if (rect.top > -20) {
|
|
201
|
-
updates[index] = true;
|
|
202
|
-
started = true;
|
|
203
|
-
}
|
|
204
|
-
} else {
|
|
205
|
-
updates[index] = true;
|
|
206
|
-
if (rect.top > windowInnerHeight + 20) {
|
|
207
|
-
ended = true;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
setVisibleImages((visibleImages) => ({ ...visibleImages, ...updates }));
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
useEffect(() => {
|
|
217
|
-
const throttledScrollEvent = throttle(() => {
|
|
218
|
-
scrollEvent();
|
|
219
|
-
}, 100);
|
|
220
|
-
window.addEventListener('scroll', throttledScrollEvent);
|
|
221
|
-
scrollEvent();
|
|
222
|
-
return () => {
|
|
223
|
-
window.removeEventListener('scroll', throttledScrollEvent);
|
|
224
|
-
};
|
|
225
|
-
}, []);
|
|
226
|
-
|
|
227
|
-
useEffect(() => {
|
|
228
|
-
scrollEvent();
|
|
229
|
-
}, [movies]);
|
|
230
123
|
|
|
231
124
|
return (
|
|
232
125
|
<StyledWrapper ref={wrapperRef}>
|
|
233
|
-
{
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
<Fragment key={movie.id}>
|
|
240
|
-
{isNewLetter && <StyledNewLetter>{movie.title.substr(0, 1)}</StyledNewLetter>}
|
|
241
|
-
<MovieItem inView={inView}>
|
|
242
|
-
<StyledSafeLink isIE11={isIE11} to={movie.path}>
|
|
126
|
+
{groupedMovies.map(({ letter, movies }) => (
|
|
127
|
+
<MovieGroup key={letter}>
|
|
128
|
+
<Letter aria-label={t('filmfrontpage.allMovieGroupTitleLabel', { letter })}>{letter}</Letter>
|
|
129
|
+
{movies.map((movie) => (
|
|
130
|
+
<MovieItem key={movie.id}>
|
|
131
|
+
<StyledSafeLink to={movie.path}>
|
|
243
132
|
<MovieImage
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
inView && movie.metaImage && movie.metaImage.url
|
|
247
|
-
? `${movie.metaImage.url}?${makeSrcQueryString(IMAGE_WIDTH * 2)}`
|
|
248
|
-
: null
|
|
133
|
+
src={
|
|
134
|
+
movie?.metaImage?.url ? `${movie.metaImage?.url}?${makeSrcQueryString(IMAGE_WIDTH * 2)}` : undefined
|
|
249
135
|
}
|
|
250
|
-
aria-label={movie.metaImage && movie.metaImage.alt}
|
|
251
|
-
title={movie.title}
|
|
252
136
|
/>
|
|
253
137
|
<MovieTextWrapper>
|
|
254
138
|
<MovieTitle>{movie.title}</MovieTitle>
|
|
@@ -256,9 +140,9 @@ const AllMoviesAlphabetically = ({ movies, locale }: Props) => {
|
|
|
256
140
|
</MovieTextWrapper>
|
|
257
141
|
</StyledSafeLink>
|
|
258
142
|
</MovieItem>
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
143
|
+
))}
|
|
144
|
+
</MovieGroup>
|
|
145
|
+
))}
|
|
262
146
|
</StyledWrapper>
|
|
263
147
|
);
|
|
264
148
|
};
|
|
@@ -1,3 +1,11 @@
|
|
|
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
|
+
|
|
1
9
|
import React from 'react';
|
|
2
10
|
import { spacing, colors, fonts, breakpoints } from '@ndla/core';
|
|
3
11
|
import SafeLink from '@ndla/safelink';
|
|
@@ -24,41 +32,45 @@ const FilmContentCard = ({
|
|
|
24
32
|
hideTags = false,
|
|
25
33
|
}: Props) => {
|
|
26
34
|
let backgroundImage = `${(metaImage && metaImage.url) || ''}`;
|
|
35
|
+
const contentTypeId = `content-type-${id}`;
|
|
27
36
|
if (resizeThumbnailImages && metaImage) {
|
|
28
37
|
backgroundImage += '?width=480';
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
return (
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
<StyledSafeLink
|
|
42
|
+
onMouseDown={(e) => e.preventDefault()}
|
|
43
|
+
to={path}
|
|
44
|
+
aria-describedby={contentTypeId}
|
|
45
|
+
columnWidth={columnWidth}
|
|
46
|
+
style={{ marginRight: `${distanceBetweenItems}px` }}>
|
|
47
|
+
<StyledImage
|
|
48
|
+
role="img"
|
|
49
|
+
columnWidth={columnWidth}
|
|
50
|
+
style={{
|
|
51
|
+
backgroundImage: `url(${backgroundImage}?${makeSrcQueryString(600)})`,
|
|
52
|
+
}}>
|
|
53
|
+
{movieResourceTypes && !hideTags && (
|
|
54
|
+
<FilmContentCardTags
|
|
55
|
+
id={contentTypeId}
|
|
56
|
+
movieResourceTypes={movieResourceTypes}
|
|
57
|
+
resourceTypes={resourceTypes}
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
</StyledImage>
|
|
61
|
+
<StyledMovieTitle>{title}</StyledMovieTitle>
|
|
62
|
+
</StyledSafeLink>
|
|
48
63
|
);
|
|
49
64
|
};
|
|
50
65
|
|
|
51
|
-
const StyledMovieTitle = styled.
|
|
66
|
+
const StyledMovieTitle = styled.span`
|
|
52
67
|
${fonts.sizes('14px', '20px')};
|
|
53
68
|
font-weight: ${fonts.weight.semibold};
|
|
54
69
|
color: #fff;
|
|
55
|
-
margin: ${spacing.xsmall} 0 ${spacing.normal};
|
|
56
|
-
min-height: ${spacing.large};
|
|
57
70
|
@media (min-width: ${breakpoints.mobileWide}) {
|
|
58
71
|
${fonts.sizes('16px', '22px')};
|
|
59
72
|
}
|
|
60
73
|
@media (min-width: ${breakpoints.tablet}) {
|
|
61
|
-
margin: ${spacing.small} 0;
|
|
62
74
|
${fonts.sizes('18px', '24px')};
|
|
63
75
|
}
|
|
64
76
|
`;
|
|
@@ -93,11 +105,18 @@ interface StyledSlideWrapperProps {
|
|
|
93
105
|
columnWidth: number;
|
|
94
106
|
}
|
|
95
107
|
|
|
96
|
-
const
|
|
108
|
+
const shouldForwardProp = (p: string) => p !== 'columnWidth';
|
|
109
|
+
|
|
110
|
+
const StyledSafeLink = styled(SafeLink, { shouldForwardProp })<StyledSlideWrapperProps>`
|
|
111
|
+
display: flex;
|
|
112
|
+
flex-direction: column;
|
|
113
|
+
gap: ${spacing.small};
|
|
97
114
|
width: ${(props) => props.columnWidth}px;
|
|
98
115
|
color: #fff;
|
|
99
116
|
box-shadow: none;
|
|
100
117
|
&:hover,
|
|
118
|
+
&:focus-within,
|
|
119
|
+
&:active,
|
|
101
120
|
&:focus {
|
|
102
121
|
${StyledMovieTitle} {
|
|
103
122
|
text-decoration: underline;
|
|
@@ -23,10 +23,11 @@ const StyledMovieTags = styled.span`
|
|
|
23
23
|
`;
|
|
24
24
|
|
|
25
25
|
interface Props {
|
|
26
|
+
id: string;
|
|
26
27
|
movieResourceTypes: MovieResourceType[];
|
|
27
28
|
resourceTypes: MovieResourceType[];
|
|
28
29
|
}
|
|
29
|
-
const FilmContentCardTags = ({ movieResourceTypes, resourceTypes }: Props) => {
|
|
30
|
+
const FilmContentCardTags = ({ movieResourceTypes, resourceTypes, id }: Props) => {
|
|
30
31
|
const resources: Record<string, boolean> = {};
|
|
31
32
|
movieResourceTypes.forEach((movieResourceType) => {
|
|
32
33
|
const resource = resourceTypes.find((resourceType) => resourceType.id === movieResourceType.id);
|
|
@@ -35,7 +36,7 @@ const FilmContentCardTags = ({ movieResourceTypes, resourceTypes }: Props) => {
|
|
|
35
36
|
}
|
|
36
37
|
});
|
|
37
38
|
return (
|
|
38
|
-
<StyledWrapperDiv>
|
|
39
|
+
<StyledWrapperDiv id={id}>
|
|
39
40
|
{Object.keys(resources).map((resourceName) => (
|
|
40
41
|
<StyledMovieTags key={resourceName}>{resourceName}</StyledMovieTags>
|
|
41
42
|
))}
|
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { Carousel, CalculatedCarouselProps } from '@ndla/carousel';
|
|
10
10
|
import styled from '@emotion/styled';
|
|
11
|
+
import { IconButtonV2 } from '@ndla/button';
|
|
12
|
+
import { ChevronLeft, ChevronRight } from '@ndla/icons/common';
|
|
11
13
|
import { breakpoints, mq, spacing } from '@ndla/core';
|
|
12
14
|
import FilmContentCard from './FilmContentCard';
|
|
13
15
|
import { MovieResourceType, MovieType } from './types';
|
|
14
|
-
import {
|
|
16
|
+
import { StyledHeadingH2 } from './filmStyles';
|
|
15
17
|
|
|
16
18
|
interface Props {
|
|
17
19
|
movies: MovieType[];
|
|
@@ -40,13 +42,18 @@ const FilmMovieList = ({
|
|
|
40
42
|
resizeThumbnailImages,
|
|
41
43
|
}: Props) => (
|
|
42
44
|
<StyledSection>
|
|
43
|
-
<
|
|
45
|
+
<StyledHeadingH2 marginLeft={autoSizedProps.margin}>{name}</StyledHeadingH2>
|
|
44
46
|
<Carousel
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
leftButton={
|
|
48
|
+
<IconButtonV2 aria-label={slideBackwardsLabel}>
|
|
49
|
+
<ChevronLeft />
|
|
50
|
+
</IconButtonV2>
|
|
51
|
+
}
|
|
52
|
+
rightButton={
|
|
53
|
+
<IconButtonV2 aria-label={slideForwardsLabel}>
|
|
54
|
+
<ChevronRight />
|
|
55
|
+
</IconButtonV2>
|
|
56
|
+
}
|
|
50
57
|
items={movies.map((movie) => (
|
|
51
58
|
<FilmContentCard
|
|
52
59
|
key={movie.id}
|
|
@@ -78,9 +78,9 @@ const FilmMovieSearch = ({
|
|
|
78
78
|
<OneColumn>
|
|
79
79
|
<TopicNavigation>
|
|
80
80
|
<StyledHeadingH2 id={skipToContentId} className="u-12/12 u-4/12@tablet">
|
|
81
|
-
{t('ndlaFilm.subjectsInMovies')}
|
|
81
|
+
{`${t('ndlaFilm.subjectsInMovies')}:`}
|
|
82
82
|
</StyledHeadingH2>
|
|
83
|
-
<nav className="u-12/12 u-8/12@tablet">
|
|
83
|
+
<nav className="u-12/12 u-8/12@tablet" aria-labelledby={skipToContentId}>
|
|
84
84
|
<ul>
|
|
85
85
|
{topics.map((topic) => (
|
|
86
86
|
<li key={topic.id}>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
10
|
-
import { SwipeEventData, useSwipeable } from 'react-swipeable';
|
|
10
|
+
import { SwipeDirections, SwipeEventData, useSwipeable } from 'react-swipeable';
|
|
11
11
|
import styled from '@emotion/styled';
|
|
12
12
|
import { css } from '@emotion/react';
|
|
13
13
|
import { breakpoints, mq, spacing, spacingUnit, fonts, colors } from '@ndla/core';
|
|
@@ -104,7 +104,9 @@ interface SlideshowLinkProps {
|
|
|
104
104
|
out?: boolean;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
const
|
|
107
|
+
const shouldForwardProp = (p: string) => p !== 'out';
|
|
108
|
+
|
|
109
|
+
const SlideshowLink = styled(SafeLink, { shouldForwardProp })<SlideshowLinkProps>`
|
|
108
110
|
display: flex;
|
|
109
111
|
box-shadow: none;
|
|
110
112
|
transition: all 400ms ease;
|
|
@@ -120,8 +122,9 @@ const SlideshowLink = styled(SafeLink)<SlideshowLinkProps>`
|
|
|
120
122
|
padding-bottom: ${spacingUnit * 3}px;
|
|
121
123
|
}
|
|
122
124
|
&:hover {
|
|
123
|
-
|
|
125
|
+
${() => SlideshowName} {
|
|
124
126
|
text-decoration: underline;
|
|
127
|
+
text-decoration-color: white;
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
`;
|
|
@@ -138,8 +141,9 @@ const SlideshowWrapper = styled.section`
|
|
|
138
141
|
`;
|
|
139
142
|
|
|
140
143
|
const SlideshowInfo = styled.div`
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
display: flex;
|
|
145
|
+
flex-direction: column;
|
|
146
|
+
gap: ${spacing.small};
|
|
143
147
|
background-color: rgba(3, 23, 43, 0.7);
|
|
144
148
|
border-radius: 4px;
|
|
145
149
|
padding: ${spacing.medium} ${spacing.medium} ${spacing.medium} ${spacing.normal};
|
|
@@ -150,40 +154,38 @@ const SlideshowInfo = styled.div`
|
|
|
150
154
|
width: 100%;
|
|
151
155
|
padding: ${spacing.medium} ${spacingUnit * 2}px ${spacing.medium} ${spacing.normal};
|
|
152
156
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
${mq.range({ from: breakpoints.tablet })} {
|
|
164
|
-
${fonts.sizes('40px', '44px')};
|
|
165
|
-
}
|
|
166
|
-
${mq.range({ from: breakpoints.desktop })} {
|
|
167
|
-
${fonts.sizes('48px', '54px')};
|
|
168
|
-
}
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
const SlideshowName = styled.p`
|
|
160
|
+
${fonts.sizes('22px', '30px')};
|
|
161
|
+
color: ${colors.white};
|
|
162
|
+
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
|
163
|
+
margin: 0;
|
|
164
|
+
font-weight: ${fonts.weight.semibold};
|
|
165
|
+
${mq.range({ from: breakpoints.mobileWide })} {
|
|
166
|
+
${fonts.sizes('26px', '30px')};
|
|
169
167
|
}
|
|
168
|
+
${mq.range({ from: breakpoints.tablet })} {
|
|
169
|
+
${fonts.sizes('40px', '44px')};
|
|
170
|
+
}
|
|
171
|
+
${mq.range({ from: breakpoints.desktop })} {
|
|
172
|
+
${fonts.sizes('48px', '54px')};
|
|
173
|
+
}
|
|
174
|
+
`;
|
|
170
175
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
${fonts.sizes('
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
${mq.range({ from: breakpoints.wide })} {
|
|
185
|
-
${fonts.sizes('20px', '32px')};
|
|
186
|
-
}
|
|
176
|
+
const SlideshowDescription = styled.p`
|
|
177
|
+
color: ${colors.white};
|
|
178
|
+
margin: 0;
|
|
179
|
+
padding: 0;
|
|
180
|
+
${fonts.sizes('12px', '18px')};
|
|
181
|
+
${mq.range({ from: breakpoints.mobileWide })} {
|
|
182
|
+
${fonts.sizes('15px', '20px')};
|
|
183
|
+
}
|
|
184
|
+
${mq.range({ from: breakpoints.tablet })} {
|
|
185
|
+
${fonts.sizes('18px', '24px')};
|
|
186
|
+
}
|
|
187
|
+
${mq.range({ from: breakpoints.wide })} {
|
|
188
|
+
${fonts.sizes('20px', '32px')};
|
|
187
189
|
}
|
|
188
190
|
`;
|
|
189
191
|
|
|
@@ -215,6 +217,7 @@ const FilmSlideshow = ({ autoSlide = false, slideshow = [], slideInterval = 5000
|
|
|
215
217
|
const [slideIndex, setSlideIndex] = useState(0);
|
|
216
218
|
const [slideIndexTarget, setSlideIndexTarget] = useState(0);
|
|
217
219
|
const [animationComplete, setAnimationComplete] = useState(true);
|
|
220
|
+
const [swipeDirection, setSwipeDirection] = useState<SwipeDirections | undefined>(undefined);
|
|
218
221
|
const slideRef = useRef<HTMLDivElement>(null);
|
|
219
222
|
const slideText = useRef<HTMLDivElement>(null);
|
|
220
223
|
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
@@ -263,6 +266,7 @@ const FilmSlideshow = ({ autoSlide = false, slideshow = [], slideInterval = 5000
|
|
|
263
266
|
};
|
|
264
267
|
|
|
265
268
|
const onSwipeEnd = () => {
|
|
269
|
+
setSwipeDirection(undefined);
|
|
266
270
|
let slide;
|
|
267
271
|
if (swipeDistance > 40) {
|
|
268
272
|
slide = -1;
|
|
@@ -292,7 +296,11 @@ const FilmSlideshow = ({ autoSlide = false, slideshow = [], slideInterval = 5000
|
|
|
292
296
|
};
|
|
293
297
|
|
|
294
298
|
const onSwipe = (eventData: SwipeEventData) => {
|
|
295
|
-
if (eventData.
|
|
299
|
+
if (eventData.initial) {
|
|
300
|
+
setSwipeDirection(eventData.dir);
|
|
301
|
+
}
|
|
302
|
+
const dir = eventData.initial ? eventData.dir : swipeDirection;
|
|
303
|
+
if (dir === 'Up' || dir === 'Down') {
|
|
296
304
|
return;
|
|
297
305
|
}
|
|
298
306
|
if (timer.current) {
|
|
@@ -352,6 +360,7 @@ const FilmSlideshow = ({ autoSlide = false, slideshow = [], slideInterval = 5000
|
|
|
352
360
|
const handlers = useSwipeable({
|
|
353
361
|
onSwiped: onSwipeEnd,
|
|
354
362
|
onSwiping: onSwipe,
|
|
363
|
+
preventScrollOnSwipe: swipeDirection === 'Left' || swipeDirection === 'Right',
|
|
355
364
|
});
|
|
356
365
|
|
|
357
366
|
if (slideshow.length === 0) {
|
|
@@ -381,8 +390,8 @@ const FilmSlideshow = ({ autoSlide = false, slideshow = [], slideInterval = 5000
|
|
|
381
390
|
<OneColumn>
|
|
382
391
|
<SlideshowLink to={slideshow[activeSlide].path} out={!animationComplete}>
|
|
383
392
|
<SlideshowInfo ref={slideText}>
|
|
384
|
-
<
|
|
385
|
-
<
|
|
393
|
+
<SlideshowName>{slideshow[activeSlide].title}</SlideshowName>
|
|
394
|
+
<SlideshowDescription>{slideshow[activeSlide].metaDescription}</SlideshowDescription>
|
|
386
395
|
</SlideshowInfo>
|
|
387
396
|
</SlideshowLink>
|
|
388
397
|
</OneColumn>
|