@ndla/ui 8.0.1 → 8.1.2

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 (47) hide show
  1. package/es/Article/Article.js +2 -3
  2. package/es/BannerCard/BannerCard.js +75 -0
  3. package/es/BannerCard/index.js +9 -0
  4. package/es/MessageBox/MessageBox.js +38 -50
  5. package/es/Programme/ProgrammeSubjects.js +8 -2
  6. package/es/ResourceBox/ResourceBox.js +154 -0
  7. package/es/ResourceBox/index.js +9 -0
  8. package/es/TopicMenu/TopicMenu.js +5 -2
  9. package/es/index.js +3 -1
  10. package/es/locale/messages-en.js +2 -1
  11. package/es/locale/messages-nb.js +2 -1
  12. package/es/locale/messages-nn.js +2 -1
  13. package/lib/Article/Article.js +2 -3
  14. package/lib/BannerCard/BannerCard.d.ts +13 -0
  15. package/lib/BannerCard/BannerCard.js +85 -0
  16. package/lib/BannerCard/index.d.ts +9 -0
  17. package/lib/BannerCard/index.js +15 -0
  18. package/lib/MessageBox/MessageBox.d.ts +2 -3
  19. package/lib/MessageBox/MessageBox.js +38 -51
  20. package/lib/Programme/ProgrammeSubjects.d.ts +1 -0
  21. package/lib/Programme/ProgrammeSubjects.js +10 -2
  22. package/lib/ResourceBox/ResourceBox.d.ts +13 -0
  23. package/lib/ResourceBox/ResourceBox.js +154 -0
  24. package/lib/ResourceBox/index.d.ts +9 -0
  25. package/lib/ResourceBox/index.js +15 -0
  26. package/lib/TopicMenu/TopicMenu.js +5 -2
  27. package/lib/index.d.ts +2 -0
  28. package/lib/index.js +19 -1
  29. package/lib/locale/messages-en.d.ts +1 -0
  30. package/lib/locale/messages-en.js +2 -1
  31. package/lib/locale/messages-nb.d.ts +1 -0
  32. package/lib/locale/messages-nb.js +2 -1
  33. package/lib/locale/messages-nn.d.ts +1 -0
  34. package/lib/locale/messages-nn.js +2 -1
  35. package/package.json +3 -5
  36. package/src/Article/Article.tsx +1 -3
  37. package/src/BannerCard/BannerCard.tsx +99 -0
  38. package/src/BannerCard/index.ts +11 -0
  39. package/src/MessageBox/MessageBox.tsx +3 -14
  40. package/src/Programme/ProgrammeSubjects.tsx +5 -0
  41. package/src/ResourceBox/ResourceBox.tsx +190 -0
  42. package/src/ResourceBox/index.ts +11 -0
  43. package/src/TopicMenu/TopicMenu.jsx +4 -1
  44. package/src/index.ts +3 -0
  45. package/src/locale/messages-en.ts +1 -0
  46. package/src/locale/messages-nb.ts +1 -0
  47. package/src/locale/messages-nn.ts +1 -0
