@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.
- package/es/ContactBlock/ContactBlock.js +14 -15
- package/es/Embed/AudioEmbed.js +1 -32
- package/es/Embed/BrightcoveEmbed.js +6 -10
- package/es/Embed/ConceptEmbed.js +8 -33
- package/es/Embed/ImageEmbed.js +36 -79
- package/es/Embed/UuDisclaimerEmbed.js +4 -12
- package/es/Embed/conceptComponents.js +28 -29
- package/es/LicenseByline/EmbedByline.js +44 -61
- package/es/LicenseByline/LicenseDescription.js +44 -8
- package/es/LicenseByline/LicenseLink.js +7 -11
- package/es/Messages/MessageBox.js +6 -6
- package/es/index.js +1 -2
- package/es/locale/messages-en.js +35 -22
- package/es/locale/messages-nb.js +35 -22
- package/es/locale/messages-nn.js +34 -21
- package/es/locale/messages-se.js +36 -23
- package/es/locale/messages-sma.js +35 -22
- package/lib/ContactBlock/ContactBlock.js +14 -15
- package/lib/Embed/AudioEmbed.d.ts +1 -3
- package/lib/Embed/AudioEmbed.js +1 -32
- package/lib/Embed/BrightcoveEmbed.d.ts +2 -3
- package/lib/Embed/BrightcoveEmbed.js +6 -10
- package/lib/Embed/ConceptEmbed.d.ts +4 -9
- package/lib/Embed/ConceptEmbed.js +8 -33
- package/lib/Embed/ImageEmbed.d.ts +2 -5
- package/lib/Embed/ImageEmbed.js +34 -79
- package/lib/Embed/UuDisclaimerEmbed.js +3 -11
- package/lib/Embed/conceptComponents.d.ts +0 -3
- package/lib/Embed/conceptComponents.js +28 -29
- package/lib/LicenseByline/EmbedByline.d.ts +7 -6
- package/lib/LicenseByline/EmbedByline.js +46 -60
- package/lib/LicenseByline/LicenseDescription.d.ts +3 -2
- package/lib/LicenseByline/LicenseDescription.js +43 -7
- package/lib/LicenseByline/LicenseLink.d.ts +3 -4
- package/lib/LicenseByline/LicenseLink.js +6 -10
- package/lib/Messages/MessageBox.js +6 -6
- package/lib/index.d.ts +1 -3
- package/lib/index.js +6 -37
- package/lib/locale/messages-en.d.ts +18 -5
- package/lib/locale/messages-en.js +35 -22
- package/lib/locale/messages-nb.d.ts +18 -5
- package/lib/locale/messages-nb.js +35 -22
- package/lib/locale/messages-nn.d.ts +18 -5
- package/lib/locale/messages-nn.js +34 -21
- package/lib/locale/messages-se.d.ts +18 -5
- package/lib/locale/messages-se.js +36 -23
- package/lib/locale/messages-sma.d.ts +18 -5
- package/lib/locale/messages-sma.js +35 -22
- package/package.json +9 -10
- package/src/ContactBlock/ContactBlock.tsx +1 -1
- package/src/Embed/AudioEmbed.stories.tsx +0 -5
- package/src/Embed/AudioEmbed.tsx +3 -40
- package/src/Embed/BrightcoveEmbed.stories.tsx +0 -4
- package/src/Embed/BrightcoveEmbed.tsx +2 -5
- package/src/Embed/ConceptEmbed.stories.tsx +0 -5
- package/src/Embed/ConceptEmbed.tsx +4 -26
- package/src/Embed/ImageEmbed.stories.tsx +0 -12
- package/src/Embed/ImageEmbed.tsx +33 -89
- package/src/Embed/UuDisclaimerEmbed.tsx +2 -1
- package/src/Embed/conceptComponents.tsx +14 -12
- package/src/LicenseByline/EmbedByline.stories.tsx +1 -26
- package/src/LicenseByline/EmbedByline.tsx +50 -82
- package/src/LicenseByline/LicenseDescription.tsx +65 -8
- package/src/LicenseByline/LicenseLink.tsx +6 -12
- package/src/Messages/MessageBox.tsx +1 -0
- package/src/index.ts +1 -12
- package/src/locale/messages-en.ts +30 -17
- package/src/locale/messages-nb.ts +30 -17
- package/src/locale/messages-nn.ts +30 -17
- package/src/locale/messages-se.ts +31 -18
- package/src/locale/messages-sma.ts +30 -17
- package/es/MediaList/MediaList.js +0 -215
- package/es/MediaList/index.js +0 -8
- package/lib/MediaList/MediaList.d.ts +0 -49
- package/lib/MediaList/MediaList.js +0 -227
- package/lib/MediaList/index.d.ts +0 -9
- package/lib/MediaList/index.js +0 -42
- package/src/MediaList/MediaList.tsx +0 -285
- 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",
|
package/src/Embed/ImageEmbed.tsx
CHANGED
|
@@ -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
|
|
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 {
|
|
20
|
+
import { RenderContext } from "./types";
|
|
21
21
|
import { Figure, FigureType, figureActionIndicatorStyle } from "../Figure";
|
|
22
|
-
import 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
|
-
<
|
|
184
|
-
|
|
170
|
+
<Image
|
|
171
|
+
focalPoint={focalPoint}
|
|
172
|
+
contentType={data.image.contentType}
|
|
185
173
|
crop={crop}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
|
|
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,
|
|
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 {
|
|
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}
|
|
235
|
+
<ImageEmbed embed={visualElement} lang={lang} />
|
|
234
236
|
) : visualElement?.resource === "brightcove" ? (
|
|
235
|
-
<BrightcoveEmbed embed={visualElement}
|
|
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
|
-
<
|
|
285
|
-
{copyright
|
|
286
|
-
</
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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("
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
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
|
|
145
|
-
|
|
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
|
|
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
|
-
<
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
|