@ndla/ui 25.0.0 → 25.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 (95) hide show
  1. package/es/Frontpage/FrontpageSearch.js +5 -3
  2. package/es/Masthead/Masthead.js +7 -7
  3. package/es/NDLAFilm/FilmSlideshow.js +7 -7
  4. package/es/NDLAFilm/NavigationArrow.js +4 -4
  5. package/es/Notion/FigureNotion.js +4 -3
  6. package/es/Notion/NotionVisualElement.js +3 -2
  7. package/es/SectionHeading/SectionHeading.js +5 -4
  8. package/es/Subject/Subject.js +109 -64
  9. package/es/Subject/SubjectAbout.js +61 -23
  10. package/es/Subject/SubjectArchive.js +109 -67
  11. package/es/Subject/SubjectCarousel.js +39 -62
  12. package/es/Subject/SubjectHeader.js +55 -25
  13. package/es/Subject/SubjectLinks.js +30 -16
  14. package/es/Subject/SubjectNewContent.js +76 -21
  15. package/es/Subject/SubjectShortcuts.js +39 -24
  16. package/es/Subject/SubjectSocial.js +20 -18
  17. package/es/all.css +1 -1
  18. package/es/index.js +1 -0
  19. package/es/locale/messages-nb.js +21 -21
  20. package/es/locale/messages-nn.js +27 -27
  21. package/es/locale/messages-se.js +22 -22
  22. package/es/locale/messages-sma.js +22 -22
  23. package/lib/Frontpage/FrontpageMultidisciplinarySubject.d.ts +5 -5
  24. package/lib/Frontpage/FrontpageSearch.js +6 -3
  25. package/lib/Frontpage/illustrations/FrontpageIllustrations.d.ts +2 -2
  26. package/lib/Masthead/Masthead.js +16 -16
  27. package/lib/MultidisciplinarySubject/Illustrations.d.ts +7 -7
  28. package/lib/NDLAFilm/FilmSlideshow.js +7 -7
  29. package/lib/NDLAFilm/NavigationArrow.js +4 -4
  30. package/lib/Notion/FigureNotion.d.ts +2 -1
  31. package/lib/Notion/FigureNotion.js +4 -3
  32. package/lib/Notion/NotionVisualElement.d.ts +1 -0
  33. package/lib/Notion/NotionVisualElement.js +3 -2
  34. package/lib/Resource/resourceComponents.d.ts +2 -2
  35. package/lib/Search/ActiveFilterContent.d.ts +1 -1
  36. package/lib/Search/ContentTypeResultStyles.d.ts +3 -3
  37. package/lib/SearchTypeResult/ActiveFilterContent.d.ts +1 -1
  38. package/lib/SectionHeading/SectionHeading.js +10 -9
  39. package/lib/Subject/Subject.d.ts +30 -82
  40. package/lib/Subject/Subject.js +90 -62
  41. package/lib/Subject/SubjectAbout.d.ts +1 -15
  42. package/lib/Subject/SubjectAbout.js +56 -25
  43. package/lib/Subject/SubjectArchive.d.ts +0 -21
  44. package/lib/Subject/SubjectArchive.js +103 -73
  45. package/lib/Subject/SubjectCarousel.d.ts +1 -31
  46. package/lib/Subject/SubjectCarousel.js +47 -76
  47. package/lib/Subject/SubjectHeader.d.ts +1 -14
  48. package/lib/Subject/SubjectHeader.js +53 -28
  49. package/lib/Subject/SubjectLinks.d.ts +1 -11
  50. package/lib/Subject/SubjectLinks.js +29 -19
  51. package/lib/Subject/SubjectNewContent.d.ts +1 -13
  52. package/lib/Subject/SubjectNewContent.js +70 -24
  53. package/lib/Subject/SubjectShortcuts.d.ts +0 -13
  54. package/lib/Subject/SubjectShortcuts.js +38 -29
  55. package/lib/Subject/SubjectSocial.d.ts +7 -22
  56. package/lib/Subject/SubjectSocial.js +19 -21
  57. package/lib/all.css +1 -1
  58. package/lib/index.d.ts +1 -0
  59. package/lib/index.js +12 -3
  60. package/lib/locale/messages-nb.js +21 -21
  61. package/lib/locale/messages-nn.js +27 -27
  62. package/lib/locale/messages-se.js +22 -22
  63. package/lib/locale/messages-sma.js +22 -22
  64. package/package.json +14 -14
  65. package/src/Frontpage/FrontpageSearch.tsx +3 -1
  66. package/src/Masthead/Masthead.tsx +1 -1
  67. package/src/NDLAFilm/FilmSlideshow.tsx +2 -0
  68. package/src/NDLAFilm/NavigationArrow.tsx +4 -4
  69. package/src/Notion/FigureNotion.tsx +5 -2
  70. package/src/Notion/NotionVisualElement.tsx +2 -0
  71. package/src/SectionHeading/SectionHeading.tsx +7 -3
  72. package/src/Subject/Subject.tsx +151 -72
  73. package/src/Subject/SubjectAbout.tsx +97 -27
  74. package/src/Subject/SubjectArchive.tsx +129 -58
  75. package/src/Subject/SubjectCarousel.tsx +42 -36
  76. package/src/Subject/SubjectHeader.tsx +75 -34
  77. package/src/Subject/SubjectLinks.tsx +21 -19
  78. package/src/Subject/SubjectNewContent.tsx +87 -32
  79. package/src/Subject/SubjectShortcuts.tsx +67 -27
  80. package/src/Subject/SubjectSocial.tsx +19 -20
  81. package/src/index.ts +2 -0
  82. package/src/locale/messages-nb.ts +21 -22
  83. package/src/locale/messages-nn.ts +27 -27
  84. package/src/locale/messages-se.ts +22 -23
  85. package/src/locale/messages-sma.ts +22 -23
  86. package/src/main.scss +0 -1
  87. package/src/Subject/component.subject-about.scss +0 -73
  88. package/src/Subject/component.subject-archive.scss +0 -92
  89. package/src/Subject/component.subject-carousel.scss +0 -32
  90. package/src/Subject/component.subject-concepts.scss +0 -37
  91. package/src/Subject/component.subject-header.scss +0 -87
  92. package/src/Subject/component.subject-links.scss +0 -14
  93. package/src/Subject/component.subject-new-content.scss +0 -82
  94. package/src/Subject/component.subject-shortcut.scss +0 -57
  95. package/src/Subject/component.subject.scss +0 -213
