Skip to content

Mute other Looping Videos when playing audio #14142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions dotcom-rendering/src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ export type Props = {
avatarUrl?: string;
showClock?: boolean;
mainMedia?: MainMedia;
/** Note YouTube recommends a minimum width of 480px @see https://developers.google.com/youtube/terms/required-minimum-functionality#embedded-youtube-player-size
/**
* Note YouTube recommends a minimum width of 480px @see https://developers.google.com/youtube/terms/required-minimum-functionality#embedded-youtube-player-size
* At 300px or below, the player will begin to lose functionality e.g. volume controls being omitted.
* Youtube requires a minimum width 200px.
*/
Expand Down Expand Up @@ -133,8 +134,14 @@ export type Props = {
isTagPage?: boolean;
/** Allows the consumer to set an aspect ratio on the image of 5:3, 5:4, 4:5 or 1:1 */
aspectRatio?: AspectRatio;
/** The index of the card in a carousel */
index?: number;
/** The Splash card in a flexible container gets a different visual treatment to other cards*/
/**
* Useful for videos. Has the form: collection-{collection ID}-{card grouping type}-{card index}
* For example, the first splash card in the second collection would be: "collection-1-splash-0"
*/
uniqueId?: string;
/** The Splash card in a flexible container gets a different visual treatment to other cards */
isFlexSplash?: boolean;
showTopBarDesktop?: boolean;
showTopBarMobile?: boolean;
Expand Down Expand Up @@ -402,6 +409,7 @@ export const Card = ({
isTagPage = false,
aspectRatio,
index = 0,
uniqueId = '',
isFlexSplash,
showTopBarDesktop = true,
showTopBarMobile = true,
Expand Down Expand Up @@ -896,7 +904,6 @@ export const Card = ({
src={media.mainMedia.videoId}
height={media.mainMedia.height}
width={media.mainMedia.width}
videoId={media.mainMedia.videoId}
thumbnailImage={
media.mainMedia.thumbnailImage ?? ''
}
Expand All @@ -909,6 +916,7 @@ export const Card = ({
aspectRatio={aspectRatio}
/>
}
uniqueId={uniqueId}
/>
</Island>
)}
Expand Down
2 changes: 1 addition & 1 deletion dotcom-rendering/src/components/DecideContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export const DecideContainer = ({
collectionId,
containerLevel,
}: Props) => {
// If you add a new container type which contains an MPU, you must also add it to
switch (containerType) {
case 'dynamic/fast':
return (
Expand Down Expand Up @@ -255,6 +254,7 @@ export const DecideContainer = ({
absoluteServerTimes={absoluteServerTimes}
imageLoading={imageLoading}
aspectRatio={aspectRatio}
collectionId={collectionId}
/>
);
case 'flexible/general':
Expand Down
113 changes: 63 additions & 50 deletions dotcom-rendering/src/components/FlexibleGeneral.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ export const decideCardPositions = (cards: DCRFrontCard[]): GroupedCards => {
}, []);
};

type ImmersiveCardLayoutProps = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've extracted the Props out into their own types for a few components here, to meet convention.

card: DCRFrontCard;
containerPalette?: DCRContainerPalette;
absoluteServerTimes: boolean;
imageLoading: Loading;
collectionId: number;
};

/**
* ImmersiveCardLayout is a special case of the card layout that is used for cards with the isImmersive property.
* It is a single feature card that takes up the full width of the container on all breakpoints.
Expand All @@ -92,17 +100,11 @@ const ImmersiveCardLayout = ({
absoluteServerTimes,
imageLoading,
collectionId,
}: {
card: DCRFrontCard;
containerPalette?: DCRContainerPalette;
absoluteServerTimes: boolean;
imageLoading: Loading;
collectionId: number;
}) => {
}: ImmersiveCardLayoutProps) => {
const isLoopingVideo = card.mainMedia?.type === 'LoopVideo';

return (
<UL padBottom={true} key={card.url}>
<UL padBottom={true}>
Copy link
Contributor Author

@domlander domlander Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I misunderstood how React keys work in a previous PR. The should be added to the first child inside the map, even if that is a Component.

<LI padSides={true}>
<FeatureCard
collectionId={collectionId}
Expand Down Expand Up @@ -229,6 +231,18 @@ const decideSplashCardProperties = (
}
};

type SplashCardLayoutProps = {
cards: DCRFrontCard[];
imageLoading: Loading;
containerPalette?: DCRContainerPalette;
showAge?: boolean;
absoluteServerTimes: boolean;
aspectRatio: AspectRatio;
isLastRow: boolean;
containerLevel: DCRContainerLevel;
collectionId: number;
};

const SplashCardLayout = ({
cards,
containerPalette,
Expand All @@ -239,17 +253,7 @@ const SplashCardLayout = ({
isLastRow,
containerLevel,
collectionId,
}: {
cards: DCRFrontCard[];
imageLoading: Loading;
containerPalette?: DCRContainerPalette;
showAge?: boolean;
absoluteServerTimes: boolean;
aspectRatio: AspectRatio;
isLastRow: boolean;
containerLevel: DCRContainerLevel;
collectionId: number;
}) => {
}: SplashCardLayoutProps) => {
const card = cards[0];
if (!card) return null;

Expand Down Expand Up @@ -380,6 +384,19 @@ const decideCardProperties = (
}
};

type FullWidthCardLayoutProps = {
cards: DCRFrontCard[];
imageLoading: Loading;
containerPalette?: DCRContainerPalette;
showAge?: boolean;
absoluteServerTimes: boolean;
aspectRatio: AspectRatio;
isFirstRow: boolean;
isLastRow: boolean;
containerLevel: DCRContainerLevel;
collectionId: number;
};

const FullWidthCardLayout = ({
cards,
containerPalette,
Expand All @@ -391,18 +408,7 @@ const FullWidthCardLayout = ({
isLastRow,
containerLevel,
collectionId,
}: {
cards: DCRFrontCard[];
imageLoading: Loading;
containerPalette?: DCRContainerPalette;
showAge?: boolean;
absoluteServerTimes: boolean;
aspectRatio: AspectRatio;
isFirstRow: boolean;
isLastRow: boolean;
containerLevel: DCRContainerLevel;
collectionId: number;
}) => {
}: FullWidthCardLayoutProps) => {
const card = cards[0];
if (!card) return null;

Expand Down Expand Up @@ -436,7 +442,6 @@ const FullWidthCardLayout = ({
showTopBar={!isFirstRow}
padBottom={!isLastRow}
hasLargeSpacing={!isLastRow}
key={card.url}
>
<LI
padSides={true}
Expand Down Expand Up @@ -481,6 +486,19 @@ const FullWidthCardLayout = ({
);
};

type HalfWidthCardLayoutProps = {
cards: DCRFrontCard[];
imageLoading: Loading;
isFirstRow?: boolean;
isFirstStandardRow?: boolean;
containerPalette?: DCRContainerPalette;
showAge?: boolean;
absoluteServerTimes: boolean;
aspectRatio: AspectRatio;
isLastRow: boolean;
containerLevel: DCRContainerLevel;
};

const HalfWidthCardLayout = ({
cards,
containerPalette,
Expand All @@ -490,22 +508,9 @@ const HalfWidthCardLayout = ({
isFirstRow,
isFirstStandardRow,
aspectRatio,
row,
isLastRow,
containerLevel,
}: {
cards: DCRFrontCard[];
imageLoading: Loading;
isFirstRow?: boolean;
isFirstStandardRow?: boolean;
containerPalette?: DCRContainerPalette;
showAge?: boolean;
absoluteServerTimes: boolean;
aspectRatio: AspectRatio;
row: number;
isLastRow: boolean;
containerLevel: DCRContainerLevel;
}) => {
}: HalfWidthCardLayoutProps) => {
if (cards.length === 0) return null;

return (
Expand All @@ -516,7 +521,6 @@ const HalfWidthCardLayout = ({
showTopBar={!isFirstRow}
/** We use one full top bar for the first row and use a split one for subsequent rows */
splitTopBar={!isFirstStandardRow}
key={row}
>
{cards.map((card, cardIndex) => {
return (
Expand Down Expand Up @@ -577,8 +581,16 @@ export const FlexibleGeneral = ({
containerLevel = 'Primary',
collectionId,
}: Props) => {
const splash = [...groupedTrails.splash].slice(0, 1);
const cards = [...groupedTrails.standard].slice(0, 19);
const splash = [...groupedTrails.splash].slice(0, 1).map((snap) => ({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given how we store cards in separate groupings (e.g. splash) and find them from curated and backfill, it was very fiddly to apply a unique index above this component.

...snap,
uniqueId: `collection-${collectionId}-splash-0`,
}));
const cards = [...groupedTrails.standard]
.slice(0, 19)
.map((standard, i) => ({
...standard,
uniqueId: `collection-${collectionId}-standard-${i}`,
}));
const groupedCards = decideCardPositions(cards);

return (
Expand Down Expand Up @@ -612,6 +624,7 @@ export const FlexibleGeneral = ({
isLastRow={i === groupedCards.length - 1}
containerLevel={containerLevel}
collectionId={collectionId}
key={row.cards[0]?.uniqueId}
/>
);

Expand All @@ -628,9 +641,9 @@ export const FlexibleGeneral = ({
isFirstRow={!splash.length && i === 0}
isFirstStandardRow={i === 0}
aspectRatio={aspectRatio}
row={i + 1}
isLastRow={i === groupedCards.length - 1}
containerLevel={containerLevel}
key={row.cards[0]?.uniqueId}
/>
);
}
Expand Down
14 changes: 14 additions & 0 deletions dotcom-rendering/src/components/FlexibleSpecial.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export const One: Story = {
snap: [],
standard: trails.slice(0, 1),
},
collectionId: 1,
},
};
export const Two: Story = {
Expand All @@ -137,6 +138,7 @@ export const Two: Story = {
snap: [],
standard: trails.slice(0, 2),
},
collectionId: 1,
},
};
export const Three: Story = {
Expand All @@ -147,6 +149,7 @@ export const Three: Story = {
snap: [],
standard: trails.slice(0, 3),
},
collectionId: 1,
},
};
export const Four: Story = {
Expand All @@ -157,6 +160,7 @@ export const Four: Story = {
snap: [],
standard: trails.slice(0, 4),
},
collectionId: 1,
},
};
export const Five: Story = {
Expand All @@ -167,6 +171,7 @@ export const Five: Story = {
snap: [],
standard: trails.slice(0, 5),
},
collectionId: 1,
},
};
export const DefaultSplashWithImageSupression: Story = {
Expand All @@ -178,6 +183,7 @@ export const DefaultSplashWithImageSupression: Story = {
snap: [],
standard: [{ ...trails[0], image: undefined }],
},
collectionId: 1,
},
};

Expand All @@ -190,6 +196,7 @@ export const BoostedSplashWithImageSupression: Story = {
snap: [],
standard: [{ ...trails[0], boostLevel: 'boost', image: undefined }],
},
collectionId: 1,
},
};

Expand All @@ -204,6 +211,7 @@ export const MegaBoostedSplashWithImageSupression: Story = {
{ ...trails[0], boostLevel: 'megaboost', image: undefined },
],
},
collectionId: 1,
},
};

