@ndla/ui 48.0.0 → 49.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 (176) hide show
  1. package/es/BlogPost/BlogPost.js +6 -6
  2. package/es/CampaignBlock/CampaignBlock.js +8 -8
  3. package/es/ContactBlock/ContactBlock.js +29 -20
  4. package/es/CopyParagraphButton/CopyParagraphButton.js +30 -58
  5. package/es/CopyParagraphButton/index.js +1 -3
  6. package/es/Embed/BrightcoveEmbed.js +8 -6
  7. package/es/Embed/ImageEmbed.js +7 -5
  8. package/es/Embed/RelatedContentEmbed.js +3 -3
  9. package/es/FactBox/FactBox.js +64 -19
  10. package/es/FactBox/index.js +0 -1
  11. package/es/Figure/index.js +0 -2
  12. package/es/FileList/File.js +46 -24
  13. package/es/FileList/FileList.js +18 -14
  14. package/es/FileList/index.js +0 -2
  15. package/es/LinkBlock/LinkBlock.js +7 -7
  16. package/es/Messages/index.js +1 -2
  17. package/es/Navigation/index.js +1 -2
  18. package/es/RelatedArticleList/RelatedArticleList.js +80 -35
  19. package/es/RelatedArticleList/index.js +2 -3
  20. package/es/Search/index.js +0 -1
  21. package/es/all.css +1 -1
  22. package/es/i18n/i18n.js +2 -1
  23. package/es/index.js +9 -11
  24. package/es/utils/relativeUrl.js +17 -2
  25. package/lib/BlogPost/BlogPost.js +5 -5
  26. package/lib/CampaignBlock/CampaignBlock.js +7 -7
  27. package/lib/ContactBlock/ContactBlock.js +28 -19
  28. package/lib/CopyParagraphButton/CopyParagraphButton.d.ts +5 -4
  29. package/lib/CopyParagraphButton/CopyParagraphButton.js +29 -57
  30. package/lib/CopyParagraphButton/index.d.ts +1 -3
  31. package/lib/CopyParagraphButton/index.js +0 -14
  32. package/lib/Embed/BrightcoveEmbed.d.ts +3 -2
  33. package/lib/Embed/BrightcoveEmbed.js +8 -6
  34. package/lib/Embed/ImageEmbed.d.ts +3 -2
  35. package/lib/Embed/ImageEmbed.js +7 -5
  36. package/lib/Embed/RelatedContentEmbed.js +3 -3
  37. package/lib/Embed/index.d.ts +1 -1
  38. package/lib/Embed/types.d.ts +1 -0
  39. package/lib/FactBox/FactBox.d.ts +1 -4
  40. package/lib/FactBox/FactBox.js +72 -27
  41. package/lib/FactBox/index.d.ts +0 -1
  42. package/lib/FactBox/index.js +0 -7
  43. package/lib/Figure/index.d.ts +0 -2
  44. package/lib/Figure/index.js +0 -14
  45. package/lib/FileList/File.d.ts +22 -3
  46. package/lib/FileList/File.js +45 -25
  47. package/lib/FileList/FileList.d.ts +10 -14
  48. package/lib/FileList/FileList.js +17 -15
  49. package/lib/FileList/index.d.ts +0 -2
  50. package/lib/FileList/index.js +0 -14
  51. package/lib/LinkBlock/LinkBlock.js +6 -6
  52. package/lib/Messages/index.d.ts +1 -2
  53. package/lib/Messages/index.js +0 -7
  54. package/lib/Navigation/index.d.ts +1 -2
  55. package/lib/Navigation/index.js +0 -7
  56. package/lib/RelatedArticleList/RelatedArticleList.d.ts +16 -17
  57. package/lib/RelatedArticleList/RelatedArticleList.js +78 -35
  58. package/lib/RelatedArticleList/index.d.ts +2 -3
  59. package/lib/RelatedArticleList/index.js +2 -12
  60. package/lib/Search/index.d.ts +0 -1
  61. package/lib/Search/index.js +0 -7
  62. package/lib/all.css +1 -1
  63. package/lib/i18n/i18n.d.ts +1 -0
  64. package/lib/i18n/i18n.js +4 -2
  65. package/lib/index.d.ts +10 -12
  66. package/lib/index.js +9 -89
  67. package/lib/utils/relativeUrl.d.ts +1 -1
  68. package/lib/utils/relativeUrl.js +19 -4
  69. package/package.json +17 -17
  70. package/src/BlogPost/BlogPost.tsx +2 -2
  71. package/src/CampaignBlock/CampaignBlock.tsx +2 -2
  72. package/src/ContactBlock/ContactBlock.tsx +12 -6
  73. package/src/CopyParagraphButton/CopyParagraphButton.tsx +24 -46
  74. package/src/CopyParagraphButton/index.tsx +1 -3
  75. package/src/Embed/BrightcoveEmbed.tsx +6 -5
  76. package/src/Embed/ImageEmbed.tsx +14 -5
  77. package/src/Embed/RelatedContentEmbed.stories.tsx +9 -9
  78. package/src/Embed/RelatedContentEmbed.tsx +3 -3
  79. package/src/Embed/index.ts +1 -1
  80. package/src/Embed/types.ts +2 -0
  81. package/src/FactBox/FactBox.tsx +29 -16
  82. package/src/FactBox/Factbox.stories.tsx +4 -4
  83. package/src/FactBox/index.ts +0 -2
  84. package/src/Figure/index.ts +0 -2
  85. package/src/FileList/File.tsx +62 -32
  86. package/src/FileList/FileList.stories.tsx +15 -15
  87. package/src/FileList/FileList.tsx +21 -27
  88. package/src/FileList/index.ts +0 -2
  89. package/src/LinkBlock/LinkBlock.tsx +2 -2
  90. package/src/Messages/index.ts +1 -2
  91. package/src/Navigation/index.ts +1 -2
  92. package/src/RelatedArticleList/RelatedArticleList.tsx +53 -47
  93. package/src/RelatedArticleList/index.ts +2 -3
  94. package/src/Search/index.ts +0 -1
  95. package/src/i18n/i18n.ts +2 -1
  96. package/src/index.ts +11 -14
  97. package/src/main.scss +0 -1
  98. package/src/utils/__tests__/relativeUrl-test.tsx +72 -0
  99. package/src/utils/relativeUrl.ts +19 -2
  100. package/es/CopyParagraphButton/CopyParagraphButtonV2.js +0 -87
  101. package/es/CopyParagraphButton/initCopyParagraphButtons.js +0 -29
  102. package/es/FactBox/FactBoxV2.js +0 -93
  103. package/es/Figure/FigureBylineExpandButton.js +0 -29
  104. package/es/Figure/FigureExpandButton.js +0 -30
  105. package/es/FileList/FileListV2.js +0 -47
  106. package/es/FileList/FileV2.js +0 -32
  107. package/es/Masthead/MastheadSearchModal.js +0 -82
  108. package/es/Messages/MessageBoxTag.js +0 -33
  109. package/es/MultidisciplinarySubject/List.js +0 -52
  110. package/es/MultidisciplinarySubject/ListItem.js +0 -90
  111. package/es/MultidisciplinarySubject/MultidisciplinarySubject.js +0 -125
  112. package/es/MultidisciplinarySubject/index.js +0 -10
  113. package/es/Navigation/NavigationTopicAbout.js +0 -164
  114. package/es/RelatedArticleList/RelatedArticleV2.js +0 -125
  115. package/es/Search/ToggleSearchButton.js +0 -51
  116. package/es/Translation/Translation.js +0 -33
  117. package/es/Translation/TranslationLine.js +0 -47
  118. package/es/Translation/index.js +0 -2
  119. package/lib/CopyParagraphButton/CopyParagraphButtonV2.d.ts +0 -15
  120. package/lib/CopyParagraphButton/CopyParagraphButtonV2.js +0 -92
  121. package/lib/CopyParagraphButton/initCopyParagraphButtons.d.ts +0 -2
  122. package/lib/CopyParagraphButton/initCopyParagraphButtons.js +0 -38
  123. package/lib/FactBox/FactBoxV2.d.ts +0 -13
  124. package/lib/FactBox/FactBoxV2.js +0 -98
  125. package/lib/Figure/FigureBylineExpandButton.d.ts +0 -16
  126. package/lib/Figure/FigureBylineExpandButton.js +0 -35
  127. package/lib/Figure/FigureExpandButton.d.ts +0 -16
  128. package/lib/Figure/FigureExpandButton.js +0 -35
  129. package/lib/FileList/FileListV2.d.ts +0 -13
  130. package/lib/FileList/FileListV2.js +0 -52
  131. package/lib/FileList/FileV2.d.ts +0 -15
  132. package/lib/FileList/FileV2.js +0 -40
  133. package/lib/Masthead/MastheadSearchModal.d.ts +0 -8
  134. package/lib/Masthead/MastheadSearchModal.js +0 -89
  135. package/lib/Messages/MessageBoxTag.d.ts +0 -12
  136. package/lib/Messages/MessageBoxTag.js +0 -40
  137. package/lib/MultidisciplinarySubject/List.d.ts +0 -7
  138. package/lib/MultidisciplinarySubject/List.js +0 -59
  139. package/lib/MultidisciplinarySubject/ListItem.d.ts +0 -10
  140. package/lib/MultidisciplinarySubject/ListItem.js +0 -97
  141. package/lib/MultidisciplinarySubject/MultidisciplinarySubject.d.ts +0 -13
  142. package/lib/MultidisciplinarySubject/MultidisciplinarySubject.js +0 -135
  143. package/lib/MultidisciplinarySubject/index.d.ts +0 -9
  144. package/lib/MultidisciplinarySubject/index.js +0 -17
  145. package/lib/Navigation/NavigationTopicAbout.d.ts +0 -13
  146. package/lib/Navigation/NavigationTopicAbout.js +0 -171
  147. package/lib/RelatedArticleList/RelatedArticleV2.d.ts +0 -26
  148. package/lib/RelatedArticleList/RelatedArticleV2.js +0 -131
  149. package/lib/Search/ToggleSearchButton.d.ts +0 -14
  150. package/lib/Search/ToggleSearchButton.js +0 -57
  151. package/lib/Translation/Translation.d.ts +0 -14
  152. package/lib/Translation/Translation.js +0 -38
  153. package/lib/Translation/TranslationLine.d.ts +0 -16
  154. package/lib/Translation/TranslationLine.js +0 -51
  155. package/lib/Translation/index.d.ts +0 -2
  156. package/lib/Translation/index.js +0 -20
  157. package/src/CopyParagraphButton/CopyParagraphButtonV2.tsx +0 -85
  158. package/src/CopyParagraphButton/initCopyParagraphButtons.tsx +0 -27
  159. package/src/FactBox/FactBoxV2.tsx +0 -56
  160. package/src/Figure/FigureBylineExpandButton.tsx +0 -34
  161. package/src/Figure/FigureExpandButton.tsx +0 -35
  162. package/src/FileList/FileListV2.tsx +0 -58
  163. package/src/FileList/FileV2.tsx +0 -33
  164. package/src/Masthead/MastheadSearchModal.tsx +0 -101
  165. package/src/Messages/MessageBoxTag.tsx +0 -34
  166. package/src/MultidisciplinarySubject/List.tsx +0 -49
  167. package/src/MultidisciplinarySubject/ListItem.tsx +0 -74
  168. package/src/MultidisciplinarySubject/MultidisciplinarySubject.tsx +0 -117
  169. package/src/MultidisciplinarySubject/index.ts +0 -11
  170. package/src/Navigation/NavigationTopicAbout.tsx +0 -171
  171. package/src/RelatedArticleList/RelatedArticleV2.tsx +0 -101
  172. package/src/Search/ToggleSearchButton.tsx +0 -64
  173. package/src/Translation/Translation.tsx +0 -29
  174. package/src/Translation/TranslationLine.tsx +0 -42
  175. package/src/Translation/component.translation.scss +0 -53
  176. package/src/Translation/index.ts +0 -2
