Skip to content

Commit 002c794

Browse files
authored
Merge pull request #14881 from guardian/doml/video-aspect-ratio
Display non-5:4 videos correctly
2 parents b2b8f56 + 64be71a commit 002c794

File tree

10 files changed

+136
-57
lines changed

10 files changed

+136
-57
lines changed

dotcom-rendering/fixtures/manual/trails.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ export const newsletterTrails: [DCRFrontCard, DCRFrontCard] = [
648648
},
649649
];
650650

651-
export const selfHostedVideoCard: DCRFrontCard = {
651+
export const selfHostedVideo54Card = {
652652
...defaultCardProps,
653653
dataLinkName: 'news | group-0 | card-@2',
654654
url: '/uk-news/2025/jan/22/prince-harry-says-sun-publisher-made-historic-admission-as-he-settles-case',
@@ -664,7 +664,7 @@ export const selfHostedVideoCard: DCRFrontCard = {
664664
src: 'https://uploads.guim.co.uk/2025%2F06%2F20%2Ftesting+only%2C+please+ignore--3cb22b60-2c3f-48d6-8bce-38c956907cce-3.mp4',
665665
},
666666
],
667-
duration: 0,
667+
duration: 30,
668668
width: 500,
669669
height: 400,
670670
image: 'https://media.guim.co.uk/6537e163c9164d25ec6102641f6a04fa5ba76560/0_210_5472_3283/master/5472.jpg',
@@ -673,7 +673,22 @@ export const selfHostedVideoCard: DCRFrontCard = {
673673
src: 'https://media.guim.co.uk/966bf085fb982b1103aaba42a812b09726cc0a3c/1417_104_1378_1104/master/1378.jpg',
674674
altText: 'Wyatt Russell and Florence Pugh in Thunderbolts*.',
675675
},
676-
};
676+
} satisfies DCRFrontCard;
677+
678+
export const selfHostedVerticalVideoCard = {
679+
...selfHostedVideo54Card,
680+
mainMedia: {
681+
...selfHostedVideo54Card.mainMedia,
682+
sources: [
683+
{
684+
mimeType: 'video/mp4',
685+
src: 'https://uploads.guimcode.co.uk/2025/11/12/5x4_test--ee49513c-bf16-4321-a444-09c9a037d584-4.0.mp4',
686+
},
687+
],
688+
width: 406,
689+
height: 720,
690+
},
691+
} satisfies DCRFrontCard;
677692

678693
export const slideshowCard: DCRFrontCard = {
679694
...defaultCardProps,

dotcom-rendering/src/components/FlexibleGeneral.stories.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
galleryTrails,
77
getSublinks,
88
opinionTrails,
9-
selfHostedVideoCard,
9+
selfHostedVerticalVideoCard,
10+
selfHostedVideo54Card,
1011
slideshowCard,
1112
trails,
1213
videoTrails,
@@ -542,14 +543,24 @@ export const ImmersiveCardsSplashAndStandard: Story = {
542543
},
543544
};
544545

