@ndla/ui 54.0.5 → 55.0.0-alpha.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 (79) hide show
  1. package/es/ContactBlock/ContactBlock.js +14 -15
  2. package/es/Embed/AudioEmbed.js +1 -32
  3. package/es/Embed/BrightcoveEmbed.js +6 -10
  4. package/es/Embed/ConceptEmbed.js +8 -33
  5. package/es/Embed/ImageEmbed.js +36 -79
  6. package/es/Embed/UuDisclaimerEmbed.js +4 -12
  7. package/es/Embed/conceptComponents.js +28 -29
  8. package/es/LicenseByline/EmbedByline.js +44 -61
  9. package/es/LicenseByline/LicenseDescription.js +44 -8
  10. package/es/LicenseByline/LicenseLink.js +7 -11
  11. package/es/Messages/MessageBox.js +6 -6
  12. package/es/index.js +1 -2
  13. package/es/locale/messages-en.js +35 -22
  14. package/es/locale/messages-nb.js +35 -22
  15. package/es/locale/messages-nn.js +34 -21
  16. package/es/locale/messages-se.js +36 -23
  17. package/es/locale/messages-sma.js +35 -22
  18. package/lib/ContactBlock/ContactBlock.js +14 -15
  19. package/lib/Embed/AudioEmbed.d.ts +1 -3
  20. package/lib/Embed/AudioEmbed.js +1 -32
  21. package/lib/Embed/BrightcoveEmbed.d.ts +2 -3
  22. package/lib/Embed/BrightcoveEmbed.js +6 -10
  23. package/lib/Embed/ConceptEmbed.d.ts +4 -9
  24. package/lib/Embed/ConceptEmbed.js +8 -33
  25. package/lib/Embed/ImageEmbed.d.ts +2 -5
  26. package/lib/Embed/ImageEmbed.js +34 -79
  27. package/lib/Embed/UuDisclaimerEmbed.js +3 -11
  28. package/lib/Embed/conceptComponents.d.ts +0 -3
  29. package/lib/Embed/conceptComponents.js +28 -29
  30. package/lib/LicenseByline/EmbedByline.d.ts +7 -6
  31. package/lib/LicenseByline/EmbedByline.js +46 -60
  32. package/lib/LicenseByline/LicenseDescription.d.ts +3 -2
  33. package/lib/LicenseByline/LicenseDescription.js +43 -7
  34. package/lib/LicenseByline/LicenseLink.d.ts +3 -4
  35. package/lib/LicenseByline/LicenseLink.js +6 -10
  36. package/lib/Messages/MessageBox.js +6 -6
  37. package/lib/index.d.ts +1 -3
  38. package/lib/index.js +6 -37
  39. package/lib/locale/messages-en.d.ts +18 -5
  40. package/lib/locale/messages-en.js +35 -22
  41. package/lib/locale/messages-nb.d.ts +18 -5
  42. package/lib/locale/messages-nb.js +35 -22
  43. package/lib/locale/messages-nn.d.ts +18 -5
  44. package/lib/locale/messages-nn.js +34 -21
  45. package/lib/locale/messages-se.d.ts +18 -5
  46. package/lib/locale/messages-se.js +36 -23
  47. package/lib/locale/messages-sma.d.ts +18 -5
  48. package/lib/locale/messages-sma.js +35 -22
  49. package/package.json +9 -10
  50. package/src/ContactBlock/ContactBlock.tsx +1 -1
  51. package/src/Embed/AudioEmbed.stories.tsx +0 -5
  52. package/src/Embed/AudioEmbed.tsx +3 -40
  53. package/src/Embed/BrightcoveEmbed.stories.tsx +0 -4
  54. package/src/Embed/BrightcoveEmbed.tsx +2 -5
  55. package/src/Embed/ConceptEmbed.stories.tsx +0 -5
  56. package/src/Embed/ConceptEmbed.tsx +4 -26
  57. package/src/Embed/ImageEmbed.stories.tsx +0 -12
  58. package/src/Embed/ImageEmbed.tsx +33 -89
  59. package/src/Embed/UuDisclaimerEmbed.tsx +2 -1
  60. package/src/Embed/conceptComponents.tsx +14 -12
  61. package/src/LicenseByline/EmbedByline.stories.tsx +1 -26
  62. package/src/LicenseByline/EmbedByline.tsx +50 -82
  63. package/src/LicenseByline/LicenseDescription.tsx +65 -8
  64. package/src/LicenseByline/LicenseLink.tsx +6 -12
  65. package/src/Messages/MessageBox.tsx +1 -0
  66. package/src/index.ts +1 -12
  67. package/src/locale/messages-en.ts +30 -17
  68. package/src/locale/messages-nb.ts +30 -17
  69. package/src/locale/messages-nn.ts +30 -17
  70. package/src/locale/messages-se.ts +31 -18
  71. package/src/locale/messages-sma.ts +30 -17
  72. package/es/MediaList/MediaList.js +0 -215
  73. package/es/MediaList/index.js +0 -8
  74. package/lib/MediaList/MediaList.d.ts +0 -49
  75. package/lib/MediaList/MediaList.js +0 -227
  76. package/lib/MediaList/index.d.ts +0 -9
  77. package/lib/MediaList/index.js +0 -42
  78. package/src/MediaList/MediaList.tsx +0 -285
  79. package/src/MediaList/index.ts +0 -17