@@ -18,12 +18,13 @@ import { ButtonV2 } from '@ndla/button';
18
18
  import { Figure } from '../Figure';
19
19
  import { EmbedByline } from '../LicenseByline';
20
20
  import EmbedErrorPlaceholder from './EmbedErrorPlaceholder';
21
- import { HeartButtonType } from './types';
21
+ import { HeartButtonType, RenderContext } from './types';
22
22
 
23
23
  interface Props {
24
24
  embed: BrightcoveMetaData;
25
25
  isConcept?: boolean;
26
26
  heartButton?: HeartButtonType;
27
+ renderContext?: RenderContext;
27
28
  }
28
29
 
29
30
  const LinkedVideoButton = styled(ButtonV2)`
@@ -57,19 +58,19 @@ const getIframeProps = (data: BrightcoveEmbedData, sources: BrightcoveVideoSourc
57
58
  width: source?.width ?? '640',
58
59
  };
59
60
  };
60
- const BrightcoveEmbed = ({ embed, isConcept, heartButton: HeartButton }: Props) => {
61
+ const BrightcoveEmbed = ({ embed, isConcept, heartButton: HeartButton, renderContext = 'article' }: Props) => {
61
62
  const [showOriginalVideo, setShowOriginalVideo] = useState(true);
62
63
  const { t } = useTranslation();
63
64
  const iframeRef = useRef<HTMLIFrameElement>(null);
64
65
  const { embedData } = embed;
65
66
  const fallbackTitle = `${t('embed.type.video')}: ${embedData.videoid}`;
66
67
  const parsedDescription = useMemo(() => {
67
- if (embed.embedData.caption) {
68
- return parse(embed.embedData.caption);
68
+ if (embed.embedData.caption || renderContext === 'article') {
69
+ return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;
69
70
  } else if (embed.status === 'success' && embed.data.description) {
70
71
  return parse(embed.data.description);
71
72
  }
72
- }, [embed]);
73
+ }, [embed, renderContext]);
73
74
 
74
75
  useEffect(() => {
75
76
  const iframe = iframeRef.current;
@@ -19,7 +19,7 @@ import { Figure, FigureType } from '../Figure';
19
19
  import Image, { ImageLink } from '../Image';
20
20
  import { EmbedByline } from '../LicenseByline';
21
21
  import EmbedErrorPlaceholder from './EmbedErrorPlaceholder';
22
- import { HeartButtonType } from './types';
22
+ import { HeartButtonType, RenderContext } from './types';
23
23
 
24
24
  interface Props {
25
25
  embed: ImageMetaData;
@@ -28,6 +28,7 @@ interface Props {
28
28
  heartButton?: HeartButtonType;
29
29
  inGrid?: boolean;
30
30
  lang?: string;
31
+ renderContext?: RenderContext;
31
32
  }
32
33
 
33
34
  export interface Author {
@@ -105,17 +106,25 @@ export const getCrop = (data: ImageEmbedData) => {
105
106
 
106
107
  const expandedSizes = '(min-width: 1024px) 1024px, 100vw';
107
108
 
108
- const ImageEmbed = ({ embed, previewAlt, heartButton: HeartButton, inGrid, path, lang }: Props) => {
109
+ const ImageEmbed = ({
110
+ embed,
111
+ previewAlt,
112
+ heartButton: HeartButton,
113
+ inGrid,
114
+ path,
115
+ lang,
116
+ renderContext = 'article',
117
+ }: Props) => {
109
118
  const [isBylineHidden, setIsBylineHidden] = useState(hideByline(embed.embedData.size));
110
119
  const [imageSizes, setImageSizes] = useState<string | undefined>(undefined);
111
120
 
112
121
  const parsedDescription = useMemo(() => {
113
- if (embed.embedData.caption) {
114
- return parse(embed.embedData.caption);
122
+ if (embed.embedData.caption || renderContext === 'article') {
123
+ return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;
115
124
  } else if (embed.status === 'success' && embed.data.caption.caption) {
116
125
  return parse(embed.data.caption.caption);
117
126
  }
118
- }, [embed]);
127
+ }, [embed, renderContext]);
119
128
 
120
129
  if (embed.status === 'error') {
121
130
  const { align, size } = embed.embedData;
@@ -10,7 +10,7 @@ import { Meta, StoryObj } from '@storybook/react';
10
10
  import { RelatedContentMetaData } from '@ndla/types-embed';
11
11
  import { defaultParameters } from '../../../../stories/defaults';
12
12
  import RelatedContentEmbed from './RelatedContentEmbed';
13
- import { RelatedArticleListV2 } from '../RelatedArticleList';
13
+ import RelatedArticleList from '../RelatedArticleList';
14
14
 
15
15
  const filmResourceMeta: RelatedContentMetaData = {
16
16
  resource: 'related-content',
@@ -397,41 +397,41 @@ const linkEmbed2: RelatedContentMetaData = {
397
397
 
398
398
  export const RelatedContentStory: StoryObj<typeof RelatedContentEmbed> = {
399
399
  render: () => (
400
- <RelatedArticleListV2>
400
+ <RelatedArticleList>
401
401
  <RelatedContentEmbed embed={learningResourceMeta} />
402
402
  <RelatedContentEmbed embed={learningResourceMeta} />
403
- </RelatedArticleListV2>
403
+ </RelatedArticleList>
404
404
  ),
405
405
  };
406
406
 
407
407
  export const HideAllAboveTwo: StoryObj<typeof RelatedContentEmbed> = {
408
408
  render: () => (
409
- <RelatedArticleListV2>
409
+ <RelatedArticleList>
410
410
  <RelatedContentEmbed embed={learningResourceMeta} />
411
411
  <RelatedContentEmbed embed={filmResourceMeta} />
412
412
  <RelatedContentEmbed embed={learningResourceMeta} />
413
413
  <RelatedContentEmbed embed={filmResourceMeta} />
414
- </RelatedArticleListV2>
414
+ </RelatedArticleList>
415
415
  ),
416
416
  };
417
417
 
418
418
  export const WithLinks: StoryObj<typeof RelatedContentEmbed> = {
419
419
  render: () => (
420
- <RelatedArticleListV2>
420
+ <RelatedArticleList>
421
421
  <RelatedContentEmbed embed={linkEmbed1} />
422
422
  <RelatedContentEmbed embed={linkEmbed2} />
423
- </RelatedArticleListV2>
423
+ </RelatedArticleList>
424
424
  ),
425
425
  };
426
426
 
427
427
  export const Mixed: StoryObj<typeof RelatedContentEmbed> = {
428
428
  render: () => (
429
- <RelatedArticleListV2>
429
+ <RelatedArticleList>
430
430
  <RelatedContentEmbed embed={linkEmbed1} />
431
431
  <RelatedContentEmbed embed={learningResourceMeta} />
432
432
  <RelatedContentEmbed embed={filmResourceMeta} />
433
433
  <RelatedContentEmbed embed={linkEmbed2} />
434
- </RelatedArticleListV2>
434
+ </RelatedArticleList>
435
435
  ),
436
436
  };
437
437
 
@@ -9,7 +9,7 @@
9
9
  import { RelatedContentMetaData } from '@ndla/types-embed';
10
10
  import { useTranslation } from 'react-i18next';
11
11
  import { contentTypeMapping } from '../model/ContentType';
12
- import { RelatedArticleV2 } from '../RelatedArticleList/RelatedArticleV2';
12
+ import { RelatedArticle } from '../RelatedArticleList/RelatedArticleList';
13
13
 
14
14
  interface Props {
15
15
  embed: RelatedContentMetaData;
@@ -34,7 +34,7 @@ const RelatedContentEmbed = ({ embed, isOembed, subject, ndlaFrontendDomain }: P
34
34
  data.resource?.path ??
35
35
  `/article/${embedData.articleId}`;
36
36
  return (
37
- <RelatedArticleV2
37
+ <RelatedArticle
38
38
  title={data.article.title?.title ?? ''}
39
39
  introduction={data.article.metaDescription?.metaDescription ?? ''}
40
40
  target={isOembed ? '_blank' : undefined}
@@ -44,7 +44,7 @@ const RelatedContentEmbed = ({ embed, isOembed, subject, ndlaFrontendDomain }: P
44
44
  );
45
45
  } else if (typeof embedData.url === 'string') {
46
46
  return (
47
- <RelatedArticleV2
47
+ <RelatedArticle
48
48
  title={embedData.title ?? ''}
49
49
  introduction=""
50
50
  to={embedData.url}
@@ -20,4 +20,4 @@ export { ConceptNotionV2 } from './conceptComponents';
20
20
  export { default as ConceptListEmbed } from './ConceptListEmbed';
21
21
  export { default as UnknownEmbed } from './UnknownEmbed';
22
22
  export { InlineConcept, BlockConcept } from './ConceptEmbed';
23
- export type { HeartButtonType } from './types';
23
+ export type { HeartButtonType, RenderContext } from './types';
@@ -10,3 +10,5 @@ import { ElementType } from 'react';
10
10
  import { EmbedMetaData } from '@ndla/types-embed';
11
11
 
12
12
  export type HeartButtonType = ElementType<{ embed: Extract<EmbedMetaData, { status: 'success' }> }>;
13
+
14
+ export type RenderContext = 'article' | 'embed';
@@ -6,10 +6,12 @@
6
6
  *
7
7
  */
8
8
 
9
- import { ReactNode, MouseEvent } from 'react';
9
+ import { ReactNode, useState } from 'react';
10
10
  import BEMHelper from 'react-bem-helper';
11
- import { ButtonV2 } from '@ndla/button';
12
11
  import { useTranslation } from 'react-i18next';
12
+ import styled from '@emotion/styled';
13
+ import { IconButtonV2 } from '@ndla/button';
14
+ import { ChevronDown, ChevronUp } from '@ndla/icons/common';
13
15
 
14
16
  const classes = new BEMHelper({
15
17
  name: 'factbox',
@@ -17,26 +19,37 @@ const classes = new BEMHelper({
17
19
  });
18
20
 
19
21
  interface Props {
20
- dangerouslySetInnerHTML?: { __html: string };
21
22
  children?: ReactNode;
22
23
  }
23
24
 
24
- const toggleFactBox = (event: MouseEvent<HTMLButtonElement>) => {
25
- const button = event.currentTarget;
26
- const aside = button?.previousSibling?.parentElement;
27
- aside?.classList?.toggle('expanded');
28
- };
29
- const FactBox = ({ children, dangerouslySetInnerHTML }: Props) => {
25
+ const StyledAside = styled.aside`
26
+ display: flex;
27
+ flex-direction: column;
28
+ align-items: center;
29
+ `;
30
+
31
+ const StyledDiv = styled.div`
32
+ width: 100%;
33
+ `;
34
+
35
+ const StyledIconButton = styled(IconButtonV2)`
36
+ margin-top: -20px;
37
+ z-index: 1;
38
+ `;
39
+
40
+ const FactBox = ({ children }: Props) => {
30
41
  const { t } = useTranslation();
42
+ const [isOpen, setIsOpen] = useState(false);
43
+
44
+ const additional = isOpen ? 'expanded' : '';
31
45
 
32
46
  return (
33
- <aside {...classes()}>
34
- <div {...classes('content')} dangerouslySetInnerHTML={dangerouslySetInnerHTML}>
35
- {children}
36
- </div>
37
- <ButtonV2 {...classes('button', 'collapsed')} onClick={toggleFactBox} title={t('factbox.open')} />
38
- <ButtonV2 {...classes('button', 'open')} onClick={toggleFactBox} title={t('factbox.close')} />
39
- </aside>
47
+ <StyledAside {...classes(undefined, undefined, additional)}>
48
+ <StyledDiv {...classes('content')}>{children}</StyledDiv>
49
+ <StyledIconButton onClick={() => setIsOpen((p) => !p)} aria-label={t(`factbox.${isOpen ? 'close' : 'open'}`)}>
50
+ {isOpen ? <ChevronUp /> : <ChevronDown />}
51
+ </StyledIconButton>
52
+ </StyledAside>
40
53
  );
41
54
  };
42
55
 
@@ -10,7 +10,7 @@ import styled from '@emotion/styled';
10
10
  import { Meta, StoryObj } from '@storybook/react';
11
11
  import { spacing } from '@ndla/core';
12
12
  import { Heading, Text } from '@ndla/typography';
13
- import FactBoxV2 from './FactBoxV2';
13
+ import FactBox from './FactBox';
14
14
  import { defaultParameters } from '../../../../stories/defaults';
15
15
 
16
16
  const Wrapper = styled.div`