545-
export const SelfHostedVideoCards: Story = {
546-
name: 'Self-hosted video cards',
546+
export const SelfHostedVideo5to4Cards: Story = {
547+
name: 'Self-hosted 5:4 video cards',
547548
args: {
548-
frontSectionTitle: 'Self-hosted video cards',
549+
frontSectionTitle: 'Self-hosted 5:4 video cards',
549550
groupedTrails: {
550551
...emptyGroupedTrails,
551-
splash: [selfHostedVideoCard],
552-
standard: [selfHostedVideoCard], // Self-hosted video is disabled at standard card size
552+
splash: [selfHostedVideo54Card],
553+
standard: [selfHostedVideo54Card], // Self-hosted video is disabled at standard card size
554+
},
555+
},
556+
};
557+
export const SelfHostedVerticalVideoCards: Story = {
558+
name: 'Self-hosted vertical video cards',
559+
args: {
560+
frontSectionTitle: 'Self-hosted vertical video cards',
561+
groupedTrails: {
562+
...emptyGroupedTrails,
563+
splash: [selfHostedVerticalVideoCard],
553564
},
554565
},
555566
};

dotcom-rendering/src/components/FlexibleSpecial.stories.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react-webpack5';
33
import { discussionApiUrl } from '../../fixtures/manual/discussionApiUrl';
44
import {
55
opinionTrails,
6-
selfHostedVideoCard,
6+
selfHostedVideo54Card,
77
slideshowCard,
88
snapLink,
99
trails,
@@ -287,7 +287,7 @@ export const SelfHostedVideoCard: Story = {
287287
groupedTrails: {
288288
...emptyGroupedTrails,
289289
snap: [],
290-
standard: [selfHostedVideoCard],
290+
standard: [selfHostedVideo54Card],
291291
},
292292
collectionId: 1,
293293
},

dotcom-rendering/src/components/SelfHostedVideo.importable.tsx

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { css } from '@emotion/react';
22
import { log, storage } from '@guardian/libs';
3-
import { space } from '@guardian/source/foundations';
3+
import { from, space } from '@guardian/source/foundations';
44
import { SvgAudio, SvgAudioMute } from '@guardian/source/react-components';
55
import { useCallback, useEffect, useRef, useState } from 'react';
66
import {
@@ -18,6 +18,7 @@ import {
1818
customSelfHostedVideoPlayAudioEventName,
1919
customYoutubePlayEventName,
2020
} from '../lib/video';
21+
import { palette } from '../palette';
2122
import type { VideoPlayerFormat } from '../types/mainMedia';
2223
import { CardPicture, type Props as CardPictureProps } from './CardPicture';
2324
import { useConfig } from './ConfigContext';
@@ -29,9 +30,23 @@ import type {
2930
import { SelfHostedVideoPlayer } from './SelfHostedVideoPlayer';
3031
import { ophanTrackerWeb } from './YoutubeAtom/eventEmitters';
3132

32-
const videoContainerStyles = css`
33+
const videoAndBackgroundStyles = css`
34+
position: relative;
35+
display: flex;
36+
justify-content: space-around;
3337
z-index: ${getZIndex('video-container')};
38+
background-color: ${palette('--video-background')};
39+
`;
40+
41+
const videoContainerStyles = (width: number, height: number) => css`
3442
position: relative;
43+
height: 100%;
44+
max-height: 100vh;
45+
max-height: 100svh;
46+
max-width: 100%;
47+
${from.tablet} {
48+
max-width: ${(width / height) * 80}%;
49+
}
3550
`;
3651

3752
const cinemagraphContainerStyles = css`
@@ -662,45 +677,47 @@ export const SelfHostedVideo = ({
662677
: undefined;
663678

664679
return (
665-
<figure
666-
ref={setNode}
667-
css={[
668-
videoContainerStyles,
669-
isCinemagraph && cinemagraphContainerStyles,
670-
]}
671-
className={`video-container ${videoStyle.toLocaleLowerCase()}`}
672-
data-component="gu-video-loop"
673-
>
674-
<SelfHostedVideoPlayer
675-
sources={sources}
676-
atomId={atomId}
677-
uniqueId={uniqueId}
678-
width={width}
679-
height={height}
680-
videoStyle={videoStyle}
681-
posterImage={optimisedPosterImage}
682-
FallbackImageComponent={FallbackImageComponent}
683-
currentTime={currentTime}
684-
setCurrentTime={setCurrentTime}
685-
ref={vidRef}
686-
isPlayable={isPlayable}
687-
playerState={playerState}
688-
isMuted={isMuted}
689-
handleLoadedMetadata={handleLoadedMetadata}
690-
handleLoadedData={handleLoadedData}
691-
handleCanPlay={handleCanPlay}
692-
handlePlayPauseClick={handlePlayPauseClick}
693-
handleAudioClick={handleAudioClick}
694-
handleKeyDown={handleKeyDown}
695-
handlePause={handlePause}
696-
onError={onError}
697-
AudioIcon={hasAudio ? AudioIcon : null}
698-
preloadPartialData={preloadPartialData}
699-
showPlayIcon={showPlayIcon}
700-
subtitleSize={subtitleSize}
701-
subtitleSource={subtitleSource}
702-
activeCue={activeCue}
703-
/>
704-
</figure>
680+
<div css={videoAndBackgroundStyles} className="loop-video-container">
681+
<figure
682+
ref={setNode}
683+
css={[
684+
videoContainerStyles(width, height),
685+
isCinemagraph && cinemagraphContainerStyles,
686+
]}
687+
className={`video-container ${videoStyle.toLocaleLowerCase()}`}
688+
data-component="gu-video-loop"
689+
>
690+
<SelfHostedVideoPlayer
691+
sources={sources}
692+
atomId={atomId}
693+
uniqueId={uniqueId}
694+
width={width}
695+
height={height}
696+
videoStyle={videoStyle}
697+
posterImage={optimisedPosterImage}
698+
FallbackImageComponent={FallbackImageComponent}
699+
currentTime={currentTime}
700+
setCurrentTime={setCurrentTime}
701+
ref={vidRef}
702+
isPlayable={isPlayable}
703+
playerState={playerState}
704+
isMuted={isMuted}
705+
handleLoadedMetadata={handleLoadedMetadata}
706+
handleLoadedData={handleLoadedData}
707+
handleCanPlay={handleCanPlay}
708+
handlePlayPauseClick={handlePlayPauseClick}
709+
handleAudioClick={handleAudioClick}
710+
handleKeyDown={handleKeyDown}
711+
handlePause={handlePause}
712+
onError={onError}
713+
AudioIcon={hasAudio ? AudioIcon : null}
714+
preloadPartialData={preloadPartialData}
715+
showPlayIcon={showPlayIcon}
716+
subtitleSource={subtitleSource}
717+
subtitleSize={subtitleSize}
718+
activeCue={activeCue}
719+
/>
720+
</figure>
721+
</div>
705722
);
706723
};

dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ const videoStyles = (width: number, height: number) => css`
3131
cursor: pointer;
3232
/* Prevents CLS by letting the browser know the space the video will take up. */
3333
aspect-ratio: ${width} / ${height};
34-
object-fit: cover;
3534
`;
3635

3736
const subtitleStyles = (subtitleSize: SubtitleSize | undefined) => css`

dotcom-rendering/src/frontend/feFront.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ export interface FEMediaAtom {
128128
activeVersion?: number;
129129
videoPlayerFormat?: 'Default' | 'Loop' | 'Cinemagraph';
130130
// channelId?: string; // currently unused
131+
dimensions?: {
132+
width: number;
133+
height: number;
134+
};
131135
}
132136

133137
export type FEFrontCard = {

dotcom-rendering/src/frontend/schemas/feFront.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3247,6 +3247,21 @@
32473247
"Loop"
32483248
],
32493249
"type": "string"
3250+
},
3251+
"dimensions": {
3252+
"type": "object",
3253+
"properties": {
3254+
"width": {
3255+
"type": "number"
3256+
},
3257+
"height": {
3258+
"type": "number"
3259+
}
3260+
},
3261+
"required": [
3262+
"height",
3263+
"width"
3264+
]
32503265
}
32513266
},
32523267
"required": [

dotcom-rendering/src/frontend/schemas/feTagPage.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,21 @@
14201420
"Loop"
14211421
],
14221422
"type": "string"
1423+
},
1424+
"dimensions": {
1425+
"type": "object",
1426+
"properties": {
1427+
"width": {
1428+
"type": "number"
1429+
},
1430+
"height": {
1431+
"type": "number"
1432+
}
1433+
},
1434+
"required": [
1435+
"height",
1436+
"width"
1437+
]
14231438
}
14241439
},
14251440
"required": [

dotcom-rendering/src/model/enhanceCards.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,8 @@ export const getActiveMediaAtom = (
249249
})),
250250
subtitleSource: subtitleAsset?.id,
251251
duration: mediaAtom.duration ?? 0,
252-
// Size fixed to a 5:4 ratio
253-
width: 500,
254-
height: 400,
252+
width: mediaAtom.dimensions?.width ?? 500,
253+
height: mediaAtom.dimensions?.height ?? 400,
255254
image,
256255
};
257256
}

dotcom-rendering/src/paletteDeclarations.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8137,6 +8137,10 @@ const paletteColours = {
81378137
light: () => sourcePalette.neutral[60],
81388138
dark: () => sourcePalette.neutral[60],
81398139
},
8140+
'--video-background': {
8141+
light: () => sourcePalette.neutral[93],
8142+
dark: () => sourcePalette.neutral[93],
8143+
},
81408144
'--video-progress-bar-background': {
81418145
light: () => transparentColour(sourcePalette.neutral[7], 0.7),
81428146
dark: () => transparentColour(sourcePalette.neutral[7], 0.7),

0 commit comments

Comments
 (0)