@@ -191,9 +191,7 @@ export const Article = ({
191
191
 
192
192
  {messages.messageBox && (
193
193
  <MSGboxWrapper>
194
- <MessageBox links={messageBoxLinks} showCloseButton>
195
- {messages.messageBox}
196
- </MessageBox>
194
+ <MessageBox links={messageBoxLinks}>{messages.messageBox}</MessageBox>
197
195
  </MSGboxWrapper>
198
196
  )}
199
197
  <ArticleHeaderWrapper competenceGoals={competenceGoals} competenceGoalTypes={competenceGoalTypes}>
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Copyright (c) 2022-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
+ import React from 'react';
9
+ import { colors, fonts, breakpoints, mq } from '@ndla/core';
10
+ import SafeLink from '@ndla/safelink';
11
+ import styled from '@emotion/styled';
12
+ import { Image } from '..';
13
+
14
+ const BannerWrapper = styled.div`
15
+ display: flex;
16
+ align-items: flex-start;
17
+ flex-direction: row;
18
+ max-width: 669px;
19
+ border-radius: 8px;
20
+ border: 1px solid ${colors.brand.greyLight};
21
+ font-family: ${fonts.sans};
22
+ padding: 30px;
23
+ gap: 30px;
24
+ ${mq.range({ until: breakpoints.tabletWide })} {
25
+ flex-direction: column;
26
+ }
27
+ `;
28
+
29
+ const ImageWrapper = styled.div`
30
+ display: flex;
31
+ flex: 0 0 40%;
32
+ ${mq.range({ until: breakpoints.tabletWide })} {
33
+ display: block;
34
+ text-align: center;
35
+ width: 100%;
36
+ }
37
+ `;
38
+
39
+ const StyledImage = styled(Image)`
40
+ ${mq.range({ until: breakpoints.tabletWide })} {
41
+ max-height: 150px;
42
+ }
43
+ `;
44
+
45
+ const TextWrapper = styled.div`
46
+ ${mq.range({ until: breakpoints.tabletWide })} {
47
+ margin-left: 0;
48
+ margin-top: 10px;
49
+ }
50
+ `;
51
+
52
+ const ContentText = styled.p`
53
+ font-size: ${fonts.sizes(16)};
54
+ color: ${colors.brand.grey};
55
+ margin: 0;
56
+ padding-top: 10px;
57
+ padding-bottom: 10px;
58
+ `;
59
+ const LinkText = styled(SafeLink)`
60
+ font-size: ${fonts.sizes(16)};
61
+ color: ${colors.brand.grey};
62
+ `;
63
+ const TitleText = styled.h2`
64
+ margin-top: 7px;
65
+ font-size: ${fonts.sizes(22)};
66
+ ${mq.range({ until: breakpoints.tabletWide })} {
67
+ margin-top: 0;
68
+ }
69
+ `;
70
+
71
+ type ImageProps = {
72
+ altText: string;
73
+ imageSrc: string;
74
+ };
75
+ type BannerProps = {
76
+ link: string;
77
+ image: ImageProps;
78
+ title: string;
79
+ content: string;
80
+ linkText: string;
81
+ };
82
+ export const BannerCard = ({ link, title, content, linkText, image }: BannerProps) => {
83
+ return (
84
+ <BannerWrapper>
85
+ <ImageWrapper>
86
+ <StyledImage alt={image.altText} src={image.imageSrc} />
87
+ </ImageWrapper>
88
+ <TextWrapper>
89
+ <TitleText>{title}</TitleText>
90
+ <ContentText>{content}</ContentText>
91
+ <LinkText target="_self" to={link}>
92
+ {linkText}
93
+ </LinkText>
94
+ </TextWrapper>
95
+ </BannerWrapper>
96
+ );
97
+ };
98
+
99
+ export default BannerCard;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Copyright (c) 2022-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 BannerCard from './BannerCard';
10
+
11
+ export { BannerCard };
@@ -8,7 +8,6 @@
8
8
 
9
9
  import React, { HTMLAttributes, useState } from 'react';
10
10
  import styled from '@emotion/styled';
11
- import Sticky from 'react-sticky-el';
12
11
  import { breakpoints, fonts, mq, spacing } from '@ndla/core';
13
12
  import { InformationOutline, HumanMaleBoard } from '@ndla/icons/common';
14
13
  import { WithTranslation, withTranslation } from 'react-i18next';
@@ -82,7 +81,6 @@ const Wrapper = styled.div<WrapperProps>`
82
81
  border-radius: ${(props) => StyleByType(props.boxType).borderRadius};
83
82
  transform: ${(props) => StyleByType(props.boxType).transform};
84
83
  left: ${(props) => StyleByType(props.boxType).left};
85
- z-index: 10;
86
84
  width: ${(props) => StyleByType(props.boxType).width};
87
85
  `;
88
86
 
@@ -155,7 +153,6 @@ type LinkProps = {
155
153
  };
156
154
  type Props = {
157
155
  type?: WrapperProps['boxType'];
158
- sticky?: boolean;
159
156
  children?: string;
160
157
  links?: LinkProps[];
161
158
  showCloseButton?: boolean;
@@ -166,14 +163,7 @@ const markdown = new Remarkable({ breaks: true });
166
163
  markdown.inline.ruler.enable(['sub', 'sup']);
167
164
  markdown.block.ruler.disable(['list', 'table']);
168
165
 
169
- export const MessageBox = ({
170
- type,
171
- sticky = false,
172
- children = '',
173
- links,
174
- showCloseButton,
175
- onClose,
176
- }: Props & WithTranslation) => {
166
+ export const MessageBox = ({ type, children = '', links, showCloseButton, onClose }: Props & WithTranslation) => {
177
167
  const [hideMessageBox, setHideMessageBox] = useState(false);
178
168
  const onCloseMessageBox = () => {
179
169
  setHideMessageBox(true);
@@ -181,8 +171,7 @@ export const MessageBox = ({
181
171
  };
182
172
  const Icon = type === 'ghost' ? HumanMaleBoard : InformationOutline;
183
173
  return (
184
- //StickyStyle top:84 makes sure that the messagebox sits beneath the masthead (header ) and the topOffsett sets it so that it applies when reaching the top of the messagebox
185
- <Sticky disabled={!sticky} stickyStyle={{ zIndex: 9998, top: 84 }} topOffset={-84}>
174
+ <>
186
175
  <Wrapper boxType={type} style={{ display: hideMessageBox ? 'none' : 'flex' }}>
187
176
  <InfoWrapper boxType={type}>
188
177
  <IconWrapper boxType={type}>
@@ -205,7 +194,7 @@ export const MessageBox = ({
205
194
  ))}
206
195
  </LinkWrapper>
207
196
  )}
208
- </Sticky>
197
+ </>
209
198
  );
210
199
  };
211
200
 
@@ -7,10 +7,12 @@
7
7
  */
8
8
 
9
9
  import React from 'react';
10
+ import { useTranslation } from 'react-i18next';
10
11
  import styled from '@emotion/styled';
11
12
  import Button from '@ndla/button';
12
13
  import { breakpoints, mq } from '@ndla/core';
13
14
  import { NavigationBox } from '../Navigation';
15
+ import { MessageBox } from '../MessageBox';
14
16
 
15
17
  const GradesMenu = styled.div`
16
18
  margin-bottom: 28px;
@@ -29,6 +31,7 @@ export type GradesProps = {
29
31
  selectedGrade?: string;
30
32
  onChangeGrade: (newGrade: string) => void;
31
33
  grades: {
34
+ missingProgrammeSubjects?: boolean;
32
35
  name: string;
33
36
  categories: {
34
37
  name: string;
@@ -45,6 +48,7 @@ type Props = GradesProps & {
45
48
  };
46
49
 
47
50
  const ProgrammeSubjects = ({ grades, onNavigate, onChangeGrade, selectedGrade = 'vg1' }: Props) => {
51
+ const { t } = useTranslation();
48
52
  const grade = grades.find((grade) => grade.name.toLowerCase() === selectedGrade) ?? grades[0];
49
53
  return (
50
54
  <>
@@ -60,6 +64,7 @@ const ProgrammeSubjects = ({ grades, onNavigate, onChangeGrade, selectedGrade =
60
64
  </Button>
61
65
  ))}
62
66
  </GradesMenu>
67
+ {grade.missingProgrammeSubjects && <MessageBox>{t('messageBoxInfo.noContent')}</MessageBox>}
63
68
  {grade.categories.map((category) => (
64
69
  <NavigationBox key={category.name} heading={category.name} items={category.subjects} onClick={onNavigate} />
65
70
  ))}
@@ -0,0 +1,190 @@
1
+ /**
2
+ *
3
+ * Copyright (c) 2022-present, NDLA.
4
+ *
5
+ * This source code is licensed under the GPLv3 license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ */
9
+ import React from 'react';
10
+ import { breakpoints, fonts, mq, colors } from '@ndla/core';
11
+ import { useTranslation } from 'react-i18next';
12
+ import { Launch } from '@ndla/icons/common';
13
+ import { LicenseByline } from '@ndla/licenses';
14
+ import { SafeLinkButton } from '@ndla/safelink';
15
+ import styled from '@emotion/styled';
16
+ import Image from '../Image';
17
+
18
+ const BoxWrapper = styled.div`
19
+ display: flex;
20
+ padding-top: 20px;
21
+ padding-bottom: 20px;
22
+ border-radius: 5px;
23
+ border: 1px solid ${colors.brand.light};
24
+ position: relative;
25
+ left: -16.6666666667%;
26
+ width: 133.3333333333%;
27
+ align-items: stretch;
28
+ margin-bottom: 24px;
29
+ font-family: ${fonts.sans};
30
+ box-shadow: 0px 20px 35px -15px rgba(32, 88, 143, 0.15);
31
+ gap: 40px;
32
+
33
+ ${mq.range({ until: breakpoints.desktop })} {
34
+ gap: 1px;
35
+ flex-direction: column;
36
+ margin: 0 auto;
37
+ width: 80%;
38
+ left: 0;
39
+ padding-left: 24px;
40
+ padding-right: 24px;
41
+ padding-bottom: 0;
42
+ margin-bottom: 24px;
43
+ height: auto;
44
+ text-align: center;
45
+ }
46
+ `;
47
+
48
+ const Boxtitle = styled.h3`
49
+ font-weight: ${fonts.weight.bold};
50
+ font-size: ${fonts.sizes(18)};
51
+ margin-top: 0;
52
+ ${mq.range({ until: breakpoints.desktop })} {
53
+ text-align: center;
54
+ width: 100%;
55
+ }
56
+ `;
57
+
58
+ const Boxcaption = styled.p`
59
+ font-size: ${fonts.sizes(14)};
60
+
61
+ ${mq.range({ until: breakpoints.desktop })} {
62
+ line-height: 22px;
63
+ }
64
+ `;
65
+
66
+ const StyledButtonDiv = styled.div`
67
+ align-items: flex-start;
68
+ ${mq.range({ until: breakpoints.desktop })} {
69
+ padding-bottom: 10px;
70
+ margin: 0 auto;
71
+ }
72
+ `;
73
+ const ResourceBoxStyledButton = styled(SafeLinkButton)`
74
+ border: 1px solid ${colors.brand.tertiary};
75
+ :hover {
76
+ background-color: ${colors.brand.primary};
77
+ color: white;
78
+ }
79
+ ${mq.range({ until: breakpoints.desktop })} {
80
+ width: 210px;
81
+ }
82
+ `;
83
+ const ResourceBoxLaunchIcon = styled(Launch)`
84
+ margin-left: 8px;
85
+ height: 15px;
86
+ width: 15px;
87
+ `;
88
+
89
+ const BoxImage = styled(Image)`
90
+ object-fit: cover;
91
+ width: 134px;
92
+ height: 134px;
93
+ border-radius: 5px;
94
+
95
+ ${mq.range({ until: breakpoints.desktop })} {
96
+ width: 200px;
97
+ height: 200px;
98
+ }
99
+ `;
100
+ const ImageSectionWrapper = styled.div`
101
+ align-items: flex-start;
102
+ display: flex;
103
+ justify-content: center;
104
+ margin-left: 20px;
105
+ ${mq.range({ until: breakpoints.desktop })} {
106
+ margin: 0 auto;
107
+ padding-top: 10px;
108
+ }
109
+ `;
110
+
111
+ const CaptionSectionWrapper = styled.div`
112
+ max-width: 600px;
113
+ ${mq.range({ until: breakpoints.desktop })} {
114
+ margin: 0 auto;
115
+ }
116
+ `;
117
+
118
+ const CenterItems = styled.div`
119
+ display: flex;
120
+ justify-content: center;
121
+ align-items: flex-start;
122
+ flex-flow: column;
123
+ ${mq.range({ until: breakpoints.desktop })} {
124
+ width: 100%;
125
+ }
126
+ `;
127
+
128
+ const TitleAndLicence = styled.div`
129
+ display: flex;
130
+ justify-content: space-between;
131
+ ${mq.range({ until: breakpoints.desktop })} {
132
+ text-align: center;
133
+ padding-top: 10px;
134
+ max-width: 200px;
135
+ margin: 0 auto;
136
+ }
137
+ `;
138
+
139
+ const LincenseWrapper = styled.div`
140
+ top: 9px;
141
+ position: absolute;
142
+ right: 1px;
143
+ ul {
144
+ margin-right: 0;
145
+ }
146
+ `;
147
+
148
+ type Props = {
149
+ image: string;
150
+ title: string;
151
+ caption: string;
152
+ licenseRights: string[];
153
+ authors?: { name: string }[];
154
+ locale?: string;
155
+ url: string;
156
+ };
157
+ export const ResourceBox = ({ image, title, caption, licenseRights, locale, authors, url }: Props) => {
158
+ const { t } = useTranslation();
159
+ return (
160
+ <BoxWrapper>
161
+ <ImageSectionWrapper>
162
+ <BoxImage alt={title} src={image} sizes="25, 25" />
163
+ </ImageSectionWrapper>
164
+ <CenterItems>
165
+ <CaptionSectionWrapper>
166
+ <TitleAndLicence>
167
+ <Boxtitle>{title}</Boxtitle>
168
+ <LincenseWrapper>
169
+ <LicenseByline licenseRights={licenseRights} locale={locale} marginRight color={colors.brand.tertiary}>
170
+ <div className="c-figure__byline-author-buttons">
171
+ <span className="c-figure__byline-authors">{authors?.map((author) => author.name).join(' ')}</span>
172
+ </div>
173
+ </LicenseByline>
174
+ </LincenseWrapper>
175
+ </TitleAndLicence>
176
+ <Boxcaption>{caption}</Boxcaption>
177
+ </CaptionSectionWrapper>
178
+
179
+ <StyledButtonDiv>
180
+ <ResourceBoxStyledButton to={url} target="_blank" outline borderShape="rounded">
181
+ {t('license.other.itemImage.ariaLabel')}
182
+ <ResourceBoxLaunchIcon aria-hidden />
183
+ </ResourceBoxStyledButton>
184
+ </StyledButtonDiv>
185
+ </CenterItems>
186
+ </BoxWrapper>
187
+ );
188
+ };
189
+
190
+ export default ResourceBox;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Copyright (c) 2022-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 ResourceBox from './ResourceBox';
10
+
11
+ export { ResourceBox };
@@ -74,6 +74,8 @@ export const TopicMenu = ({
74
74
  currentProgramme,
75
75
  initialSelectedMenu,
76
76
  messages,
77
+ selectedGrade,
78
+ onGradeChange,
77
79
  }) => {
78
80
  const { t } = useTranslation();
79
81
  const [isNarrowScreen, setIsNarrowScreen] = useState(false);
@@ -242,7 +244,8 @@ export const TopicMenu = ({
242
244
  <div {...classes('all-subjects')}>
243
245
  <ProgrammeSubjects
244
246
  grades={currentProgramme.grades}
245
- preSelectedGradeIndex={currentProgramme.selectedGradeIndex ? currentProgramme.selectedGradeIndex : 0}
247
+ selectedGrade={selectedGrade}
248
+ onChangeGrade={onGradeChange}
246
249
  onNavigate={closeMenu}
247
250
  />
248
251
  </div>
package/src/index.ts CHANGED
@@ -117,6 +117,8 @@ export { default as Breadcrumblist } from './Breadcrumblist';
117
117
 
118
118
  export { MessageBox, MessageBoxTag, MessageBoxType } from './MessageBox';
119
119
 
120
+ export { ResourceBox } from './ResourceBox';
121
+
120
122
  export { default as CloseButton } from './CloseButton';
121
123
  export { default as AudioPlayer, initAudioPlayers } from './AudioPlayer';
122
124
 
@@ -218,3 +220,4 @@ export { default as CopyParagraphButton } from './CopyParagraphButton';
218
220
 
219
221
  export { default as ContentPlaceholder } from './ContentPlaceholder';
220
222
  export { Notion, ConceptNotion } from './Notion';
223
+ export { BannerCard } from './BannerCard';
@@ -366,6 +366,7 @@ const messages = {
366
366
  access: {
367
367
  onlyTeacher: 'This resource is accessible only to teachers who are logged in with Feide.',
368
368
  },
369
+ possiblyOutdated: 'The article is outdated',
369
370
  },
370
371
  competenceGoals: {
371
372
  competenceGoal: 'competence-goal',
@@ -364,6 +364,7 @@ const messages = {
364
364
  access: {
365
365
  onlyTeacher: 'Denne ressursen er bare tilgjengelig for lærere som er pålogget med Feide.',
366
366
  },
367
+ possiblyOutdated: 'Artikkelen er foreldet.',
367
368
  },
368
369
  competenceGoals: {
369
370
  competenceGoal: 'kompetansemål',
@@ -365,6 +365,7 @@ const messages = {
365
365
  access: {
366
366
  onlyTeacher: 'Denne ressursen er berre tilgjengeleg for lærarar som er pålogga med Feide.',
367
367
  },
368
+ possiblyOutdated: 'Artikkelen er foreldet.',
368
369
  },
369
370
  competenceGoals: {
370
371
  competenceGoal: 'kompetansemål',