diff --git a/dotcom-rendering/src/components/MultiImageBlockComponent.stories.tsx b/dotcom-rendering/src/components/MultiImageBlockComponent.stories.tsx
index 5c068242595..b3d110d1785 100644
--- a/dotcom-rendering/src/components/MultiImageBlockComponent.stories.tsx
+++ b/dotcom-rendering/src/components/MultiImageBlockComponent.stories.tsx
@@ -144,3 +144,20 @@ export const GridOfFourWithCaption = () => {
);
};
GridOfFourWithCaption.storyName = 'grid of four with caption';
+
+export const Slideshow = () => {
+ return (
+
+ );
+};
+Slideshow.storyName = 'slideshow';
diff --git a/dotcom-rendering/src/components/MultiImageBlockComponent.tsx b/dotcom-rendering/src/components/MultiImageBlockComponent.tsx
index c4c1b89927b..88de111dcef 100644
--- a/dotcom-rendering/src/components/MultiImageBlockComponent.tsx
+++ b/dotcom-rendering/src/components/MultiImageBlockComponent.tsx
@@ -5,11 +5,15 @@ import type { ImageBlockElement } from '../types/content';
import { Caption } from './Caption';
import { GridItem } from './GridItem';
import { ImageComponent } from './ImageComponent';
+import { SlideshowCarousel } from './SlideshowCarousel.importable';
+import { getLargest, getMaster } from '../lib/image';
+import { Island } from './Island';
type Props = {
images: ImageBlockElement[];
format: ArticleFormat;
caption?: string;
+ presentation?: 'slideshow' | 'side-by-side' | 'stacked';
};
const ieFallback = css`
@@ -102,6 +106,14 @@ const GridOfFour = ({ children }: { children: React.ReactNode }) => (
);
+const removeLastFullStop = (text?: string) => {
+ if (!text) return text;
+ if (text.endsWith('.')) {
+ return text.slice(0, -1);
+ }
+ return text;
+};
+
const OneImage = ({
images,
format,
@@ -110,23 +122,26 @@ const OneImage = ({
images: [ImageBlockElement];
format: ArticleFormat;
caption?: string;
-}) => (
-
-
- {!!caption && (
-
{
+ const captionToUse = caption || removeLastFullStop(images[0].data.caption);
+ return (
+
+
- )}
-
-);
+ {!!captionToUse && (
+
+ )}
+
+ );
+};
const TwoImage = ({
images,
@@ -136,35 +151,44 @@ const TwoImage = ({
images: [ImageBlockElement, ImageBlockElement];
format: ArticleFormat;
caption?: string;
-}) => (
-
-
-
- {
+ const captionLeft =
+ images[0].data.caption &&
+ `${removeLastFullStop(images[0].data.caption)} (above left). `;
+ const captionRight =
+ images[1].data.caption &&
+ `${removeLastFullStop(images[1].data.caption)} (above right). `;
+ const captionToUse = caption || `${captionLeft ?? ''}${captionRight ?? ''}`;
+ return (
+
+
+
+
+
+
+
+
+
+ {!!captionToUse && (
+
-
-
-
-
-
- {!!caption && (
-
- )}
-
-);
+ )}
+
+ );
+};
const ThreeImage = ({
images,
@@ -174,43 +198,59 @@ const ThreeImage = ({
images: [ImageBlockElement, ImageBlockElement, ImageBlockElement];
format: ArticleFormat;
caption?: string;
-}) => (
-
-
-
- {
+ const captionTop =
+ images[0].data.caption &&
+ `${removeLastFullStop(images[0].data.caption)} (top). `;
+ const captionBottomLeft =
+ images[1].data.caption &&
+ `${removeLastFullStop(images[1].data.caption)} (bottom left). `;
+ const captionBottomRight =
+ images[2].data.caption &&
+ `${removeLastFullStop(images[2].data.caption)} (bottom right). `;
+ const captionToUse =
+ caption ||
+ `${captionTop ?? ''}${captionBottomLeft ?? ''}${
+ captionBottomRight ?? ''
+ }`;
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ {!!captionToUse && (
+
-
-
-
-
-
-
-
-
- {!!caption && (
-
- )}
-
-);
+ )}
+
+ );
+};
const FourImage = ({
images,
@@ -225,88 +265,153 @@ const FourImage = ({
];
format: ArticleFormat;
caption?: string;
-}) => (
-
-
-
-
-
-
- {
+ const captionTopLeft =
+ images[0].data.caption &&
+ `${removeLastFullStop(images[0].data.caption)} (top left). `;
+ const captionTopRight =
+ images[1].data.caption &&
+ `${removeLastFullStop(images[1].data.caption)} (top right). `;
+ const captionBottomLeft =
+ images[2].data.caption &&
+ `${removeLastFullStop(images[2].data.caption)} (bottom left). `;
+ const captionBottomRight =
+ images[3].data.caption &&
+ `${removeLastFullStop(images[3].data.caption)} (bottom right). `;
+ const captionToUse =
+ caption ||
+ `${captionTopLeft ?? ''}${captionTopRight ?? ''}${
+ captionBottomLeft ?? ''
+ }${captionBottomRight ?? ''}`;
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {!!captionToUse && (
+
-
-
-
-
-
-
+ );
+};
+
+const Slideshow = ({
+ images,
+ format,
+ caption,
+}: {
+ images: ImageBlockElement[];
+ format: ArticleFormat;
+ caption?: string;
+}) => {
+ const imagesForSlideshow = images.map((element) => {
+ /** Legacy images do not have a master so we fallback to the largest available */
+ const image =
+ getMaster(element.media.allImages) ??
+ getLargest(element.media.allImages);
+ return {
+ imageSrc: image?.url ?? '',
+ imageCaption: element.data.caption,
+ };
+ });
+ return (
+ <>
+
+
-
-
- {!!caption && (
-
- )}
-
-);
+
+ >
+ );
+};
export const MultiImageBlockComponent = ({
images,
format,
caption,
+ presentation,
}: Props) => {
- const [one, two, three, four] = images;
+ if (presentation && presentation === 'slideshow') {
+ return ;
+ } else {
+ const [one, two, three, four] = images;
- if (one && two && three && four) {
- return (
-
- );
- }
+ if (one && two && three && four) {
+ return (
+
+ );
+ }
- if (one && two && three) {
- return (
-
- );
- }
+ if (one && two && three) {
+ return (
+
+ );
+ }
- if (one && two) {
- return (
-
- );
- }
+ if (one && two) {
+ return (
+
+ );
+ }
- if (one) {
- return ;
- }
+ if (one) {
+ return (
+
+ );
+ }
- return null;
+ return null;
+ }
};
diff --git a/dotcom-rendering/src/frontend/schemas/feArticle.json b/dotcom-rendering/src/frontend/schemas/feArticle.json
index ba05d3e81f5..10868ad50cb 100644
--- a/dotcom-rendering/src/frontend/schemas/feArticle.json
+++ b/dotcom-rendering/src/frontend/schemas/feArticle.json
@@ -2935,6 +2935,14 @@
},
"role": {
"$ref": "#/definitions/RoleType"
+ },
+ "presentation": {
+ "enum": [
+ "side-by-side",
+ "slideshow",
+ "stacked"
+ ],
+ "type": "string"
}
},
"required": [
diff --git a/dotcom-rendering/src/lib/renderElement.tsx b/dotcom-rendering/src/lib/renderElement.tsx
index a04b2026e0a..1d39554cce3 100644
--- a/dotcom-rendering/src/lib/renderElement.tsx
+++ b/dotcom-rendering/src/lib/renderElement.tsx
@@ -568,6 +568,7 @@ export const renderElement = ({
key={index}
images={element.images}
caption={element.caption}
+ presentation={element.presentation}
/>
);
case 'model.dotcomrendering.pageElements.NewsletterSignupBlockElement':
diff --git a/dotcom-rendering/src/lib/thrift/nativeConnection.ts b/dotcom-rendering/src/lib/thrift/nativeConnection.ts
index 3b1ab0659f5..97e112b9508 100644
--- a/dotcom-rendering/src/lib/thrift/nativeConnection.ts
+++ b/dotcom-rendering/src/lib/thrift/nativeConnection.ts
@@ -124,7 +124,7 @@ export class NativeConnection extends ThriftConnection {
resolve: res,
reject: rej,
timeoutId: setTimeout(function () {
- connection.reset(id);
+ // connection.reset(id);
}, ACTION_TIMEOUT_MS),
});
const message: NativeMessage = {
diff --git a/dotcom-rendering/src/model/block-schema.json b/dotcom-rendering/src/model/block-schema.json
index 97c8187254a..0dfe9cba990 100644
--- a/dotcom-rendering/src/model/block-schema.json
+++ b/dotcom-rendering/src/model/block-schema.json
@@ -2423,6 +2423,14 @@
},
"role": {
"$ref": "#/definitions/RoleType"
+ },
+ "presentation": {
+ "enum": [
+ "side-by-side",
+ "slideshow",
+ "stacked"
+ ],
+ "type": "string"
}
},
"required": [
diff --git a/dotcom-rendering/src/model/enhance-images.ts b/dotcom-rendering/src/model/enhance-images.ts
index 44024de18db..36a4ed9b3b8 100644
--- a/dotcom-rendering/src/model/enhance-images.ts
+++ b/dotcom-rendering/src/model/enhance-images.ts
@@ -454,7 +454,7 @@ const enhance =
.addMultiImageElements()
// If any MultiImageBlockElement is followed by a ul/l caption, delete the special caption
// element and use the value for the multi image `caption` prop
- .addCaptionsToMultis()
+ // .addCaptionsToMultis()
.addImagePositions(imagesForLightbox).elements
);
};
diff --git a/dotcom-rendering/src/types/content.ts b/dotcom-rendering/src/types/content.ts
index 3fbd75dcc98..5fef2a8a838 100644
--- a/dotcom-rendering/src/types/content.ts
+++ b/dotcom-rendering/src/types/content.ts
@@ -464,6 +464,7 @@ export interface MultiImageBlockElement {
images: ImageBlockElement[];
caption?: string;
role?: RoleType;
+ presentation?: 'slideshow' | 'side-by-side' | 'stacked';
}
export interface NewsletterSignupBlockElement {