@@ -1,13 +1,11 @@
1
- import React, { ReactNode, Component, createRef, Fragment, RefObject } from 'react';
2
- import PropTypes from 'prop-types';
3
- import BEMHelper from 'react-bem-helper';
1
+ import React, { ReactNode, Component, createRef, RefObject } from 'react';
2
+ import styled from '@emotion/styled';
4
3
  import { Forward } from '@ndla/icons/common';
5
4
  import { Cross } from '@ndla/icons/action';
5
+ import { breakpoints, colors, fonts, mq, spacing, utils } from '@ndla/core';
6
6
  import SafeLink from '@ndla/safelink';
7
7
  import SectionHeading from '../SectionHeading';
8
8
 
9
- const classes = BEMHelper('c-subject-archive');
10
-
11
9
  interface Props {
12
10
  featuringArticle: {
13
11
  media: ReactNode;
@@ -26,6 +24,109 @@ interface State {
26
24
  minHeight: number | null;
27
25
  }
28
26
 
27
+ interface SubjectArchiveSectionProps {
28
+ fixedWidth: boolean;
29
+ animate: boolean;
30
+ }
31
+
32
+ const ArchiveWrapper = styled.div`
33
+ display: flex;
34
+ flex-flow: column;
35
+ `;
36
+
37
+ const StyledSectionHeading = styled(SectionHeading)`
38
+ margin: 0 0 ${spacing.small} 0;
39
+ ${mq.range({ from: breakpoints.tablet })} {
40
+ ${utils.visuallyHidden};
41
+ }
42
+ `;
43
+
44
+ const ArchiveButon = styled.button`
45
+ display: inline-flex;
46
+ align-items: center;
47
+ cursor: pointer;
48
+ margin: ${spacing.small} 0 0 0;
49
+ padding: ${spacing.xsmall} 0;
50
+ border: 0;
51
+ color: ${colors.brand.primary};
52
+ ${fonts.sizes('16px', '24px')};
53
+ font-weight: ${fonts.weight.semibold};
54
+ ${mq.range({ from: breakpoints.tablet })} {
55
+ margin: ${spacing.xsmall} ${spacing.normal} ${spacing.normal};
56
+ }
57
+ c-icon {
58
+ width: 18px;
59
+ height: 18px;
60
+ margin-right: ${spacing.small};
61
+ }
62
+ `;
63
+
64
+ interface StyledNavProps {
65
+ animate: boolean;
66
+ }
67
+ const StyledNav = styled.nav<StyledNavProps>`
68
+ padding: 0;
69
+ animation: ${(p) => p.animate && 'fadeIn 0.3s ease-in-out'};
70
+ ${mq.range({ from: breakpoints.tablet })} {
71
+ padding: ${spacing.large} ${spacing.large} 0 ${spacing.large};
72
+ }
73
+ `;
74
+
75
+ const StyledArchiveList = styled.ul`
76
+ list-style: none;
77
+ margin: 0;
78
+ padding: 0;
79
+
80
+ li {
81
+ ${fonts.sizes('16px', '24px')};
82
+ margin-bottom: ${spacing.small};
83
+ }
84
+ `;
85
+
86
+ const MediaWrapper = styled.div`
87
+ width: 100%;
88
+ & > * {
89
+ width: 100%;
90
+ }
91
+ `;
92
+
93
+ const StyledContent = styled.div`
94
+ padding: ${spacing.small} 0 0 0;
95
+ ${mq.range({ from: breakpoints.tablet })} {
96
+ padding: ${spacing.normal};
97
+ }
98
+ `;
99
+
100
+ const StyledHeading = styled.h1`
101
+ ${fonts.sizes('20px', '32px')};
102
+ margin: 0 0 ${spacing.small} 0;
103
+ flex: 0 0 auto;
104
+ `;
105
+
106
+ const StyledDescription = styled.p`
107
+ margin: 0;
108
+ ${fonts.sizes('16px', '26px')}
109
+ `;
110
+
111
+ const SubjectArchiveSection = styled.section<SubjectArchiveSectionProps>`
112
+ margin-bottom: ${spacing.large};
113
+ display: flex;
114
+ flex-direction: column;
115
+ max-width: ${(p) => p.fixedWidth && '350px'};
116
+ animation: ${(p) => p.animate && 'fadeIn 0.3s ease-in-out'};
117
+
118
+ ${mq.range({ from: breakpoints.tablet })} {
119
+ border: 1px solid ${colors.brand.greyLight};
120
+ }
121
+ `;
122
+
123
+ interface FeaturingSectionProps {
124
+ animate: boolean;
125
+ }
126
+ const FeaturingSection = styled.section<FeaturingSectionProps>`
127
+ animation: ${(p) => p.animate && 'fadeIn 0.3s ease-in-out'};
128
+ `;
129
+
29
130
  class SubjectArchive extends Component<Props, State> {
30
131
  wrapperRef: RefObject<HTMLElement> | null = createRef<HTMLElement>();
31
132
  constructor(props: Props) {
@@ -59,81 +160,51 @@ class SubjectArchive extends Component<Props, State> {
59
160
  const archiveId = 'subject-archive';
60
161
 
61
162
  const section = this.state.archiveOpen ? (
62
- <nav id={archiveId} {...classes('archive')}>
63
- <ul {...classes('archive-articles')}>
163
+ <StyledNav id={archiveId} animate={!!this.state.minHeight}>
164
+ <StyledArchiveList>
64
165
  {archiveArticles.map((article) => (
65
166
  <li key={article.heading}>
66
167
  <SafeLink to={article.url}>{article.heading}</SafeLink>
67
168
  </li>
68
169
  ))}
69
- </ul>
70
- </nav>
170
+ </StyledArchiveList>
171
+ </StyledNav>
71
172
  ) : (
72
- <section {...classes('featuring')}>
73
- <div {...classes('media-wrapper')}>{featuringArticle.media}</div>
74
- <div {...classes('content')}>
75
- <h1 {...classes('heading')}>
173
+ <FeaturingSection animate={!!this.state.minHeight}>
174
+ <MediaWrapper>{featuringArticle.media}</MediaWrapper>
175
+ <StyledContent>
176
+ <StyledHeading>
76
177
  <SafeLink to={featuringArticle.url}>{featuringArticle.heading}</SafeLink>
77
- </h1>
78
- <p {...classes('description')}>{featuringArticle.description}</p>
79
- </div>
80
- </section>
178
+ </StyledHeading>
179
+ <StyledDescription>{featuringArticle.description}</StyledDescription>
180
+ </StyledContent>
181
+ </FeaturingSection>
81
182
  );
82
183
 
83
- const subClasses = Object.entries({ fixedWidth, animate: !!this.state.minHeight })
84
- .filter(([_, include]) => include)
85
- .map(([className, _]) => className);
86
-
87
184
  return (
88
- <section {...classes('', subClasses)} ref={this.wrapperRef}>
89
- <SectionHeading large className={classes('section-heading').className}>
90
- {sectionHeading}
91
- </SectionHeading>
92
- <div {...classes('wrapper')}>
185
+ <SubjectArchiveSection animate={!!this.state.minHeight} fixedWidth={fixedWidth} ref={this.wrapperRef}>
186
+ <StyledSectionHeading large>{sectionHeading}</StyledSectionHeading>
187
+ <ArchiveWrapper>
93
188
  {section}
94
- <button
189
+ <ArchiveButon
95
190
  type="button"
96
191
  aria-expanded={this.state.archiveOpen}
97
192
  aria-controls={archiveId}
98
- className={classes('archive-button').className}
99
193
  onClick={this.handleToggleArchive}>
100
194
  {this.state.archiveOpen ? (
101
- <Fragment>
195
+ <>
102
196
  <Cross /> <span>{messages.close}</span>
103
- </Fragment>
197
+ </>
104
198
  ) : (
105
- <Fragment>
199
+ <>
106
200
  <Forward /> <span>{messages.archive}</span>
107
- </Fragment>
201
+ </>
108
202
  )}
109
- </button>
110
- </div>
111
- </section>
203
+ </ArchiveButon>
204
+ </ArchiveWrapper>
205
+ </SubjectArchiveSection>
112
206
  );
113
207
  }
114
- static propTypes = {
115
- featuringArticle: PropTypes.shape({
116
- media: PropTypes.node.isRequired,
117
- heading: PropTypes.string.isRequired,
118
- description: PropTypes.string.isRequired,
119
- url: PropTypes.string.isRequired,
120
- }).isRequired,
121
- archiveArticles: PropTypes.arrayOf(
122
- PropTypes.shape({
123
- url: PropTypes.string.isRequired,
124
- heading: PropTypes.string.isRequired,
125
- }),
126
- ).isRequired,
127
- sectionHeading: PropTypes.string.isRequired,
128
- fixedWidth: PropTypes.bool,
129
- messages: PropTypes.shape({
130
- archive: PropTypes.string.isRequired,
131
- }),
132
- };
133
-
134
- static defaultProps = {
135
- fixedWidth: false,
136
- };
137
208
  }
138
209
 
139
210
  export default SubjectArchive;
@@ -1,15 +1,13 @@
1
1
  import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import BEMHelper from 'react-bem-helper';
2
+ import styled from '@emotion/styled';
3
+ import { css } from '@emotion/core';
4
4
  import { Carousel, CarouselAutosize } from '@ndla/carousel';
5
5
  import { withTranslation, WithTranslation } from 'react-i18next';
6
- import { spacingUnit } from '@ndla/core';
6
+ import { breakpoints, mq, spacing, spacingUnit } from '@ndla/core';
7
7
  import { SafeLinkProps } from '@ndla/safelink';
8
8
  import { ContentCard } from '../index';
9
9
  import { SubjectSectionTitle } from './Subject';
10
10
 
11
- const subjectCarouselClasses = BEMHelper('c-subject-carousel');
12
-
13
11
  interface Props {
14
12
  subjects?: {
15
13
  id: string;
@@ -24,11 +22,42 @@ interface Props {
24
22
  wideScreen?: boolean;
25
23
  }
26
24
 
27
- const getSubclasses = (obj: Record<string, boolean>): string[] => {
28
- return Object.entries(obj)
29
- .filter(([_, value]) => !!value)
30
- .map(([className, _]) => className);
31
- };
25
+ interface StyledSectionProps {
26
+ narrowScreen: boolean;
27
+ wideScreen: boolean;
28
+ }
29
+
30
+ const StyledSection = styled.section<StyledSectionProps>`
31
+ margin-bottom: ${spacing.large};
32
+ ${mq.range({ from: breakpoints.tablet })} {
33
+ margin-bottom: 100px;
34
+ }
35
+ ${(p) =>
36
+ p.narrowScreen &&
37
+ css`
38
+ display: none;
39
+ ${mq.range({ from: breakpoints.tablet })} {
40
+ display: block;
41
+ }
42
+ `};
43
+ ${(p) =>
44
+ p.narrowScreen &&
45
+ css`
46
+ ${mq.range({ from: breakpoints.tablet })} {
47
+ display: block;
48
+ }
49
+ `};
50
+ `;
51
+
52
+ const StyledSubjectSectionTitle = styled(SubjectSectionTitle)`
53
+ ${mq.range({ from: breakpoints.tablet })} {
54
+ margin-left: ${spacing.medium} !important;
55
+ }
56
+
57
+ ${mq.range({ from: breakpoints.desktop })} {
58
+ margin-left: ${spacingUnit * 3}px !important;
59
+ }
60
+ `;
32
61
 
33
62
  const SubjectCarousel = ({
34
63
  subjects = [],
@@ -37,7 +66,7 @@ const SubjectCarousel = ({
37
66
  wideScreen = false,
38
67
  t,
39
68
  }: Props & WithTranslation) => (
40
- <section {...subjectCarouselClasses('', getSubclasses({ narrowScreen, wideScreen }))}>
69
+ <StyledSection narrowScreen={narrowScreen} wideScreen={wideScreen}>
41
70
  <CarouselAutosize
42
71
  breakpoints={[
43
72
  {
@@ -99,7 +128,7 @@ const SubjectCarousel = ({
99
128
  itemsLength={subjects?.length ?? 0}>
100
129
  {(autoSizedProps) => (
101
130
  <>
102
- <SubjectSectionTitle {...subjectCarouselClasses('title')}>{title}</SubjectSectionTitle>
131
+ <StyledSubjectSectionTitle>{title}</StyledSubjectSectionTitle>
103
132
  <Carousel
104
133
  {...autoSizedProps}
105
134
  disableScroll={(autoSizedProps?.columnsPrSlide ?? 0) >= subjects.length}
@@ -122,30 +151,7 @@ const SubjectCarousel = ({
122
151
  </>
123
152
  )}
124
153
  </CarouselAutosize>
125
- </section>
154
+ </StyledSection>
126
155
  );
127
156
 
128
- SubjectCarousel.propTypes = {
129
- subjects: PropTypes.arrayOf(
130
- PropTypes.shape({
131
- id: PropTypes.string.isRequired,
132
- title: PropTypes.string.isRequired,
133
- type: PropTypes.string,
134
- text: PropTypes.string.isRequired,
135
- image: PropTypes.string,
136
- toLinkProps: PropTypes.func.isRequired,
137
- }).isRequired,
138
- ).isRequired,
139
- title: PropTypes.string,
140
- narrowScreen: PropTypes.bool,
141
- wideScreen: PropTypes.bool,
142
- };
143
-
144
- SubjectCarousel.defaultProps = {
145
- subjects: [],
146
- title: '',
147
- narrowScreen: false,
148
- wideScreen: false,
149
- };
150
-
151
157
  export default withTranslation()(SubjectCarousel);
@@ -1,13 +1,10 @@
1
1
  import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import BEMHelper from 'react-bem-helper';
4
-
2
+ import styled from '@emotion/styled';
3
+ import { css } from '@emotion/core';
5
4
  import { breakpoints } from '@ndla/util';
6
-
5
+ import { colors, fonts, mq, spacing, spacingUnit } from '@ndla/core';
7
6
  import OneColumn from '../Layout/OneColumn';
8
7
 
9
- const classes = BEMHelper('c-subject-header');
10
-
11
8
  type Types = 'mobile' | 'tablet' | 'desktop' | 'wide';
12
9
 
13
10
  interface Props {
@@ -18,36 +15,80 @@ interface Props {
18
15
  heading: string;
19
16
  }
20
17
 
21
- const SubjectHeader = ({ images, heading }: Props) => (
22
- <header {...classes()}>
23
- {images &&
24
- images.map((image) =>
25
- image.types.map((type) => (
26
- <div
27
- key={`${image.url}${type}`}
28
- {...classes('background', type)}
29
- style={{ backgroundImage: `url(${image.url})` }}
30
- />
31
- )),
32
- )}
33
- <OneColumn noPadding>
34
- <h1 {...classes('heading')}>{heading}</h1>
35
- </OneColumn>
36
- </header>
37
- );
18
+ const StyledHeader = styled.header`
19
+ width: 100%;
20
+ position: relative;
21
+ min-height: 180px;
22
+ display: flex;
23
+ justify-content: flex-start;
24
+ background: ${colors.brand.primary};
38
25
 
39
- SubjectHeader.propTypes = {
40
- images: PropTypes.arrayOf(
41
- PropTypes.shape({
42
- url: PropTypes.string.isRequired,
43
- types: PropTypes.arrayOf(PropTypes.oneOf(Object.keys(breakpoints))).isRequired,
44
- }),
45
- ),
46
- heading: PropTypes.string.isRequired,
47
- };
26
+ ${mq.range({ from: breakpoints.tablet })} {
27
+ height: 320px;
28
+ align-items: center;
29
+ }
30
+ `;
48
31
 
49
- SubjectHeader.defaultProps = {
50
- images: null,
32
+ const typeMap: Record<Types, { from?: string; until?: string }> = {
33
+ mobile: { from: breakpoints.mobile, until: breakpoints.tablet },
34
+ tablet: { from: breakpoints.tablet, until: breakpoints.desktop },
35
+ desktop: { from: breakpoints.desktop, until: breakpoints.wide },
36
+ wide: { from: breakpoints.wide },
51
37
  };
38
+ interface StyledBackgroundProps {
39
+ type: Types;
40
+ imageUrl: string;
41
+ }
42
+
43
+ const StyledBackground = styled.div<StyledBackgroundProps>`
44
+ position: absolute;
45
+ width: 100%;
46
+ height: 100%;
47
+ top: 0%;
48
+ background-size: cover;
49
+ background-repeat: no-repeat;
50
+ background-position: center right;
51
+ opacity: 0.5;
52
+ background-image: url(${(p) => p.imageUrl});
53
+ ${(p) =>
54
+ p.type &&
55
+ css`
56
+ display: none;
57
+ ${mq.range(typeMap[p.type])} {
58
+ display: block;
59
+ }
60
+ `};
61
+ `;
62
+
63
+ const StyledHeading = styled.h1`
64
+ ${fonts.sizes('24px', '28px')};
65
+ color: ${colors.white};
66
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
67
+ margin: ${spacing.medium} 0 ${spacing.normal} 0;
68
+ font-weight: ${fonts.weight.bold};
69
+ padding: 0 ${spacing.normal};
70
+
71
+ ${mq.range({ from: breakpoints.tablet })} {
72
+ margin: 0;
73
+ ${fonts.sizes('40px', '40px')};
74
+ padding: 0 0 0 ${spacingUnit * 3}px;
75
+ }
76
+ ${mq.range({ from: breakpoints.desktop })} {
77
+ margin: 0;
78
+ ${fonts.sizes('52px', '52px')};
79
+ padding: 0 0 0 ${spacingUnit * 3}px;
80
+ }
81
+ `;
82
+
83
+ const SubjectHeader = ({ images = [], heading }: Props) => (
84
+ <StyledHeader>
85
+ {images?.map((image) =>
86
+ image.types.map((type) => <StyledBackground key={`${image.url}${type}`} imageUrl={image.url} type={type} />),
87
+ )}
88
+ <OneColumn noPadding>
89
+ <StyledHeading>{heading}</StyledHeading>
90
+ </OneColumn>
91
+ </StyledHeader>
92
+ );
52
93
 
53
94
  export default SubjectHeader;
@@ -1,11 +1,23 @@
1
1
  import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import BEMHelper from 'react-bem-helper';
2
+ import styled from '@emotion/styled';
3
+ import { spacing } from '@ndla/core';
4
4
  import SafeLink, { SafeLinkProps } from '@ndla/safelink';
5
5
 
6
6
  import { SubjectSectionTitle } from './Subject';
7
7
 
8
- const classes = BEMHelper('c-subject-links');
8
+ const SubjectLinksSection = styled.section`
9
+ margin-bottom: ${spacing.large};
10
+ `;
11
+
12
+ const StyledSubjectSectionTitle = styled(SubjectSectionTitle)`
13
+ margin: 0 0 ${spacing.small} 0;
14
+ `;
15
+
16
+ const SubjectLinksList = styled.ul`
17
+ margin: 0;
18
+ padding: 0;
19
+ list-style: none;
20
+ `;
9
21
 
10
22
  interface Props {
11
23
  links: {
@@ -16,28 +28,18 @@ interface Props {
16
28
  }
17
29
 
18
30
  const SubjectLinks = ({ links, heading }: Props) => (
19
- <section {...classes()}>
20
- <SubjectSectionTitle className={classes('heading').className}>{heading}</SubjectSectionTitle>
31
+ <SubjectLinksSection>
32
+ <StyledSubjectSectionTitle>{heading}</StyledSubjectSectionTitle>
21
33
  <nav>
22
- <ul {...classes('list')}>
34
+ <SubjectLinksList>
23
35
  {links.map((link) => (
24
- <li key={link.toLinkProps().to.toString()} {...classes('item')}>
36
+ <li key={link.toLinkProps().to.toString()}>
25
37
  <SafeLink {...link.toLinkProps()}>{link.text}</SafeLink>
26
38
  </li>
27
39
  ))}
28
- </ul>
40
+ </SubjectLinksList>
29
41
  </nav>
30
- </section>
42
+ </SubjectLinksSection>
31
43
  );
32
44
 
33
- SubjectLinks.propTypes = {
34
- links: PropTypes.arrayOf(
35
- PropTypes.shape({
36
- toLinkProps: PropTypes.func.isRequired,
37
- text: PropTypes.string.isRequired,
38
- }),
39
- ),
40
- heading: PropTypes.string.isRequired,
41
- };
42
-
43
45
  export default SubjectLinks;
@@ -1,12 +1,10 @@
1
1
  import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import BEMHelper from 'react-bem-helper';
2
+ import styled from '@emotion/styled';
4
3
  import SafeLink from '@ndla/safelink';
4
+ import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
5
5
  import ContentTypeBadge from '../ContentTypeBadge';
6
6
  import { SubjectSectionTitle } from './Subject';
7
7
 
8
- const classes = BEMHelper('c-subject-new-content');
9
-
10
8
  interface Props {
11
9
  heading: string;
12
10
  content: {
@@ -17,39 +15,96 @@ interface Props {
17
15
  }[];
18
16
  }
19
17
 
18
+ const StyledSection = styled.section`
19
+ ${mq.range({ until: breakpoints.tablet })} {
20
+ margin-bottom: ${spacing.large};
21
+ }
22
+ `;
23
+
24
+ const StyledSubjectSectionTitle = styled(SubjectSectionTitle)`
25
+ ${mq.range({ from: breakpoints.tabletWide })} {
26
+ margin-left: ${spacing.large} !important;
27
+ }
28
+ `;
29
+
30
+ const StyledUl = styled.ul`
31
+ margin: 0;
32
+ padding: 0;
33
+ `;
34
+
35
+ const StyledListItem = styled.li`
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: space-between;
39
+ &:last-child {
40
+ margin-bottom: 0;
41
+ }
42
+ `;
43
+
44
+ const LeftWrapper = styled.div`
45
+ display: flex;
46
+ justify-content: flex-start;
47
+ align-items: flex-start;
48
+
49
+ .c-icon {
50
+ width: 14px;
51
+ height: 14px;
52
+ margin-left: ${spacing.xsmall};
53
+ margin-right: ${spacing.xsmall};
54
+ }
55
+
56
+ .c-content-type-badge {
57
+ margin-top: 23px;
58
+ ${mq.range({ until: breakpoints.tabletWide })} {
59
+ display: none;
60
+ }
61
+ }
62
+ `;
63
+
64
+ const ContentLinkWrapper = styled.div`
65
+ ${mq.range({ from: breakpoints.tabletWide })} {
66
+ padding-left: ${spacing.normal};
67
+ }
68
+ padding-bottom: ${spacing.small};
69
+ `;
70
+
71
+ const DateWrapper = styled.div`
72
+ color: ${colors.text.light};
73
+ ${fonts.sizes('14px', '18px')};
74
+ ${mq.range({ from: breakpoints.tablet })} {
75
+ ${fonts.sizes('16px', '20px')};
76
+ }
77
+ `;
78
+
79
+ const StyledSafeLink = styled(SafeLink)`
80
+ color: ${colors.brand.dark};
81
+ font-weight: 600;
82
+ ${fonts.sizes('16px', '20px')};
83
+ margin-bottom: ${spacing.xsmall};
84
+ ${mq.range({ from: breakpoints.tablet })} {
85
+ ${fonts.sizes('18px', '30px')};
86
+ }
87
+ `;
88
+
20
89
  const SubjectNewContent = ({ heading, content }: Props) => (
21
- <section {...classes()}>
22
- <SubjectSectionTitle className={classes('heading').className}>{heading}</SubjectSectionTitle>
23
- <nav {...classes('content')}>
24
- <ul {...classes('list')}>
90
+ <StyledSection>
91
+ <StyledSubjectSectionTitle>{heading}</StyledSubjectSectionTitle>
92
+ <nav>
93
+ <StyledUl>
25
94
  {content.map((item) => (
26
- <li {...classes('item')} key={item.url}>
27
- <div {...classes('left-wrapper')}>
95
+ <StyledListItem>
96
+ <LeftWrapper>
28
97
  <ContentTypeBadge type={item.contentType} size="x-small" background border />
29
- <div {...classes('content-link')}>
30
- <div {...classes('date')}>{item.formattedDate}</div>
31
- <SafeLink to={item.url} {...classes('link')}>
32
- {item.name}
33
- </SafeLink>
34
- </div>
35
- </div>
36
- </li>
98
+ <ContentLinkWrapper>
99
+ <DateWrapper>{item.formattedDate}</DateWrapper>
100
+ <StyledSafeLink to={item.url}>{item.name}</StyledSafeLink>
101
+ </ContentLinkWrapper>
102
+ </LeftWrapper>
103
+ </StyledListItem>
37
104
  ))}
38
- </ul>
105
+ </StyledUl>
39
106
  </nav>
40
- </section>
107
+ </StyledSection>
41
108
  );
42
109
 
43
- SubjectNewContent.propTypes = {
44
- heading: PropTypes.string.isRequired,
45
- content: PropTypes.arrayOf(
46
- PropTypes.shape({
47
- name: PropTypes.string.isRequired,
48
- url: PropTypes.string.isRequired,
49
- formattedDate: PropTypes.string.isRequired,
50
- contentType: PropTypes.string.isRequired,
51
- }),
52
- ).isRequired,
53
- };
54
-
55
110
  export default SubjectNewContent;