From 101c4ff35c11280469a3a88c7a8ca94f566fd6e9 Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Thu, 18 Jun 2026 13:04:52 +0100 Subject: [PATCH 1/5] Add picture index in Hosted Gallery --- .../src/components/GalleryCaption.tsx | 28 ++++++++++++++++--- .../src/components/GalleryImage.tsx | 3 ++ .../src/layouts/HostedGalleryLayout.tsx | 1 + 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/dotcom-rendering/src/components/GalleryCaption.tsx b/dotcom-rendering/src/components/GalleryCaption.tsx index b932f99459a..79b9fca80aa 100644 --- a/dotcom-rendering/src/components/GalleryCaption.tsx +++ b/dotcom-rendering/src/components/GalleryCaption.tsx @@ -1,5 +1,11 @@ import { css } from '@emotion/react'; -import { between, from, space, textSans14 } from '@guardian/source/foundations'; +import { + between, + from, + space, + textSans14, + textSans15, +} from '@guardian/source/foundations'; import { grid } from '../grid'; import { ArticleDesign, type ArticleFormat } from '../lib/articleFormat'; import { palette } from '../palette'; @@ -16,6 +22,7 @@ type Props = { webTitle: string; /** Position of the image in the gallery used to build share fragment */ position?: number; + imagesLength?: number; }; const styles = css` @@ -46,12 +53,12 @@ export const GalleryCaption = ({ pageId, webTitle, position, + imagesLength, }: Props) => { const emptyCaption = captionHtml === undefined || captionHtml.trim() === ''; const hideCredit = displayCredit === false || credit === undefined || credit === ''; - const shouldIncludeShareButton = - format.design !== ArticleDesign.HostedGallery; + const isHostedGallery = format.design === ArticleDesign.HostedGallery; if (emptyCaption && hideCredit) { return null; @@ -59,6 +66,19 @@ export const GalleryCaption = ({ return (
+ {isHostedGallery && + typeof position === 'number' && + imagesLength !== undefined ? ( + + {position - 1}/{imagesLength} + + ) : null} {emptyCaption ? null : } {hideCredit ? null : ( )} - {shouldIncludeShareButton && ( + {!isHostedGallery && (
{ const asset = getImage(image.media.allImages); @@ -138,6 +140,7 @@ export const GalleryImage = ({ pageId={pageId} webTitle={webTitle} position={image.position} + imagesLength={imagesLength} /> ); diff --git a/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx b/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx index 0670496af5b..652de79974a 100644 --- a/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx +++ b/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx @@ -222,6 +222,7 @@ const GalleryBody = (props: { webTitle={props.webTitle} renderingTarget={props.renderingTarget} key={element.elementId} + imagesLength={props.bodyElements.length} /> ); } else { From ad4c57beb65b1d87354a4d6b7d2c7dfbd67372e8 Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Mon, 22 Jun 2026 08:19:10 +0100 Subject: [PATCH 2/5] Add a comment for the position substraction for clarity --- dotcom-rendering/src/components/GalleryCaption.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/dotcom-rendering/src/components/GalleryCaption.tsx b/dotcom-rendering/src/components/GalleryCaption.tsx index 79b9fca80aa..dea9e66c58a 100644 --- a/dotcom-rendering/src/components/GalleryCaption.tsx +++ b/dotcom-rendering/src/components/GalleryCaption.tsx @@ -76,6 +76,7 @@ export const GalleryCaption = ({ padding: ${space[2]}px 0 ${space[1]}px; `} > + {/* Gallery caption hashes use a 1-offset position (first image maps to "img-2"), so subtract 1 to show the expected hosted gallery index. */} {position - 1}/{imagesLength} ) : null} From 6b70f731f47ff192c51e6a0d2475f1675efddc5b Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Mon, 22 Jun 2026 10:03:36 +0100 Subject: [PATCH 3/5] Refactor to have more robust solution --- dotcom-rendering/src/components/GalleryCaption.tsx | 7 ++++--- dotcom-rendering/src/components/GalleryImage.tsx | 14 ++++++++++---- .../src/layouts/HostedGalleryLayout.tsx | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dotcom-rendering/src/components/GalleryCaption.tsx b/dotcom-rendering/src/components/GalleryCaption.tsx index dea9e66c58a..b93c24c4c0b 100644 --- a/dotcom-rendering/src/components/GalleryCaption.tsx +++ b/dotcom-rendering/src/components/GalleryCaption.tsx @@ -23,6 +23,7 @@ type Props = { /** Position of the image in the gallery used to build share fragment */ position?: number; imagesLength?: number; + imageIndex?: number; }; const styles = css` @@ -54,6 +55,7 @@ export const GalleryCaption = ({ webTitle, position, imagesLength, + imageIndex, }: Props) => { const emptyCaption = captionHtml === undefined || captionHtml.trim() === ''; const hideCredit = @@ -67,7 +69,7 @@ export const GalleryCaption = ({ return (
{isHostedGallery && - typeof position === 'number' && + imageIndex !== undefined && imagesLength !== undefined ? ( - {/* Gallery caption hashes use a 1-offset position (first image maps to "img-2"), so subtract 1 to show the expected hosted gallery index. */} - {position - 1}/{imagesLength} + {imageIndex + 1}/{imagesLength} ) : null} {emptyCaption ? null : } diff --git a/dotcom-rendering/src/components/GalleryImage.tsx b/dotcom-rendering/src/components/GalleryImage.tsx index 6e5eecea425..b533ccc472b 100644 --- a/dotcom-rendering/src/components/GalleryImage.tsx +++ b/dotcom-rendering/src/components/GalleryImage.tsx @@ -5,7 +5,10 @@ import { grid } from '../grid'; import { type ArticleFormat } from '../lib/articleFormat'; import { getImage } from '../lib/image'; import { palette } from '../palette'; -import { type ImageBlockElement } from '../types/content'; +import type { + AdPlaceholderBlockElement, + ImageBlockElement, +} from '../types/content'; import { type RenderingTarget } from '../types/renderingTarget'; import { AppsLightboxImage } from './AppsLightboxImage.island'; import { GalleryCaption } from './GalleryCaption'; @@ -19,7 +22,7 @@ type Props = { pageId: string; webTitle: string; renderingTarget: RenderingTarget; - imagesLength?: number; + images?: (ImageBlockElement | AdPlaceholderBlockElement)[]; }; const styles = css` @@ -71,7 +74,7 @@ export const GalleryImage = ({ pageId, webTitle, renderingTarget, - imagesLength, + images, }: Props) => { const asset = getImage(image.media.allImages); @@ -86,6 +89,8 @@ export const GalleryImage = ({ return null; } + const imageIndex = images?.indexOf(image); + return (
); diff --git a/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx b/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx index 652de79974a..8a7c88fe305 100644 --- a/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx +++ b/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx @@ -222,7 +222,7 @@ const GalleryBody = (props: { webTitle={props.webTitle} renderingTarget={props.renderingTarget} key={element.elementId} - imagesLength={props.bodyElements.length} + images={props.bodyElements} /> ); } else { From 0197c9f2e6359bcc3da9666f215a68be6a983bfb Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Tue, 23 Jun 2026 12:45:27 +0100 Subject: [PATCH 4/5] Re-add the use of position after the changes made to omit MainMedia --- dotcom-rendering/src/components/GalleryCaption.tsx | 7 +++---- dotcom-rendering/src/components/GalleryImage.tsx | 14 ++++---------- .../src/layouts/HostedGalleryLayout.tsx | 3 ++- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/dotcom-rendering/src/components/GalleryCaption.tsx b/dotcom-rendering/src/components/GalleryCaption.tsx index b93c24c4c0b..7e44cd87dad 100644 --- a/dotcom-rendering/src/components/GalleryCaption.tsx +++ b/dotcom-rendering/src/components/GalleryCaption.tsx @@ -22,8 +22,8 @@ type Props = { webTitle: string; /** Position of the image in the gallery used to build share fragment */ position?: number; + // Pass the total number of images from Hosted Gallery to include in the image caption (e.g. 1/5, 2/5, etc.) imagesLength?: number; - imageIndex?: number; }; const styles = css` @@ -55,7 +55,6 @@ export const GalleryCaption = ({ webTitle, position, imagesLength, - imageIndex, }: Props) => { const emptyCaption = captionHtml === undefined || captionHtml.trim() === ''; const hideCredit = @@ -69,7 +68,7 @@ export const GalleryCaption = ({ return (
{isHostedGallery && - imageIndex !== undefined && + typeof position === 'number' && imagesLength !== undefined ? ( - {imageIndex + 1}/{imagesLength} + {position}/{imagesLength} ) : null} {emptyCaption ? null : } diff --git a/dotcom-rendering/src/components/GalleryImage.tsx b/dotcom-rendering/src/components/GalleryImage.tsx index b533ccc472b..63bc52b8aa9 100644 --- a/dotcom-rendering/src/components/GalleryImage.tsx +++ b/dotcom-rendering/src/components/GalleryImage.tsx @@ -5,10 +5,7 @@ import { grid } from '../grid'; import { type ArticleFormat } from '../lib/articleFormat'; import { getImage } from '../lib/image'; import { palette } from '../palette'; -import type { - AdPlaceholderBlockElement, - ImageBlockElement, -} from '../types/content'; +import type { ImageBlockElement } from '../types/content'; import { type RenderingTarget } from '../types/renderingTarget'; import { AppsLightboxImage } from './AppsLightboxImage.island'; import { GalleryCaption } from './GalleryCaption'; @@ -22,7 +19,7 @@ type Props = { pageId: string; webTitle: string; renderingTarget: RenderingTarget; - images?: (ImageBlockElement | AdPlaceholderBlockElement)[]; + imagesLength?: number; }; const styles = css` @@ -74,7 +71,7 @@ export const GalleryImage = ({ pageId, webTitle, renderingTarget, - images, + imagesLength, }: Props) => { const asset = getImage(image.media.allImages); @@ -89,8 +86,6 @@ export const GalleryImage = ({ return null; } - const imageIndex = images?.indexOf(image); - return (
); diff --git a/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx b/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx index 8a7c88fe305..84c578117ab 100644 --- a/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx +++ b/dotcom-rendering/src/layouts/HostedGalleryLayout.tsx @@ -222,7 +222,8 @@ const GalleryBody = (props: { webTitle={props.webTitle} renderingTarget={props.renderingTarget} key={element.elementId} - images={props.bodyElements} + // Pass the total number of images to include in the image caption (e.g. 1/5, 2/5, etc.) + imagesLength={props.bodyElements.length} /> ); } else { From 3b30a61c955a404958ad7e1fb0cc44e1d7946b78 Mon Sep 17 00:00:00 2001 From: Dina Hafez Date: Tue, 23 Jun 2026 13:58:56 +0100 Subject: [PATCH 5/5] Update dotcom-rendering/src/components/GalleryCaption.tsx Co-authored-by: Charlotte <43961396+cemms1@users.noreply.github.com> --- dotcom-rendering/src/components/GalleryCaption.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotcom-rendering/src/components/GalleryCaption.tsx b/dotcom-rendering/src/components/GalleryCaption.tsx index 7e44cd87dad..798d3693018 100644 --- a/dotcom-rendering/src/components/GalleryCaption.tsx +++ b/dotcom-rendering/src/components/GalleryCaption.tsx @@ -69,7 +69,7 @@ export const GalleryCaption = ({
{isHostedGallery && typeof position === 'number' && - imagesLength !== undefined ? ( + !!imagesLength ? (