@@ -11,7 +11,6 @@ import { Meta, StoryObj } from "@storybook/react";
11
11
  import { IImageMetaInformationV3 } from "@ndla/types-backend/image-api";
12
12
  import { ImageEmbedData } from "@ndla/types-embed";
13
13
  import ImageEmbed from "./ImageEmbed";
14
- import StoryFavoriteButton from "../../../../stories/StoryFavoriteButton";
15
14
  import { ArticleWrapper } from "../Article";
16
15
  import LayoutItem, { OneColumn } from "../Layout";
17
16
 
@@ -111,7 +110,6 @@ export default meta;
111
110
 
112
111
  export const ImageEmbedStory: StoryObj<typeof ImageEmbed> = {
113
112
  args: {
114
- heartButton: StoryFavoriteButton,
115
113
  embed: {
116
114
  resource: "image",
117
115
  status: "success",
@@ -125,7 +123,6 @@ ImageEmbedStory.storyName = "ImageEmbed";
125
123
 
126
124
  export const Failed: StoryObj<typeof ImageEmbed> = {
127
125
  args: {
128
- heartButton: StoryFavoriteButton,
129
126
  embed: {
130
127
  resource: "image",
131
128
  status: "error",
@@ -136,7 +133,6 @@ export const Failed: StoryObj<typeof ImageEmbed> = {
136
133
 
137
134
  export const HiddenByline: StoryObj<typeof ImageEmbed> = {
138
135
  args: {
139
- heartButton: StoryFavoriteButton,
140
136
  embed: {
141
137
  resource: "image",
142
138
  status: "success",
@@ -151,7 +147,6 @@ export const HiddenByline: StoryObj<typeof ImageEmbed> = {
151
147
 
152
148
  export const FullWidth: StoryObj<typeof ImageEmbed> = {
153
149
  args: {
154
- heartButton: StoryFavoriteButton,
155
150
  embed: {
156
151
  resource: "image",
157
152
  status: "success",
@@ -168,7 +163,6 @@ export const FullWidth: StoryObj<typeof ImageEmbed> = {
168
163
 
169
164
  export const Cropped: StoryObj<typeof ImageEmbed> = {
170
165
  args: {
171
- heartButton: StoryFavoriteButton,
172
166
  embed: {
173
167
  resource: "image",
174
168
  status: "success",
@@ -214,7 +208,6 @@ const TextWrapper = ({ children }: { children: ReactNode }) => (
214
208
 
215
209
  export const FloatLeft: StoryObj<typeof ImageEmbed> = {
216
210
  args: {
217
- heartButton: StoryFavoriteButton,
218
211
  embed: {
219
212
  resource: "image",
220
213
  status: "success",
@@ -234,7 +227,6 @@ export const FloatLeft: StoryObj<typeof ImageEmbed> = {
234
227
 
235
228
  export const FloatRight: StoryObj<typeof ImageEmbed> = {
236
229
  args: {
237
- heartButton: StoryFavoriteButton,
238
230
  embed: {
239
231
  resource: "image",
240
232
  status: "success",
@@ -255,7 +247,6 @@ export const FloatRight: StoryObj<typeof ImageEmbed> = {
255
247
 
256
248
  export const FloatRightSmall: StoryObj<typeof ImageEmbed> = {
257
249
  args: {
258
- heartButton: StoryFavoriteButton,
259
250
  embed: {
260
251
  resource: "image",
261
252
  status: "success",
@@ -276,7 +267,6 @@ export const FloatRightSmall: StoryObj<typeof ImageEmbed> = {
276
267
 
277
268
  export const FloatLeftSmall: StoryObj<typeof ImageEmbed> = {
278
269
  args: {
279
- heartButton: StoryFavoriteButton,
280
270
  embed: {
281
271
  resource: "image",
282
272
  status: "success",
@@ -297,7 +287,6 @@ export const FloatLeftSmall: StoryObj<typeof ImageEmbed> = {
297
287
 
298
288
  export const FloatRightExtraSmall: StoryObj<typeof ImageEmbed> = {
299
289
  args: {
300
- heartButton: StoryFavoriteButton,
301
290
  embed: {
302
291
  resource: "image",
303
292
  status: "success",
@@ -318,7 +307,6 @@ export const FloatRightExtraSmall: StoryObj<typeof ImageEmbed> = {
318
307
 
319
308
  export const FloatLeftExtraSmall: StoryObj<typeof ImageEmbed> = {
320
309
  args: {
321
- heartButton: StoryFavoriteButton,
322
310
  embed: {
323
311
  resource: "image",
324
312
  status: "success",
@@ -11,23 +11,20 @@ import parse from "html-react-parser";
11
11
  import { MouseEventHandler, ReactNode, useMemo, useState } from "react";
12
12
  import { useTranslation } from "react-i18next";
13
13
  import styled from "@emotion/styled";
14
- import { colors, spacing, utils } from "@ndla/core";
14
+ import { colors, spacing } from "@ndla/core";
15
15
  import { ExpandTwoArrows } from "@ndla/icons/action";
16
16
  import { ArrowCollapse, ChevronDown, ChevronUp } from "@ndla/icons/common";
17
17
  import { COPYRIGHTED } from "@ndla/licenses";
18
18
  import { ImageEmbedData, ImageMetaData } from "@ndla/types-embed";
19
19
  import EmbedErrorPlaceholder from "./EmbedErrorPlaceholder";
20
- import { CanonicalUrlFuncs, HeartButtonType, RenderContext } from "./types";
20
+ import { RenderContext } from "./types";
21
21
  import { Figure, FigureType, figureActionIndicatorStyle } from "../Figure";
22
- import Image, { ImageLink } from "../Image";
22
+ import Image from "../Image";
23
23
  import { EmbedByline } from "../LicenseByline";
24
24
 
25
25
  interface Props {
26
26
  embed: ImageMetaData;
27
27
  previewAlt?: boolean;
28
- path?: string;
29
- heartButton?: HeartButtonType;
30
- canonicalUrl?: CanonicalUrlFuncs["image"];
31
28
  inGrid?: boolean;
32
29
  lang?: string;
33
30
  renderContext?: RenderContext;
@@ -131,17 +128,7 @@ const StyledFigure = styled(Figure)`
131
128
  }
132
129
  `;
133
130
 
134
- const ImageEmbed = ({
135
- embed,
136
- previewAlt,
137
- heartButton: HeartButton,
138
- inGrid,
139
- path,
140
- lang,
141
- canonicalUrl,
142
- renderContext = "article",
143
- children,
144
- }: Props) => {
131
+ const ImageEmbed = ({ embed, previewAlt, inGrid, lang, renderContext = "article", children }: Props) => {
145
132
  const [isBylineHidden, setIsBylineHidden] = useState(hideByline(embed.embedData));
146
133
  const [imageSizes, setImageSizes] = useState<string | undefined>(undefined);
147
134
  // 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).
@@ -180,94 +167,51 @@ const ImageEmbed = ({
180
167
  return (
181
168
  <StyledFigure type={imageSizes ? undefined : figureType} {...floatAttr}>
182
169
  {children}
183
- <ImageWrapper
184
- src={!isCopyrighted ? canonicalUrl?.(data) : undefined}
170
+ <Image
171
+ focalPoint={focalPoint}
172
+ contentType={data.image.contentType}
185
173
  crop={crop}
186
- embedData={embedData}
187
- pagePath={path}
188
- >
189
- <Image
190
- focalPoint={focalPoint}
191
- contentType={data.image.contentType}
192
- crop={crop}
193
- sizes={imageSizes ?? sizes}
194
- alt={altText}
195
- src={data.image.imageUrl}
196
- border={embedData.border}
197
- expandButton={
198
- <ExpandButton
199
- embedData={embedData}
200
- expanded={!!imageSizes}
201
- bylineHidden={isBylineHidden}
202
- onExpand={() => {
203
- if (!imageSizes) {
204
- setImageSizes(expandedSizes);
205
- setTimeout(() => {
206
- setFloatAttr({});
207
- }, 400); //Removing the float parameter too quickly causes the image to be resized from left regardless
208
- } else {
209
- setImageSizes(undefined);
210
- setFloatAttr({ "data-float": embedData.align });
211
- }
212
- }}
213
- onHideByline={() => setIsBylineHidden((p) => !p)}
214
- />
215
- }
216
- lang={lang}
217
- />
218
- </ImageWrapper>
174
+ sizes={imageSizes ?? sizes}
175
+ alt={altText}
176
+ src={data.image.imageUrl}
177
+ border={embedData.border}
178
+ expandButton={
179
+ <ExpandButton
180
+ embedData={embedData}
181
+ expanded={!!imageSizes}
182
+ bylineHidden={isBylineHidden}
183
+ onExpand={() => {
184
+ if (!imageSizes) {
185
+ setImageSizes(expandedSizes);
186
+ setTimeout(() => {
187
+ setFloatAttr({});
188
+ }, 400); //Removing the float parameter too quickly causes the image to be resized from left regardless
189
+ } else {
190
+ setImageSizes(undefined);
191
+ setFloatAttr({ "data-float": embedData.align });
192
+ }
193
+ }}
194
+ onHideByline={() => setIsBylineHidden((p) => !p)}
195
+ />
196
+ }
197
+ lang={lang}
198
+ />
219
199
  {isBylineHidden ? null : (
220
200
  <EmbedByline
221
201
  type="image"
222
202
  copyright={data.copyright}
223
- hideOnLargeScreens={isSmall(embedData.size) && !imageSizes}
224
203
  description={parsedDescription}
225
- bottomRounded
226
204
  visibleAlt={previewAlt ? embed.embedData.alt : ""}
227
- inGrid={inGrid}
228
- >
229
- {HeartButton && !isCopyrighted && <HeartButton embed={embed} />}
230
- </EmbedByline>
205
+ />
231
206
  )}
232
207
  </StyledFigure>
233
208
  );
234
209
  };
235
210
 
236
- const HiddenSpan = styled.span`
237
- ${utils.visuallyHidden};
238
- `;
239
-
240
- interface ImageWrapperProps {
241
- src?: string;
242
- children: React.ReactNode;
243
- pagePath?: string;
244
- crop?: {
245
- startX: number;
246
- startY: number;
247
- endX: number;
248
- endY: number;
249
- };
250
- embedData: ImageEmbedData;
251
- }
252
-
253
211
  const hideByline = (embed: ImageEmbedData): boolean => {
254
212
  return (!!embed.size && embed.size.endsWith("-hide-byline")) || embed.hideByline === "true";
255
213
  };
256
214
 
257
- const ImageWrapper = ({ src, crop, children, pagePath, embedData }: ImageWrapperProps) => {
258
- const { t } = useTranslation();
259
- if (isSmall(embedData.size) || hideByline(embedData) || !src || (pagePath && src.endsWith(pagePath))) {
260
- return <>{children}</>;
261
- }
262
-
263
- return (
264
- <ImageLink src={src} crop={crop}>
265
- {children}
266
- <HiddenSpan>{t("license.images.itemImage.ariaLabel")}</HiddenSpan>
267
- </ImageLink>
268
- );
269
- };
270
-
271
215
  interface ExpandButtonProps {
272
216
  embedData: ImageEmbedData;
273
217
  expanded: boolean;
@@ -9,7 +9,7 @@
9
9
  import { ReactNode } from "react";
10
10
  import { useTranslation } from "react-i18next";
11
11
  import styled from "@emotion/styled";
12
- import { spacing } from "@ndla/core";
12
+ import { fonts, spacing } from "@ndla/core";
13
13
  import { InformationOutline } from "@ndla/icons/common";
14
14
  import { SafeLink } from "@ndla/safelink";
15
15
  import { UuDisclaimerMetaData } from "@ndla/types-embed";
@@ -26,6 +26,7 @@ const StyledMessageBox = styled(MessageBox)`
26
26
 
27
27
  const Disclaimer = styled.div`
28
28
  display: flow;
29
+ ${fonts.sizes("18px", "24px")};
29
30
  user-select: none;
30
31
  -webkit-user-select: none;
31
32
  -moz-user-select: none;
@@ -12,14 +12,13 @@ import { useTranslation } from "react-i18next";
12
12
  import { css } from "@emotion/react";
13
13
  import styled from "@emotion/styled";
14
14
  import { breakpoints, colors, fonts, misc, mq, spacing, stackOrder } from "@ndla/core";
15
- import { COPYRIGHTED } from "@ndla/licenses";
16
15
  import { ConceptData, ConceptVisualElementMeta } from "@ndla/types-embed";
17
- import { ExternalEmbed, HeartButtonType, IframeEmbed } from ".";
16
+ import { ExternalEmbed, IframeEmbed } from ".";
18
17
  import BrightcoveEmbed from "./BrightcoveEmbed";
19
18
  import H5pEmbed from "./H5pEmbed";
20
19
  import ImageEmbed from "./ImageEmbed";
21
20
  import { Gloss } from "../Gloss";
22
- import { EmbedByline } from "../LicenseByline";
21
+ import { LicenseContainerContent } from "../LicenseByline/EmbedByline";
23
22
  import { Copyright } from "../types";
24
23
 
25
24
  export type ConceptType = "concept" | "gloss";
@@ -47,8 +46,6 @@ interface ConceptNotionProps extends RefAttributes<HTMLDivElement>, Omit<Concept
47
46
  tags?: string[];
48
47
  subjects?: string[];
49
48
  headerButtons?: ReactNode;
50
- heartButton?: HeartButtonType;
51
- conceptHeartButton?: ReactNode;
52
49
  exampleIds?: string;
53
50
  exampleLangs?: string;
54
51
  showTitle?: boolean;
@@ -182,6 +179,13 @@ const StyledList = styled.ul`
182
179
  padding: ${spacing.xxsmall};
183
180
  }
184
181
  `;
182
+ const BylineWrapper = styled.div`
183
+ padding: 0 ${spacing.normal} ${spacing.small} ${spacing.normal};
184
+ span {
185
+ font-family: ${fonts.sans};
186
+ ${fonts.sizes("16px", "26px")};
187
+ }
188
+ `;
185
189
 
186
190
  export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
187
191
  (
@@ -196,8 +200,6 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
196
200
  previewAlt,
197
201
  tags,
198
202
  subjects,
199
- heartButton,
200
- conceptHeartButton,
201
203
  conceptType,
202
204
  glossData,
203
205
  headerButtons,
@@ -230,9 +232,9 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
230
232
  <>
231
233
  <StyledNotionDialogContent>
232
234
  {visualElement?.resource === "image" ? (
233
- <ImageEmbed embed={visualElement} heartButton={heartButton} lang={lang} />
235
+ <ImageEmbed embed={visualElement} lang={lang} />
234
236
  ) : visualElement?.resource === "brightcove" ? (
235
- <BrightcoveEmbed embed={visualElement} heartButton={heartButton} />
237
+ <BrightcoveEmbed embed={visualElement} />
236
238
  ) : visualElement?.resource === "h5p" ? (
237
239
  <H5pEmbed embed={visualElement} />
238
240
  ) : visualElement?.resource === "iframe" ? (
@@ -281,9 +283,9 @@ export const ConceptNotionV2 = forwardRef<HTMLDivElement, ConceptNotionProps>(
281
283
  )}
282
284
  </ContentSpacing>
283
285
  {copyright && (
284
- <EmbedByline copyright={copyright} type={conceptType as ConceptType}>
285
- {copyright.license?.license.toLowerCase() !== COPYRIGHTED && conceptHeartButton}
286
- </EmbedByline>
286
+ <BylineWrapper>
287
+ <LicenseContainerContent copyright={copyright} type={conceptType as ConceptType} />
288
+ </BylineWrapper>
287
289
  )}
288
290
  </div>
289
291
  );
@@ -6,25 +6,9 @@
6
6
  *
7
7
  */
8
8
 
9
- import styled from "@emotion/styled";
10
9
  import { Meta, StoryFn } from "@storybook/react";
11
- import { IconButtonV2 } from "@ndla/button";
12
- import { breakpoints, mq, spacing } from "@ndla/core";
13
- import { HeartOutline } from "@ndla/icons/action";
14
- import { Switch } from "@ndla/switch";
15
10
  import EmbedByline from "./EmbedByline";
16
11
 
17
- const ButtonWrapper = styled.div`
18
- display: flex;
19
- gap: ${spacing.small};
20
- ${mq.range({ until: breakpoints.tablet })} {
21
- flex: 1;
22
- width: 100%;
23
- justify-content: space-between;
24
- align-items: space-between;
25
- }
26
- `;
27
-
28
12
  export default {
29
13
  title: "Components/EmbedByline",
30
14
  component: EmbedByline,
@@ -34,14 +18,6 @@ export default {
34
18
  bottomRounded: true,
35
19
  visibleAlt: "Synlig alt-tekst kan legges her, eller fjernes helt",
36
20
  type: "image",
37
- children: (
38
- <ButtonWrapper>
39
- <Switch checked={false} label="Bytt til synstolket video" onChange={() => {}} id="switch" />
40
- <IconButtonV2 variant="ghost" aria-label="Legg til i favoritter">
41
- <HeartOutline />
42
- </IconButtonV2>
43
- </ButtonWrapper>
44
- ),
45
21
  description:
46
22
  "Bildetekst som kan være ganske lang. Denne roboten er laget av DALLE2, en helt vaskeekte AI. Hvis denne teksten blir veldig lang kommer den på flere linjer.",
47
23
  copyright: {
@@ -71,8 +47,7 @@ export default {
71
47
  } as Meta<typeof EmbedByline>;
72
48
 
73
49
  export const EmbedBylineStory: StoryFn<typeof EmbedByline> = (args) => {
74
- const { children, ...rest } = args;
75
- return <EmbedByline {...rest}>{children}</EmbedByline>;
50
+ return <EmbedByline {...args} />;
76
51
  };
77
52
 
78
53
  EmbedBylineStory.storyName = "EmbedByline";
@@ -8,9 +8,8 @@
8
8
 
9
9
  import { ReactNode } from "react";
10
10
  import { useTranslation } from "react-i18next";
11
- import { css } from "@emotion/react";
12
11
  import styled from "@emotion/styled";
13
- import { breakpoints, colors, fonts, misc, mq, spacing } from "@ndla/core";
12
+ import { colors, fonts, misc, spacing } from "@ndla/core";
14
13
  import { WarningOutline } from "@ndla/icons/common";
15
14
  import { getLicenseByAbbreviation, getLicenseCredits } from "@ndla/licenses";
16
15
  import { ICopyright as ArticleCopyright } from "@ndla/types-backend/article-api";
@@ -28,9 +27,6 @@ interface BaseProps {
28
27
  children?: ReactNode;
29
28
  visibleAlt?: string;
30
29
  error?: true | false;
31
- hideOnLargeScreens?: boolean;
32
- first?: boolean;
33
- inGrid?: boolean;
34
30
  }
35
31
 
36
32
  export interface EmbedBylineErrorProps extends BaseProps {
@@ -78,19 +74,13 @@ export type EmbedBylineTypeProps =
78
74
 
79
75
  type Props = EmbedBylineTypeProps | EmbedBylineErrorProps;
80
76
 
81
- export type LicenseType = ReturnType<typeof getLicenseByAbbreviation>;
82
-
83
- const BylineWrapper = styled.div`
77
+ const BylineWrapper = styled.figcaption`
84
78
  display: flex;
85
79
  flex-direction: column;
86
- gap: ${spacing.small};
87
80
  font-family: ${fonts.sans};
88
- ${fonts.sizes("18px", "24px")};
89
- background-color: ${colors.brand.lightest};
90
- padding: ${spacing.nsmall} ${spacing.normal};
91
- border: 1px solid ${colors.brand.light};
92
- border-top: none;
93
-
81
+ ${fonts.sizes("16px", "26px")};
82
+ padding: ${spacing.small} 0;
83
+ background-color: ${colors.white};
94
84
  &[data-top-rounded="true"] {
95
85
  border-top-right-radius: ${misc.borderRadius};
96
86
  border-top-left-radius: ${misc.borderRadius};
@@ -104,97 +94,75 @@ const BylineWrapper = styled.div`
104
94
  &[data-error="true"] {
105
95
  border: none;
106
96
  background-color: ${colors.support.redLightest};
107
- }
108
- &[data-first="true"] {
109
- border-top: 1px solid ${colors.brand.light};
110
- }
111
- &[data-hide-on-large-screens="true"] {
112
- ${mq.range({ from: breakpoints.tablet })} {
113
- display: none;
114
- }
115
- }
116
- `;
117
-
118
- const mobileStyling = css`
119
- align-items: flex-start;
120
- gap: ${spacing.xsmall};
121
- flex-direction: column;
122
- `;
123
-
124
- const RightsWrapper = styled.div`
125
- display: flex;
126
- align-items: center;
127
- flex-wrap: wrap;
128
- gap: ${spacing.nsmall};
129
-
130
- &[data-grid="true"] {
131
- ${mobileStyling}
132
- }
133
-
134
- ${mq.range({ until: breakpoints.tabletWide })} {
135
- ${mobileStyling}
97
+ padding: ${spacing.nsmall} ${spacing.normal};
98
+ ${fonts.sizes("18px", "24px")};
136
99
  }
137
100
  `;
138
101
 
139
102
  const StyledSpan = styled.span`
140
103
  font-style: italic;
141
104
  color: grey;
105
+ font-family: ${fonts.sans};
106
+ ${fonts.sizes("16px", "26px")};
142
107
  `;
143
108
 
144
- const LicenseInformationWrapper = styled.div`
145
- flex: 1;
146
- padding-right: ${spacing.xsmall};
147
- `;
148
-
149
- const EmbedByline = ({
150
- type,
151
- topRounded,
152
- bottomRounded,
153
- description,
154
- children,
155
- visibleAlt,
156
- hideOnLargeScreens,
157
- first = true,
158
- inGrid = false,
159
- ...props
160
- }: Props) => {
161
- const { t, i18n } = useTranslation();
109
+ const EmbedByline = ({ type, topRounded, bottomRounded, description, children, visibleAlt, ...props }: Props) => {
110
+ const { t } = useTranslation();
162
111
 
163
112
  if (props.error) {
164
113
  const typeString = type === "h5p" ? "H5P" : t(`embed.type.${type}`).toLowerCase();
165
114
  return (
166
115
  <BylineWrapper data-top-rounded={topRounded} data-bottom-rounded={bottomRounded} data-error={true}>
167
- <LicenseDescription description={t("embed.embedError", { type: typeString })} icon={<WarningOutline />} />
116
+ <LicenseDescription warningByline={props.error} icon={<WarningOutline />}>
117
+ {t("embed.embedError", { type: typeString })}
118
+ </LicenseDescription>
168
119
  </BylineWrapper>
169
120
  );
170
121
  }
171
122
 
172
123
  const { copyright } = props;
173
124
 
125
+ return (
126
+ <>
127
+ <BylineWrapper>
128
+ <div>
129
+ <LicenseContainerContent type={type} copyright={copyright}>
130
+ {description}
131
+ </LicenseContainerContent>
132
+ {children}
133
+ </div>
134
+ </BylineWrapper>
135
+ {visibleAlt ? <StyledSpan>{`Alt: ${visibleAlt}`}</StyledSpan> : null}
136
+ </>
137
+ );
138
+ };
139
+
140
+ interface LicenseContainerProps {
141
+ children?: ReactNode;
142
+ copyright: EmbedBylineTypeProps["copyright"];
143
+ type: Props["type"];
144
+ }
145
+
146
+ export const LicenseContainerContent = ({ children, copyright, type }: LicenseContainerProps) => {
147
+ const { t, i18n } = useTranslation();
174
148
  const license = copyright ? getLicenseByAbbreviation(copyright.license?.license ?? "", i18n.language) : undefined;
175
149
  const authors = getLicenseCredits(copyright);
176
150
  const captionAuthors = Object.values(authors).find((i) => i.length > 0) ?? [];
177
151
 
152
+ const Component = children ? LicenseDescription : "span";
153
+
178
154
  return (
179
- <BylineWrapper
180
- data-top-rounded={topRounded}
181
- data-hide-on-large-screens={hideOnLargeScreens}
182
- data-bottom-rounded={bottomRounded}
183
- data-first={first}
184
- >
185
- {description && <LicenseDescription description={description} />}
186
- {visibleAlt ? <StyledSpan>{`Alt: ${visibleAlt}`}</StyledSpan> : null}
187
- <RightsWrapper data-grid={inGrid}>
188
- {license ? <LicenseLink license={license} asLink={!!license.url.length} /> : null}
189
- <LicenseInformationWrapper>
190
- <span>
191
- <b>{`${t(`embed.type.${type}`)}${captionAuthors.length ? ":" : ""}`} </b>
192
- {captionAuthors.map((author) => author.name).join(", ")}
193
- </span>
194
- </LicenseInformationWrapper>
195
- {children}
196
- </RightsWrapper>
197
- </BylineWrapper>
155
+ <Component>
156
+ {children}
157
+ {` ${t(`embed.type.${type}`)}${captionAuthors.length ? ": " : ""}`}
158
+ {captionAuthors.map((author) => author.name).join(", ")}
159
+ {license ? (
160
+ <>
161
+ {" / "}
162
+ <LicenseLink license={license} />
163
+ </>
164
+ ) : null}
165
+ </Component>
198
166
  );
199
167
  };
200
168