@ndla/ui 8.0.0 → 8.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.
@@ -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
 
@@ -214,7 +214,7 @@ const Notion = ({ id, labels = [], text, title, visualElement, imageElement, chi
214
214
  </ImageWrapper>
215
215
  )}
216
216
  <TextWrapper hasVisualElement={!!(imageElement || visualElement?.metaImage)}>
217
- {parseMarkdown(`**${title}** \u2013 ${text}`)}
217
+ {parseMarkdown(`**${title}** \u2013 ${text}`, 'body')}
218
218
  {!!labels.length && (
219
219
  <LabelsContainer>
220
220
  {t('searchPage.resultType.notionLabels')}
@@ -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';