Expand All @@ -218,6 +226,7 @@ export const GigaBoostedSplashWithImageSupression: Story = {
{ ...trails[0], boostLevel: 'gigaboost', image: undefined },
],
},
collectionId: 1,
},
};

Expand All @@ -230,6 +239,7 @@ export const DefaultSplashWithLiveUpdates: Story = {
snap: [],
standard: [{ ...liveUpdatesCard }],
},
collectionId: 1,
},
};

Expand All @@ -242,6 +252,7 @@ export const BoostedSplashWithLiveUpdates: Story = {
snap: [],
standard: [{ ...liveUpdatesCard, boostLevel: 'boost' }],
},
collectionId: 1,
},
};

Expand All @@ -254,6 +265,7 @@ export const MegaBoostedSplashWithLiveUpdates: Story = {
snap: [],
standard: [{ ...liveUpdatesCard, boostLevel: 'megaboost' }],
},
collectionId: 1,
},
};

Expand All @@ -266,6 +278,7 @@ export const GigaBoostedSplashWithLiveUpdates: Story = {
snap: [],
standard: [{ ...liveUpdatesCard, boostLevel: 'gigaboost' }],
},
collectionId: 1,
},
};

Expand Down Expand Up @@ -293,6 +306,7 @@ export const WithSpecialPaletteVariations = {
snap: [],
standard: trails.slice(0, 5),
},
collectionId: 1,
},
render: (args) => (
<>
Expand Down
Loading