@ndla/ui 52.0.0 → 53.0.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.
Files changed (202) hide show
  1. package/es/Article/Article.js +110 -117
  2. package/es/Article/ArticleHeaderWrapper.js +14 -9
  3. package/es/Embed/ImageEmbed.js +10 -4
  4. package/es/all.css +1 -1
  5. package/es/index.js +0 -1
  6. package/es/locale/messages-en.js +5 -0
  7. package/es/locale/messages-nb.js +5 -0
  8. package/es/locale/messages-nn.js +5 -0
  9. package/es/locale/messages-se.js +5 -0
  10. package/es/locale/messages-sma.js +5 -0
  11. package/lib/Article/Article.d.ts +4 -5
  12. package/lib/Article/Article.js +109 -116
  13. package/lib/Article/ArticleByline.js +1 -1
  14. package/lib/Article/ArticleFootNotes.js +1 -1
  15. package/lib/Article/ArticleHeaderWrapper.js +15 -10
  16. package/lib/Article/ArticleParagraph.js +1 -1
  17. package/lib/Article/index.d.ts +1 -0
  18. package/lib/Article/index.js +1 -1
  19. package/lib/AudioPlayer/AudioPlayer.js +1 -1
  20. package/lib/AudioPlayer/Controls.js +1 -1
  21. package/lib/AudioPlayer/index.js +1 -1
  22. package/lib/BlogPost/BlogPost.js +1 -1
  23. package/lib/BlogPost/index.js +1 -1
  24. package/lib/Breadcrumb/Breadcrumb.js +1 -1
  25. package/lib/Breadcrumb/BreadcrumbItem.js +1 -1
  26. package/lib/Breadcrumb/HomeBreadcrumb.js +1 -1
  27. package/lib/Breadcrumb/index.js +1 -1
  28. package/lib/CampaignBlock/CampaignBlock.js +1 -1
  29. package/lib/CampaignBlock/index.js +1 -1
  30. package/lib/CodeBlock/CodeBlock.js +1 -1
  31. package/lib/CodeBlock/index.js +1 -1
  32. package/lib/ContactBlock/ContactBlock.js +1 -1
  33. package/lib/ContactBlock/index.js +1 -1
  34. package/lib/ContentPlaceholder/ContentPlaceholder.js +1 -1
  35. package/lib/ContentPlaceholder/index.js +1 -1
  36. package/lib/ContentTypeBadge/ContentTypeBadge.js +1 -1
  37. package/lib/CopyParagraphButton/CopyParagraphButton.js +1 -1
  38. package/lib/CopyParagraphButton/index.js +1 -1
  39. package/lib/CreatedBy/CreatedBy.js +1 -1
  40. package/lib/CreatedBy/index.js +1 -1
  41. package/lib/DefinitionList/DefinitionDescription.js +1 -1
  42. package/lib/DefinitionList/DefinitionTerm.js +1 -1
  43. package/lib/DefinitionList/index.js +1 -1
  44. package/lib/Embed/AudioEmbed.js +1 -1
  45. package/lib/Embed/BrightcoveEmbed.js +1 -1
  46. package/lib/Embed/ConceptEmbed.js +1 -1
  47. package/lib/Embed/ConceptListEmbed.js +1 -1
  48. package/lib/Embed/ContentLinkEmbed.js +1 -1
  49. package/lib/Embed/CopyrightEmbed.js +1 -1
  50. package/lib/Embed/EmbedErrorPlaceholder.js +1 -1
  51. package/lib/Embed/ExternalEmbed.js +1 -1
  52. package/lib/Embed/FootnoteEmbed.js +1 -1
  53. package/lib/Embed/H5pEmbed.js +1 -1
  54. package/lib/Embed/IframeEmbed.js +1 -1
  55. package/lib/Embed/ImageEmbed.js +11 -5
  56. package/lib/Embed/UnknownEmbed.js +1 -1
  57. package/lib/Embed/UuDisclaimerEmbed.js +1 -1
  58. package/lib/Embed/conceptComponents.js +1 -1
  59. package/lib/Embed/index.js +1 -1
  60. package/lib/ErrorMessage/ErrorMessage.js +1 -1
  61. package/lib/ErrorMessage/ErrorResourceAccessDenied.js +1 -1
  62. package/lib/ErrorMessage/index.js +1 -1
  63. package/lib/FactBox/FactBox.js +1 -1
  64. package/lib/FactBox/index.js +1 -1
  65. package/lib/Figure/Figure.js +1 -1
  66. package/lib/Figure/index.js +1 -1
  67. package/lib/FileList/File.js +1 -1
  68. package/lib/FileList/FileList.js +1 -1
  69. package/lib/FileList/Format.js +1 -1
  70. package/lib/FileList/index.js +1 -1
  71. package/lib/Footer/FooterBlock.js +1 -1
  72. package/lib/FramedContent/FramedContent.js +1 -1
  73. package/lib/FramedContent/index.js +1 -1
  74. package/lib/FrontpageArticle/FrontpageArticle.js +1 -1
  75. package/lib/Gloss/Gloss.js +1 -1
  76. package/lib/Gloss/GlossExample.js +1 -1
  77. package/lib/Gloss/index.js +1 -1
  78. package/lib/Grid/Grid.js +1 -1
  79. package/lib/Hero/Hero.js +1 -1
  80. package/lib/Hero/HeroContent.js +1 -1
  81. package/lib/Image/Image.js +1 -1
  82. package/lib/Image/ImageLink.js +1 -1
  83. package/lib/KeyFigure/KeyFigure.js +1 -1
  84. package/lib/KeyFigure/index.js +1 -1
  85. package/lib/LanguageSelector/LanguageSelector.js +1 -1
  86. package/lib/LanguageSelector/index.js +1 -1
  87. package/lib/Layout/OneColumn.js +1 -1
  88. package/lib/Layout/PageContainer.js +1 -1
  89. package/lib/Layout/index.js +1 -1
  90. package/lib/LetterFilter/LetterFilter.js +1 -1
  91. package/lib/LetterFilter/index.js +1 -1
  92. package/lib/LicenseByline/EmbedByline.js +1 -1
  93. package/lib/LicenseByline/LicenseDescription.js +1 -1
  94. package/lib/LicenseByline/LicenseLink.js +1 -1
  95. package/lib/LicenseByline/index.js +1 -1
  96. package/lib/LinkBlock/LinkBlock.js +1 -1
  97. package/lib/LinkBlock/LinkBlockSection.js +1 -1
  98. package/lib/LinkBlock/index.js +1 -1
  99. package/lib/List/OrderedList.js +1 -1
  100. package/lib/List/UnOrderedList.js +1 -1
  101. package/lib/List/index.js +1 -1
  102. package/lib/Logo/Logo.js +1 -1
  103. package/lib/Logo/SvgLogo.js +1 -1
  104. package/lib/Logo/index.js +1 -1
  105. package/lib/MediaList/MediaList.js +1 -1
  106. package/lib/Messages/MessageBanner.js +1 -1
  107. package/lib/Messages/MessageBox.js +1 -1
  108. package/lib/Messages/index.js +1 -1
  109. package/lib/MyNdla/Resource/Folder.js +1 -1
  110. package/lib/MyNdla/Resource/index.js +1 -1
  111. package/lib/MyNdla/index.js +1 -1
  112. package/lib/Notion/Notion.js +1 -1
  113. package/lib/Notion/NotionImage.js +1 -1
  114. package/lib/Notion/index.js +1 -1
  115. package/lib/ProgrammeCard/ProgrammeCard.js +1 -1
  116. package/lib/ProgrammeCard/index.js +1 -1
  117. package/lib/RelatedArticleList/RelatedArticleList.js +1 -1
  118. package/lib/Resource/BlockResource.js +1 -1
  119. package/lib/Resource/ListResource.js +1 -1
  120. package/lib/Resource/index.js +1 -1
  121. package/lib/Resource/resourceComponents.js +1 -1
  122. package/lib/ResourceBox/ResourceBox.js +1 -1
  123. package/lib/ResourceBox/index.js +1 -1
  124. package/lib/Search/ActiveFilterContent.js +1 -1
  125. package/lib/Search/ActiveFilters.js +1 -1
  126. package/lib/Search/ContentTypeResult.js +1 -1
  127. package/lib/Search/ContentTypeResultStyles.js +1 -1
  128. package/lib/Search/LoadingWrapper.js +1 -1
  129. package/lib/Search/SearchField.js +1 -1
  130. package/lib/Search/SearchFieldForm.js +1 -1
  131. package/lib/Search/SearchResult.js +1 -1
  132. package/lib/Search/SearchResultSleeve.js +1 -1
  133. package/lib/Search/index.js +1 -1
  134. package/lib/SnackBar/DefaultSnackbar.js +1 -1
  135. package/lib/SnackBar/SnackbarProvider.js +1 -1
  136. package/lib/SnackBar/index.js +1 -1
  137. package/lib/Table/Table.js +1 -1
  138. package/lib/TagSelector/Control.js +1 -1
  139. package/lib/TagSelector/DropdownIndicator.js +1 -1
  140. package/lib/TagSelector/MenuList.js +1 -1
  141. package/lib/TagSelector/Option.js +1 -1
  142. package/lib/TagSelector/SelectContainer.js +1 -1
  143. package/lib/TagSelector/TagSelector.js +1 -1
  144. package/lib/TagSelector/ValueButton.js +1 -1
  145. package/lib/TagSelector/index.js +1 -1
  146. package/lib/TreeStructure/AddFolderButton.js +1 -1
  147. package/lib/TreeStructure/ComboboxButton.js +1 -1
  148. package/lib/TreeStructure/FolderItem.js +1 -1
  149. package/lib/TreeStructure/FolderItems.js +1 -1
  150. package/lib/TreeStructure/TreeStructure.js +1 -1
  151. package/lib/TreeStructure/index.js +1 -1
  152. package/lib/all.css +1 -1
  153. package/lib/i18n/i18n.js +1 -1
  154. package/lib/index.d.ts +1 -1
  155. package/lib/index.js +1 -26
  156. package/lib/locale/messages-en.d.ts +5 -0
  157. package/lib/locale/messages-en.js +6 -1
  158. package/lib/locale/messages-nb.d.ts +5 -0
  159. package/lib/locale/messages-nb.js +6 -1
  160. package/lib/locale/messages-nn.d.ts +5 -0
  161. package/lib/locale/messages-nn.js +6 -1
  162. package/lib/locale/messages-se.d.ts +5 -0
  163. package/lib/locale/messages-se.js +6 -1
  164. package/lib/locale/messages-sma.d.ts +5 -0
  165. package/lib/locale/messages-sma.js +6 -1
  166. package/lib/utils/resourceTypeColor.js +1 -1
  167. package/package.json +6 -7
  168. package/src/Article/Article.tsx +177 -113
  169. package/src/Article/ArticleHeaderWrapper.tsx +16 -9
  170. package/src/Article/index.ts +2 -0
  171. package/src/CodeBlock/CodeBlock.stories.tsx +1 -3
  172. package/src/Embed/ImageEmbed.tsx +5 -1
  173. package/src/LicenseByline/EmbedByline.stories.tsx +2 -2
  174. package/src/all.scss +2 -3
  175. package/src/index.ts +2 -2
  176. package/src/locale/messages-en.ts +5 -0
  177. package/src/locale/messages-nb.ts +5 -0
  178. package/src/locale/messages-nn.ts +5 -0
  179. package/src/locale/messages-se.ts +5 -0
  180. package/src/locale/messages-sma.ts +5 -0
  181. package/es/Article/ArticleNotions.js +0 -90
  182. package/es/Masthead/Masthead.js +0 -62
  183. package/es/Masthead/SkipToMainContent.js +0 -30
  184. package/es/Masthead/index.js +0 -13
  185. package/es/Masthead/utils.js +0 -38
  186. package/lib/Article/ArticleNotions.d.ts +0 -14
  187. package/lib/Article/ArticleNotions.js +0 -96
  188. package/lib/Masthead/Masthead.d.ts +0 -23
  189. package/lib/Masthead/Masthead.js +0 -68
  190. package/lib/Masthead/SkipToMainContent.d.ts +0 -12
  191. package/lib/Masthead/SkipToMainContent.js +0 -37
  192. package/lib/Masthead/index.d.ts +0 -12
  193. package/lib/Masthead/index.js +0 -36
  194. package/lib/Masthead/utils.d.ts +0 -11
  195. package/lib/Masthead/utils.js +0 -46
  196. package/src/Article/ArticleNotions.tsx +0 -139
  197. package/src/Article/component.article.scss +0 -149
  198. package/src/Masthead/Masthead.tsx +0 -100
  199. package/src/Masthead/SkipToMainContent.tsx +0 -54
  200. package/src/Masthead/index.ts +0 -16
  201. package/src/Masthead/utils.ts +0 -45
  202. package/src/main.scss +0 -4