@@ -22,7 +22,7 @@ const Wrapper = styled.div`
22
22
  */
23
23
  export default {
24
24
  title: 'Components/FactBox',
25
- component: FactBoxV2,
25
+ component: FactBox,
26
26
  tags: ['autodocs'],
27
27
  paramemeters: {
28
28
  inlineStories: true,
@@ -57,6 +57,6 @@ export default {
57
57
  </>
58
58
  ),
59
59
  },
60
- } as Meta<typeof FactBoxV2>;
60
+ } as Meta<typeof FactBox>;
61
61
 
62
- export const Default: StoryObj<typeof FactBoxV2> = {};
62
+ export const Default: StoryObj<typeof FactBox> = {};
@@ -1,5 +1,3 @@
1
1
  import FactBox from './FactBox';
2
2
 
3
- export { default as FactBoxV2 } from './FactBoxV2';
4
-
5
3
  export default FactBox;
@@ -7,8 +7,6 @@
7
7
  */
8
8
 
9
9
  export { default as Figure } from './Figure';
10
- export { FigureExpandButton } from './FigureExpandButton';
11
- export { FigureBylineExpandButton } from './FigureBylineExpandButton';
12
10
  export { FigureOpenDialogButton } from './FigureOpenDialogButton';
13
11
 
14
12
  export type { FigureType } from './Figure';
@@ -1,9 +1,35 @@
1
+ /**
2
+ * Copyright (c) 2023-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 styled from '@emotion/styled';
10
+ import { useTranslation } from 'react-i18next';
11
+ import SafeLink from '@ndla/safelink';
2
12
  import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
3
13
  import { Download } from '@ndla/icons/common';
4
- import SafeLink from '@ndla/safelink';
5
- import Tooltip from '@ndla/tooltip';
6
- import { FileFormat, FileType } from './FileList';
14
+
15
+ interface Props {
16
+ title: string;
17
+ url: string;
18
+ fileExists: boolean;
19
+ fileType: string;
20
+ }
21
+
22
+ export interface FileType {
23
+ title: string;
24
+ formats: FileFormat[];
25
+ fileExists?: boolean;
26
+ }
27
+
28
+ export interface FileFormat {
29
+ url: string;
30
+ fileType: string;
31
+ tooltip: string;
32
+ }
7
33
 
8
34
  const LinkTextWrapper = styled.div`