@@ -6,37 +6,139 @@
6
6
  *
7
7
  */
8
8
 
9
- import { ReactNode, useEffect, useRef, useState, forwardRef, ComponentPropsWithRef } from "react";
10
- import BEMHelper from "react-bem-helper";
9
+ import { ReactNode, forwardRef, ComponentPropsWithRef, useMemo, CSSProperties } from "react";
10
+ import { SerializedStyles, css } from "@emotion/react";
11
11
  import styled from "@emotion/styled";
12
12
 
13
- import { spacing, mq, breakpoints } from "@ndla/core";
14
- import { useIntersectionObserver } from "@ndla/hooks";
13
+ import { spacing, mq, breakpoints, fonts, colors, spacingUnit } from "@ndla/core";
15
14
  import { Heading, Text } from "@ndla/typography";
16
- import { resizeObserver } from "@ndla/util";
17
15
  import ArticleByline from "./ArticleByline";
18
16
  import ArticleHeaderWrapper from "./ArticleHeaderWrapper";
19
- import ArticleNotions from "./ArticleNotions";
20
17
  import LayoutItem from "../Layout";
21
18
  import MessageBox from "../Messages/MessageBox";
22
19
  import { Article as ArticleType } from "../types";
23
20
 
24
- const classes = new BEMHelper({
25
- name: "article",
26
- prefix: "c-",
27
- });
21
+ export type ArticleModifier =
22
+ | "clean"
23
+ | "in-topic"
24
+ | "subject-material"
25
+ | "assessment-resources"
26
+ | "tasks-and-activities"
27
+ | "concept"
28
+ | "source-material";
28
29
 
29
30
  interface ArticleWrapperProps extends ComponentPropsWithRef<"article"> {
30
- modifier?: string;
31
+ modifier?: ArticleModifier;
31
32
  }
32
33
 
33
- export const ArticleWrapper = forwardRef<HTMLElement, ArticleWrapperProps>(
34
- ({ children, modifier, className, ...rest }, ref) => (
35
- <article {...rest} {...classes(undefined, modifier, className)} ref={ref}>
34
+ const StyledArticle = styled.article`
35
+ font-family: ${fonts.serif};
36
+ background: ${colors.white};
37
+ margin-top: ${spacing.large};
38
+ margin-right: auto;
39
+ margin-bottom: ${spacing.normal};
40
+ margin-left: auto;
41
+ overflow-wrap: break-word;
42
+ ${fonts.sizes("18px", "29px")};
43
+ position: relative;
44
+
45
+ mjx-stretchy-v > mjx-ext > mjx-c {
46
+ transform: scaleY(100) translateY(0.075em);
47
+ }
48
+
49
+ > section > p {
50
+ &:not([class]) {
51
+ margin-bottom: 29px;
52
+ }
53
+ }
54
+
55
+ ${mq.range({ from: breakpoints.tablet })} {
56
+ ${fonts.sizes("18px", "29px")}; //This is probably not needed, but it's here to be sure.
57
+
58
+ > section > p {
59
+ &:not([class]) {
60
+ margin-bottom: 35px;
61
+ }
62
+ }
63
+ padding: 0 ${spacing.normal} ${spacing.normal};
64
+ margin-bottom: ${spacing.large};
65
+ margin-top: -${spacingUnit * 6}px;
66
+ padding-top: ${spacing.xlarge};
67
+ }
68
+ ${mq.range({ from: breakpoints.desktop })} {
69
+ padding-bottom: ${spacing.large};
70
+ margin-bottom: ${spacing.large};
71
+ }
72
+
73
+ &::after {
74
+ content: "";
75
+ display: table;
76
+ clear: both;
77
+ }
78
+
79
+ p {
80
+ margin-top: 0;
81
+ }
82
+ `;
83
+
84
+ // Make sure to wrap modifiers in & {} to avoid specificity issues
85
+ const articleModifiers: Partial<Record<ArticleModifier, SerializedStyles>> = {
86
+ clean: css`
87
+ & {
88
+ margin-top: ${spacing.normal} !important;
89
+ padding: ${spacing.small} !important;
90
+ ${mq.range({ from: breakpoints.tablet })} {
91
+ padding: 0 !important;
92
+ }
93
+ border: none;
94
+ }
95
+ `,
96
+ "in-topic": css`
97
+ & {
98
+ margin-top: 0 !important;
99
+ padding: 0 !important;
100
+ padding-left: ${spacing.medium} !important;
101
+ }
102
+ `,
103
+ };
104
+
105
+ const borderCss = css`
106
+ ${mq.range({ from: breakpoints.tablet })} {
107
+ border: 2px solid var(--color);
108
+ }
109
+ `;
110
+
111
+ export const ArticleWrapper = forwardRef<HTMLElement, ArticleWrapperProps>(({ children, modifier, ...rest }, ref) => {
112
+ const borderColor = useMemo(() => {
113
+ let color = undefined;
114
+ if (modifier === "subject-material") {
115
+ color = colors.subjectMaterial.light;
116
+ } else if (modifier === "assessment-resources") {
117
+ color = colors.assessmentResource.background;
118
+ } else if (modifier === "tasks-and-activities") {
119
+ color = colors.tasksAndActivities.background;
120
+ } else if (modifier === "concept") {
121
+ color = colors.concept.light;
122
+ } else if (modifier === "source-material") {
123
+ color = colors.sourceMaterial.light;
124
+ }
125
+ if (color) {
126
+ return { "--color": color } as CSSProperties;
127
+ }
128
+ return undefined;
129
+ }, [modifier]);
130
+
131
+ return (
132
+ <StyledArticle
133
+ css={[borderColor ? borderCss : undefined, modifier ? articleModifiers[modifier] : undefined]}
134
+ style={borderColor}
135
+ {...rest}
136
+ ref={ref}
137
+ >
36
138
  {children}
37
- </article>
38
- ),
39
- );
139
+ </StyledArticle>
140
+ );
141
+ });
40
142
 