9
35
  & > span {
@@ -31,7 +57,29 @@ const FileLink = styled(SafeLink)`
31
57
  }
32
58
  `;
33
59
 
34
- const renderFormat = (format: FileFormat, title: string, isPrimary: boolean, isDeadLink: boolean) => {
60
+ const FileListItem = styled.li`
61
+ ${fonts.sizes('18px', '26px')};
62
+ font-weight: ${fonts.weight.semibold};
63
+ min-height: 60px;
64
+ background: ${colors.brand.greyLighter};
65
+ display: flex;
66
+ align-items: center;
67
+ flex-wrap: wrap;
68
+ margin-bottom: ${spacing.xsmall};
69
+ padding: ${spacing.small};
70
+ ${mq.range({ from: breakpoints.tablet })} {
71
+ padding: ${spacing.small} ${spacing.normal};
72
+ }
73
+ `;
74
+
75
+ interface FormatProps {
76
+ format: FileFormat;
77
+ title: string;
78
+ isPrimary: boolean;
79
+ isDeadLink: boolean;
80
+ }
81
+
82
+ const Format = ({ format, title, isPrimary, isDeadLink }: FormatProps) => {
35
83
  const titleWithFormat = `${title} (${format.fileType.toUpperCase()})`;
36
84
 
37
85
  if (isDeadLink) {
@@ -46,40 +94,22 @@ const renderFormat = (format: FileFormat, title: string, isPrimary: boolean, isD
46
94
  return (
47
95
  <FileLink key={format.url} to={format.url} target="_blank" aria-label={titleWithFormat}>
48
96
  <Download />
49
- <Tooltip tooltip={format.tooltip}>
50
- <LinkTextWrapper>
51
- <span>{isPrimary ? titleWithFormat : `(${format.fileType.toUpperCase()})`}</span>
52
- </LinkTextWrapper>
53
- </Tooltip>
97
+ <LinkTextWrapper aria-label={format.tooltip}>
98
+ <span>{isPrimary ? titleWithFormat : `(${format.fileType.toUpperCase()})`}</span>
99
+ </LinkTextWrapper>
54
100
  </FileLink>
55
101
  );
56
102
  };
57
103
 
58
- interface Props {
59
- file: FileType;
60
- }
104
+ const File = ({ title, url, fileExists, fileType }: Props) => {
105
+ const { t } = useTranslation();
106
+ const tooltip = `${t('download')} ${url.split('/').pop()}`;
61
107
 
62
- const FileListItem = styled.li`
63
- ${fonts.sizes('18px', '26px')};
64
- font-weight: ${fonts.weight.semibold};
65
- min-height: 60px;
66
- background: ${colors.brand.greyLighter};
67
- display: flex;
68
- align-items: center;
69
- flex-wrap: wrap;
70
- margin-bottom: ${spacing.xsmall};
71
- padding: ${spacing.small};
72
- ${mq.range({ from: breakpoints.tablet })} {
73
- padding: ${spacing.small} ${spacing.normal};
74
- }
75
- `;
76
-
77
- const File = ({ file }: Props) => {
78
- const formatLinks = file.formats.map((format, index) =>
79
- renderFormat(format, file.title, index === 0, !file.fileExists),
108
+ return (
109
+ <FileListItem>
110
+ <Format format={{ url, fileType, tooltip }} isPrimary title={title} isDeadLink={!fileExists} />
111
+ </FileListItem>
80
112
  );
81
-
82
- return <FileListItem key={file.title}>{formatLinks}</FileListItem>;
83
113
  };
84
114
 
85
115
  export default File;
@@ -7,14 +7,14 @@
7
7
  */
8
8
 
9
9
  import { Meta, StoryObj } from '@storybook/react';
10
- import FileV2 from './FileV2';
10
+ import File from './File';
11
11
  import { defaultParameters } from '../../../../stories/defaults';
12
- import FileListV2 from './FileListV2';
12
+ import FileList from './FileList';
13
13
 
14
14
  export default {
15
15
  title: 'Components/FileList',
16
16
  tags: ['autodocs'],
17
- component: FileV2,
17
+ component: File,
18
18
  parameters: {
19
19
  inlineStories: true,
20
20
  ...defaultParameters,
@@ -26,23 +26,23 @@ export default {
26
26
  fileType: 'pdf',
27
27
  },
28
28
  render: (args) => (
29
- <FileListV2>
30
- <FileV2 {...args} />
31
- </FileListV2>
29
+ <FileList>
30
+ <File {...args} />
31
+ </FileList>
32
32
  ),
33
- } as Meta<typeof FileV2>;
33
+ } as Meta<typeof File>;
34
34
 
35
- export const FileNotFound: StoryObj<typeof FileV2> = {
35
+ export const FileNotFound: StoryObj<typeof File> = {
36
36
  args: { fileExists: false },
37
37
  };
38
38
 
39
- export const SeveralFiles: StoryObj<typeof FileV2> = {
39
+ export const SeveralFiles: StoryObj<typeof File> = {
40
40
  render: () => (
41
- <FileListV2>
42
- <FileV2 title="Fil 1" url="https://ndla.no/1" fileExists fileType="mp4" />
43
- <FileV2 title="Fil 2" url="https://ndla.no/2" fileExists={false} fileType="pdf" />
44
- <FileV2 title="Fil 3" url="https://ndla.no/3" fileExists fileType="docx" />
45
- <FileV2 title="Fil 4" url="https://ndla.no/4" fileExists fileType="docx" />
46
- </FileListV2>
41
+ <FileList>
42
+ <File title="Fil 1" url="https://ndla.no/1" fileExists fileType="mp4" />
43
+ <File title="Fil 2" url="https://ndla.no/2" fileExists={false} fileType="pdf" />
44
+ <File title="Fil 3" url="https://ndla.no/3" fileExists fileType="docx" />
45
+ <File title="Fil 4" url="https://ndla.no/4" fileExists fileType="docx" />
46
+ </FileList>
47
47
  ),
48
48
  };
@@ -1,23 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2023-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 styled from '@emotion/styled';
2
10
  import { colors, fonts, spacing } from '@ndla/core';
3
- import File from './File';
4
-
5
- export interface FileType {
6
- title: string;
7
- formats: FileFormat[];
8
- fileExists?: boolean;
9
- }
10
-
11
- export interface FileFormat {
12
- url: string;
13
- fileType: string;
14
- tooltip: string;
15
- }
11
+ import { ReactNode } from 'react';
12
+ import { useTranslation } from 'react-i18next';
16
13
 
17
14
  interface Props {
18
- id: string;
19
- heading: string;
20
- files: FileType[];
15
+ children: ReactNode;
21
16
  }
22
17
 
23
18
  const FileListSection = styled.section`
@@ -35,7 +30,7 @@ const FileListSection = styled.section`
35
30
  }
36
31
  `;
37
32
 
38
- const FileListHeading = styled.h1`
33
+ const FileListHeading = styled.h3`
39
34
  ${fonts.sizes('16px', '18px')};
40
35
  letter-spacing: 0.05em;
41
36
  margin: 0 0 ${spacing.xsmall} 0;
@@ -50,15 +45,14 @@ const FilesList = styled.ul`
50
45
  padding: 0;
51
46
  `;
52
47
 
53
- const FileList = ({ files, heading, id }: Props) => (
54
- <FileListSection>
55
- <FileListHeading>{heading}</FileListHeading>
56
- <FilesList>
57
- {files.map((file) => (
58
- <File key={`file-${id}-${file.title}`} file={file} />
59
- ))}
60
- </FilesList>
61
- </FileListSection>
62
- );
48
+ const FileList = ({ children }: Props) => {
49
+ const { t } = useTranslation();
50
+ return (
51
+ <FileListSection>
52
+ <FileListHeading>{t('files')}</FileListHeading>
53
+ <FilesList>{children}</FilesList>
54
+ </FileListSection>
55
+ );
56
+ };
63
57
 
64
58
  export default FileList;
@@ -1,8 +1,6 @@
1
1
  import FileList from './FileList';
2
2
 
3
3
  export { default as File } from './File';
4
- export { default as FileListV2 } from './FileListV2';
5
4
  export { default as PdfFile } from './PdfFile';
6
- export { default as FileV2 } from './FileV2';
7
5
 
8
6
  export default FileList;
@@ -15,7 +15,7 @@ import { breakpoints, colors, spacing, mq } from '@ndla/core';
15
15
  import { LinkBlockEmbedData } from '@ndla/types-embed';
16
16
  import { useMemo } from 'react';
17
17
  import { Heading } from '@ndla/typography';
18
- import { usePossiblyRelativeUrl } from '../utils/relativeUrl';
18
+ import { getPossiblyRelativeUrl } from '../utils/relativeUrl';
19
19
 
20
20
  const StyledForward = styled(Forward)`
21
21
  margin: 0 ${spacing.nsmall};
@@ -78,7 +78,7 @@ interface Props extends Omit<LinkBlockEmbedData, 'resource'> {
78
78
  }
79
79
 
80
80
  const LinkBlock = ({ title, language, date, url, path }: Props) => {
81
- const href = usePossiblyRelativeUrl(url, path);
81
+ const href = getPossiblyRelativeUrl(url, path);
82
82
  const formattedDate = useMemo(() => {
83
83
  if (!date) return null;
84
84
  const locale = language === 'nb' ? nb : language === 'nn' ? nn : enGB;
@@ -6,8 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import MessageBoxTag from './MessageBoxTag';
10
9
  import MessageBox from './MessageBox';
11
10
  import MessageBanner from './MessageBanner';
12
11
 
13
- export { MessageBox, MessageBoxTag, MessageBanner };
12
+ export { MessageBox, MessageBanner };
@@ -7,6 +7,5 @@
7
7
  */
8
8
 
9
9
  import NavigationBox from './NavigationBox';
10
- import NavigationTopicAbout from './NavigationTopicAbout';
11
10
 
12
- export { NavigationBox, NavigationTopicAbout };
11
+ export { NavigationBox };