41
143
  type ArticleTitleProps = {
42
144
  icon?: ReactNode;
@@ -46,28 +148,40 @@ type ArticleTitleProps = {
46
148
  lang?: string;
47
149
  };
48
150
 
49
- export const ArticleTitle = ({ children, icon, label, id, lang }: ArticleTitleProps) => {
50
- const modifiers = [];
51
- if (icon) {
52
- modifiers.push("icon");
53
- }
54
-
55
- let labelView = null;
151
+ const TitleLabelText = styled(Text)`
152
+ color: #757575;
153
+ text-transform: uppercase;
154
+ font-family: ${fonts.sans};
155
+ `;
56
156
 
57
- if (label) {
58
- labelView = <p>{label}</p>;
157
+ const ArticleTitleWrapper = styled.div`
158
+ display: flex;
159
+ gap: ${spacing.normal};
160
+ align-items: flex-start;
161
+ h1 {
162
+ overflow-wrap: anywhere;
59
163
  }
164
+ padding-bottom: ${spacing.medium};
165
+ [data-badge] {
166
+ flex-shrink: 0;
167
+ }
168
+ `;
60
169
 
61
- return (
62
- <div {...classes("title", modifiers)}>
63
- {icon}
64
- {labelView}
65
- <Heading element="h1" headingStyle="h1-resource" id={id} tabIndex={-1} lang={lang}>
170
+ export const ArticleTitle = ({ children, icon, label, id, lang }: ArticleTitleProps) => (
171
+ <ArticleTitleWrapper>
172
+ {icon}
173
+ <hgroup>
174
+ {!!label && (
175
+ <TitleLabelText textStyle="meta-text-medium" margin="none">
176
+ {label}
177
+ </TitleLabelText>
178
+ )}
179
+ <Heading element="h1" margin="none" headingStyle="h1-resource" id={id} tabIndex={-1} lang={lang}>
66
180
  {children}
67
181
  </Heading>
68
- </div>
69
- );
70
- };
182
+ </hgroup>
183
+ </ArticleTitleWrapper>
184
+ );
71
185
 
72
186
  type ArticleIntroductionProps = {
73
187
  children: ReactNode;
@@ -107,29 +221,15 @@ type Props = {
107
221
  article: ArticleType;
108
222
  icon?: ReactNode;
109
223
  licenseBox?: ReactNode;
110
- modifier?: string;
224
+ modifier?: ArticleModifier;
111
225
  children?: ReactNode;
112
226
  messages: Messages;
113
- contentTransformed?: boolean;
114
227
  messageBoxLinks?: [];
115
228
  competenceGoals?: ReactNode;
116
229
  id: string;
117
- notions?: ReactNode;
118
230
  lang?: string;
119
231
  };
120
232
 
121
- const getArticleContent = (content: any, contentTransformed?: boolean) => {
122
- if (contentTransformed) {
123
- return content;
124
- }
125
- switch (typeof content) {
126
- case "function":
127
- return content();
128
- default:
129
- return content;
130
- }
131
- };
132
-
133
233
  export const Article = ({
134
234
  article,
135
235
  icon,
@@ -140,79 +240,43 @@ export const Article = ({
140
240
  children,
141
241
  competenceGoals,
142
242
  id,
143
- notions,
144
243
  heartButton,
145
- contentTransformed,
146
244
  lang,
147
245
  }: Props) => {
148
- const articleRef = useRef<HTMLDivElement>(null);
149
- const wrapperRef = useRef<HTMLDivElement>(null);
150
- const { entry } = useIntersectionObserver({
151
- rootMargin: "400px",
152
- target: articleRef.current,
153
- threshold: 0.1,
154
- });
155
- const [articlePositionRight, setArticlePositionRight] = useState(0);
156
-
157
- const showExplainNotions = !!entry?.isIntersecting;
158
-
159
- useEffect(() => {
160
- if (wrapperRef?.current) {
161
- const handler = () => {
162
- if (wrapperRef?.current) {
163
- const offset =
164
- wrapperRef.current.getBoundingClientRect().left + wrapperRef.current.getBoundingClientRect().width;
165
- setArticlePositionRight(offset);
166
- }
167
- };
168
- handler();
169
-
170
- return resizeObserver(document.body, handler);
171
- }
172
- }, [wrapperRef]);
173
-
174
246
  const { title, introduction, published, content, footNotes, copyright } = article;
175
247
 
176
248
  const authors =
177
249
  copyright?.creators.length || copyright?.rightsholders.length ? copyright.creators : copyright?.processors;
178
250
 
179
251
  return (
180
- <div ref={wrapperRef}>
181
- <ArticleWrapper modifier={modifier} ref={articleRef} data-ndla-article="">
182
- <LayoutItem layout="center">
183
- {messages.messageBox && (
184
- <MSGboxWrapper>
185
- <MessageBox links={messageBoxLinks}>{messages.messageBox}</MessageBox>
186
- </MSGboxWrapper>
187
- )}
188
- <ArticleHeaderWrapper competenceGoals={competenceGoals}>
189
- {heartButton ? <ArticleFavoritesButtonWrapper>{heartButton}</ArticleFavoritesButtonWrapper> : null}
190
- <ArticleTitle id={id} icon={icon} label={messages.label} lang={lang}>
191
- {title}
192
- </ArticleTitle>
193
- <ArticleIntroduction lang={lang}>{introduction}</ArticleIntroduction>
194
- </ArticleHeaderWrapper>
195
- </LayoutItem>
196
- <LayoutItem layout="center">
197
- {notions && showExplainNotions && (
198
- <ArticleNotions buttonOffsetRight={articlePositionRight}>{notions}</ArticleNotions>
199
- )}
200
- {getArticleContent(content, contentTransformed)}
201
- </LayoutItem>
202
-
203
- <LayoutItem layout="center">
204
- <ArticleByline
205
- footnotes={footNotes}
206
- authors={authors}
207
- suppliers={copyright?.rightsholders}
208
- published={published}
209
- license={copyright?.license?.license ?? ""}
210
- licenseBox={licenseBox}
211
- />
212
- </LayoutItem>
213
- <LayoutItem layout="extend">{children}</LayoutItem>
214
- </ArticleWrapper>
215
- </div>
252
+ <ArticleWrapper modifier={modifier} data-ndla-article="">
253
+ <LayoutItem layout="center">
254
+ {messages.messageBox && (
255
+ <MSGboxWrapper>
256
+ <MessageBox links={messageBoxLinks}>{messages.messageBox}</MessageBox>
257
+ </MSGboxWrapper>
258
+ )}
259
+ <ArticleHeaderWrapper competenceGoals={competenceGoals}>
260
+ {heartButton ? <ArticleFavoritesButtonWrapper>{heartButton}</ArticleFavoritesButtonWrapper> : null}
261
+ <ArticleTitle id={id} icon={icon} label={messages.label} lang={lang}>
262
+ {title}
263
+ </ArticleTitle>
264
+ <ArticleIntroduction lang={lang}>{introduction}</ArticleIntroduction>
265
+ </ArticleHeaderWrapper>
266
+ </LayoutItem>
267
+ <LayoutItem layout="center">{content}</LayoutItem>
268
+ <LayoutItem layout="center">
269
+ <ArticleByline
270
+ footnotes={footNotes}
271
+ authors={authors}
272
+ suppliers={copyright?.rightsholders}
273
+ published={published}
274
+ license={copyright?.license?.license ?? ""}
275
+ licenseBox={licenseBox}
276
+ />
277
+ </LayoutItem>
278
+ <LayoutItem layout="extend">{children}</LayoutItem>
279
+ </ArticleWrapper>
216
280
  );
217
281
  };
218
282
 
@@ -7,24 +7,31 @@
7
7
  */
8
8
 
9
9
  import { ReactNode } from "react";
10
- import BEMHelper from "react-bem-helper";
11
-
12
- const classes = new BEMHelper({
13
- name: "article",
14
- prefix: "c-",
15
- });
10
+ import styled from "@emotion/styled";
11
+ import { breakpoints, mq, spacing } from "@ndla/core";
16
12
 
17
13
  type Props = {
18
14
  competenceGoals?: ReactNode;
19
15
  children: ReactNode;
20
16
  };
21
17
 
18
+ const StyledHeaderWrapper = styled.div`
19
+ margin-bottom: ${spacing.normal};
20
+ ${mq.range({ from: breakpoints.tablet })} {
21
+ margin-bottom: ${spacing.large};
22
+ }
23
+ `;
24
+
25
+ const CompetenceWrapper = styled.div`
26
+ margin-top: ${spacing.normal};
27
+ `;
28
+
22
29
  const ArticleHeaderWrapper = ({ children, competenceGoals }: Props) => {
23
30
  return (
24
- <div {...classes("header")}>
31
+ <StyledHeaderWrapper>
25
32
  {children}
26
- <div {...classes("competence")}>{competenceGoals}</div>
27
- </div>
33
+ <CompetenceWrapper>{competenceGoals}</CompetenceWrapper>
34
+ </StyledHeaderWrapper>
28
35
  );
29
36
  };
30
37
 
@@ -14,4 +14,6 @@ import ArticleHeaderWrapper from "./ArticleHeaderWrapper";
14
14
  export { ArticleByline, ArticleFootNotes, ArticleHeaderWrapper, ArticleTitle, ArticleIntroduction, ArticleWrapper };
15
15
  export { ArticleParagraph } from "./ArticleParagraph";
16
16
 
17
+ export type { ArticleModifier } from "./Article";
18
+
17
19
  export default Article;
@@ -61,13 +61,11 @@ export default {
61
61
  argTypes: {
62
62
  actionButton: {
63
63
  table: {
64
+ disable: true,
64
65
  type: {
65
66
  detail: "Takes any ReactNode, but as the name implies: use a button component, preferably an icon-button",
66
67
  },
67
68
  },
68
- control: {
69
- type: null,
70
- },
71
69
  },
72
70
  },
73
71
  } as Meta<typeof CodeBlock>;
@@ -161,6 +161,10 @@ const ImageEmbed = ({
161
161
 
162
162
  const { data, embedData } = embed;
163
163
 
164
+ // Full-size figures automatically get a margin of {spacing.normal} on its y-axis if a float is not set (or if float is an empty string).
165
+ // This adds some margin to normal figures within an article, but should not happen for figures in a grid.
166
+ const floatAttr = inGrid && !embedData.align ? {} : { "data-float": embedData.align };
167
+
164
168
  const altText = embedData.alt || "";
165
169
 
166
170
  const figureType = getFigureType(embedData.size, embedData.align);
@@ -172,7 +176,7 @@ const ImageEmbed = ({
172
176
  const isCopyrighted = data.copyright.license.license.toLowerCase() === COPYRIGHTED;
173
177
 
174
178
  return (
175
- <StyledFigure type={imageSizes ? undefined : figureType} data-float={embedData.align}>
179
+ <StyledFigure type={imageSizes ? undefined : figureType} {...floatAttr}>
176
180
  {children}
177
181
  <ImageWrapper
178
182
  src={!isCopyrighted ? canonicalUrl?.(data) : undefined}
@@ -63,8 +63,8 @@ export default {
63
63
  },
64
64
  argTypes: {
65
65
  children: {
66
- control: {
67
- type: null,
66
+ table: {
67
+ disable: true,
68
68
  },
69
69
  },
70
70
  },
package/src/all.scss CHANGED
@@ -1,3 +1,2 @@
1
- @import '~@ndla/core/scss/core';
2
- @import './main';
3
- @import '~@ndla/core/scss/utilities';
1
+ @import "~@ndla/core/scss/core";
2
+ @import "~@ndla/core/scss/utilities";
package/src/index.ts CHANGED
@@ -47,12 +47,12 @@ export {
47
47
  ArticleParagraph,
48
48
  } from "./Article";
49
49
 
50
+ export type { ArticleModifier } from "./Article";
51
+
50
52
  export { getPossiblyRelativeUrl } from "./utils/relativeUrl";
51
53
 
52
54
  export { default as Table, TableStyling } from "./Table";
53
55
 
54
- export { default as Masthead, getMastheadHeight, useMastheadHeight, SkipToMainContent } from "./Masthead";
55
-
56
56
  export { default as ContentLoader } from "./ContentLoader";
57
57
 
58
58
  export { default as RelatedArticleList, RelatedArticle } from "./RelatedArticleList";
@@ -544,8 +544,10 @@ const messages = {
544
544
  },
545
545
  contentTypes: {
546
546
  all: "All",
547
+ article: "Article",
547
548
  subject: "Subject",
548
549
  "topic-article": "Topic article",
550
+ learningpath: "Learning path",
549
551
  "learning-path": "Learning path",
550
552
  "subject-material": "Subject material",
551
553
  "tasks-and-activities": "Task and activities",
@@ -933,6 +935,7 @@ const messages = {
933
935
  onDragEndMissingOver: "The folder {{name}} was dropped",
934
936
  onDragCancel: "Dragging was cancelled. The folder {{name}} was dropped",
935
937
  dragHandle: "Drag the folder {{name}}",
938
+ professional: "a professional",
936
939
  sharedWarning: "Name and description will be visible for everyone you share the folder with",
937
940
  sharing: {
938
941
  share: "Share folder",
@@ -941,6 +944,7 @@ const messages = {
941
944
  unShare: "Sharing stopped. The folder is no longer shared",
942
945
  copyLink: "Copy link to folder",
943
946
  link: "Link is copied",
947
+ savedLink: "Link to {{ name }} has been added to My folders.",
944
948
  header: {
945
949
  shared: "This folder is shared",
946
950
  },
@@ -1187,6 +1191,7 @@ const messages = {
1187
1191
  copyFolderDisclaimer:
1188
1192
  "This creates a copy of the folder. Any changes made to the original folder will not be updated here.",
1189
1193
  loginCopyFolderPitch: "Do you wish to copy this folder?",
1194
+ loginSaveFolderLinkPitch: "Do you wish to save the link to this shared folder?",
1190
1195
  help: "Help",
1191
1196
  more: "More options",
1192
1197
  selectView: "Select view",
@@ -544,8 +544,10 @@ const messages = {
544
544
  },
545
545
  contentTypes: {
546
546
  all: "Alle",
547
+ article: "Artikkel",
547
548
  subject: "Fag",
548
549
  "topic-article": "Emne",
550
+ learningpath: "Læringssti",
549
551
  "learning-path": "Læringssti",
550
552
  "subject-material": "Fagstoff",
551
553
  "tasks-and-activities": "Oppgaver og aktiviteter",
@@ -933,6 +935,7 @@ const messages = {
933
935
  onDragEndMissingOver: "Mappen {{name}} ble sluppet",
934
936
  onDragCancel: "Flytting avbrutt. Mappen {{name}} ble sluppet",
935
937
  dragHandle: "Sorter mappen {{name}}",
938
+ professional: "en fagperson",
936
939
  sharedWarning: "Navn og beskrivelse blir synlig for alle du deler mappen med.",
937
940
  sharing: {
938
941
  share: "Del mappe",
@@ -941,6 +944,7 @@ const messages = {
941
944
  unShare: "Delingen er avsluttet. Mappen er ikke lenger delt.",
942
945
  copyLink: "Kopier lenke til mappa",
943
946
  link: "Lenken er kopiert",
947
+ savedLink: "Lenke til {{ name }} er lagt til i Mine mapper.",
944
948
  header: {
945
949
  shared: "Denne mappa er delt",
946
950
  },
@@ -1187,6 +1191,7 @@ const messages = {
1187
1191
  copyFolderDisclaimer:
1188
1192
  "Dette lager en kopi av mappen. Eventuelle endringer i originalmappen vil ikke bli oppdatert her.",
1189
1193
  loginCopyFolderPitch: "Ønsker du å kopiere denne mappen?",
1194
+ loginSaveFolderLinkPitch: "Ønsker du å lagre lenken til denne delte mappen?",
1190
1195
  help: "Hjelp",
1191
1196
  more: "Flere valg",
1192
1197
  selectView: "Velg visning",
@@ -544,8 +544,10 @@ const messages = {
544
544
  },
545
545
  contentTypes: {
546
546
  all: "Alle",
547
+ article: "Artikkel",
547
548
  subject: "Fag",
548
549
  "topic-article": "Emne",
550
+ learningpath: "Læringssti",
549
551
  "learning-path": "Læringssti",
550
552
  "subject-material": "Fagstoff",
551
553
  "tasks-and-activities": "Oppgåver og aktivitetar",
@@ -933,6 +935,7 @@ const messages = {
933
935
  onDragEndMissingOver: "Mappa blei sleppt",
934
936
  onDragCancel: "Flytting avbrutt. Mappa {{name}} blei sleppt",
935
937
  dragHandle: "Sorter mappa {{name}}",
938
+ professional: "ein fagperson",
936
939
  sharedWarning: "Namn og beskriving blir synleg for alle du deler mappa med.",
937
940
  sharing: {
938
941
  share: "Del mappe",
@@ -940,6 +943,7 @@ const messages = {
940
943
  sharedFolder: "Delt mappe",
941
944
  unShare: "Delinga er avslutta. Mappa er ikkje lenger delt",
942
945
  link: "Lenka er kopiert",
946
+ savedLink: "Lenka til {{ name }} er lagt til i Mine mapper.",
943
947
  copyLink: "Kopier lenke til mappa",
944
948
  header: {
945
949
  shared: "Denne mappa er delt",
@@ -1187,6 +1191,7 @@ const messages = {
1187
1191
  copyFolderDisclaimer:
1188
1192
  "Dette lagar ein kopi av mappa. Eventuelle endringar i originalmappa vil ikkje bli oppdatert her.",
1189
1193
  loginCopyFolderPitch: "Ønsker du å kopiere denne mappa?",
1194
+ loginSaveFolderLinkPitch: "Ønsker du å lagra lenka til denne delte mappa?",
1190
1195
  help: "Hjelp",
1191
1196
  more: "Fleire val",
1192
1197
  selectView: "Velg visning",
@@ -546,8 +546,10 @@ const messages = {
546
546
  },
547
547
  contentTypes: {
548
548
  all: "Buot",
549
+ article: "Artikkel",
549
550
  subject: "Fága",
550
551
  "topic-article": "Fáddá",
552
+ learningpath: "Oahppanbálggis",
551
553
  "learning-path": "Oahppanbálggis",
552
554
  "subject-material": "Fágaávdnasat",
553
555
  "tasks-and-activities": "Bihtát ja doaimmat",
@@ -935,6 +937,7 @@ const messages = {
935
937
  onDragEndMissingOver: "Mappen {{name}} ble sluppet",
936
938
  onDragCancel: "Flytting avbrutt. Mappen {{name}} ble sluppet",
937
939
  dragHandle: "Sorter mappen {{name}}",
940
+ professional: "en fagperson",
938
941
  sharedWarning: "Navn og beskrivelse blir synlig for alle du deler mappen med.",
939
942
  sharing: {
940
943
  share: "Del mappe",
@@ -943,6 +946,7 @@ const messages = {
943
946
  unShare: "Delingen er avsluttet. Mappen er ikke lenger delt.",
944
947
  copyLink: "Kopier lenke til mappa",
945
948
  link: "Lenken er kopiert",
949
+ savedLink: "Lenke til {{ name }} er lagt til i Mine mapper.",
946
950
  header: {
947
951
  shared: "Denne mappa er delt",
948
952
  },
@@ -1189,6 +1193,7 @@ const messages = {
1189
1193
  copyFolderDisclaimer:
1190
1194
  "Dette lager en kopi av mappen. Eventuelle endringer i originalmappen vil ikke bli oppdatert her.",
1191
1195
  loginCopyFolderPitch: "Ønsker du å kopiere denne mappen?",
1196
+ loginSaveFolderLinkPitch: "Ønsker du å lagre lenken til denne delte mappen?",
1192
1197
  help: "Hjelp",
1193
1198
  more: "Flere valg",
1194
1199
  selectView: "Velg visning",
@@ -548,8 +548,10 @@ const messages = {
548
548
  },
549
549
  contentTypes: {
550
550
  all: "Alle",
551
+ article: "Artikkel",
551
552
  subject: "Faagem",
552
553
  "topic-article": "Teema",
554
+ learningpath: "Lïeremebaalka",
553
555
  "learning-path": "Lïeremebaalka",
554
556
  "subject-material": "Faage-aamhtese",
555
557
  "tasks-and-activities": "Laavenjassh jïh darjomh",
@@ -937,6 +939,7 @@ const messages = {
937
939
  onDragEndMissingOver: "Mappen {{name}} ble sluppet",
938
940
  onDragCancel: "Flytting avbrutt. Mappen {{name}} ble sluppet",
939
941
  dragHandle: "Sorter mappen {{name}}",
942
+ professional: "en fagperson",
940
943
  sharedWarning: "Navn og beskrivelse blir synlig for alle du deler mappen med.",
941
944
  sharing: {
942
945
  share: "Del mappe",
@@ -945,6 +948,7 @@ const messages = {
945
948
  unShare: "Delingen er avsluttet. Mappen er ikke lenger delt.",
946
949
  copyLink: "Kopier lenke til mappa",
947
950
  link: "Lenken er kopiert",
951
+ savedLink: "Lenke til {{ name }} er lagt til i Mine mapper.",
948
952
  header: {
949
953
  shared: "Denne mappa er delt",
950
954
  },
@@ -1191,6 +1195,7 @@ const messages = {
1191
1195
  copyFolderDisclaimer:
1192
1196
  "Dette lager en kopi av mappen. Eventuelle endringer i originalmappen vil ikke bli oppdatert her.",
1193
1197
  loginCopyFolderPitch: "Ønsker du å kopiere denne mappen?",
1198
+ loginSaveFolderLinkPitch: "Ønsker du å lagre lenken til denne delte mappen?",
1194
1199
  help: "Hjelp",
1195
1200
  more: "Flere valg",
1196
1201
  selectView: "Velg visning",