diff --git a/dotcom-rendering/fixtures/manual/trails.ts b/dotcom-rendering/fixtures/manual/trails.ts index abe12789ff0..f6d67f6bc81 100644 --- a/dotcom-rendering/fixtures/manual/trails.ts +++ b/dotcom-rendering/fixtures/manual/trails.ts @@ -648,7 +648,7 @@ export const newsletterTrails: [DCRFrontCard, DCRFrontCard] = [ }, ]; -export const loopVideoCard: DCRFrontCard = { +export const selfHostedVideoCard: DCRFrontCard = { ...defaultCardProps, dataLinkName: 'news | group-0 | card-@2', url: '/uk-news/2025/jan/22/prince-harry-says-sun-publisher-made-historic-admission-as-he-settles-case', diff --git a/dotcom-rendering/src/components/Card/Card.tsx b/dotcom-rendering/src/components/Card/Card.tsx index 87a9dd8608b..baf40d9c4ee 100644 --- a/dotcom-rendering/src/components/Card/Card.tsx +++ b/dotcom-rendering/src/components/Card/Card.tsx @@ -42,9 +42,9 @@ import type { Loading } from '../CardPicture'; import { CardPicture } from '../CardPicture'; import { Island } from '../Island'; import { LatestLinks } from '../LatestLinks.importable'; -import { LoopVideo } from '../LoopVideo.importable'; -import type { SubtitleSize } from '../LoopVideoPlayer'; import { Pill } from '../Pill'; +import { SelfHostedVideo } from '../SelfHostedVideo.importable'; +import type { SubtitleSize } from '../SelfHostedVideoPlayer'; import { SlideshowCarousel } from '../SlideshowCarousel.importable'; import { Snap } from '../Snap'; import { SnapCssSandbox } from '../SnapCssSandbox'; @@ -946,7 +946,7 @@ export const Card = ({ priority="critical" defer={{ until: 'visible' }} > - { document.dispatchEvent( - new CustomEvent(customLoopPlayAudioEventName, { + new CustomEvent(customSelfHostedVideoPlayAudioEventName, { detail: { uniqueId }, }), ); }; const logAndReportError = (src: string, error: Error) => { - const message = `Autoplay failure for loop video. Source: ${src} could not be played. Error: ${String( + const message = `Autoplay failure for self-hosted video. Source: ${src} could not be played. Error: ${String( error, )}`; if (error instanceof Error) { window.guardian.modules.sentry.reportError( new Error(message), - 'loop-video', + 'self-hosted-video', ); } @@ -72,7 +72,7 @@ const getOptimisedPosterImage = (mainImage: string): string => { return generateImageURL({ mainImage, - imageWidth: 940, // The widest a looping video can be: Flexible special, giga-boosted + imageWidth: 940, // The widest a video can be: flexible special container, giga-boosted slot resolution, aspectRatio: '5:4', }); @@ -95,7 +95,7 @@ const doesVideoHaveAudio = (video: HTMLVideoElement): boolean => { new Error( 'Could not determine if video has audio. This is likely due to the browser not supporting the necessary properties.', ), - 'loop-video', + 'self-hosted-video', ); return true; @@ -127,7 +127,7 @@ type Props = { subtitleSize: SubtitleSize; }; -export const LoopVideo = ({ +export const SelfHostedVideo = ({ sources, atomId, uniqueId, @@ -321,7 +321,7 @@ export const LoopVideo = ({ }; document.addEventListener( - customLoopPlayAudioEventName, + customSelfHostedVideoPlayAudioEventName, handleCustomPlayAudioEvent, ); document.addEventListener( @@ -339,7 +339,7 @@ export const LoopVideo = ({ return () => { document.removeEventListener( - customLoopPlayAudioEventName, + customSelfHostedVideoPlayAudioEventName, handleCustomPlayAudioEvent, ); document.removeEventListener( @@ -573,13 +573,13 @@ export const LoopVideo = ({ * Sentry and log in the console. */ const onError = () => { - const message = `Loop video could not be played. source: ${ + const message = `Self-hosted video could not be played. source: ${ vidRef.current?.currentSrc ?? 'unknown' }`; window.guardian.modules.sentry.reportError( new Error(message), - 'loop-video', + 'self-hosted-video', ); log('dotcom', message); }; @@ -643,10 +643,10 @@ export const LoopVideo = ({
- , + render: (args) => , parameters: { chromatic: { viewports: [breakpoints.mobile, breakpoints.wide], disableSnapshot: true, }, }, -} satisfies Meta; +} satisfies Meta; export default meta; -type Story = StoryObj; +type Story = StoryObj; -export const Default: Story = { - name: 'Default', +export const Loop4to5: Story = { + name: 'Looping video in 4:5 aspect ratio', args: { sources: [ { @@ -56,10 +56,10 @@ export const Default: Story = { // }, // }; -export const Without5to4Ratio: Story = { - name: 'Without 5:4 aspect ratio', +export const Loop16to9: Story = { + name: 'Looping video in 16:9 aspect ratio', args: { - ...Default.args, + ...Loop4to5.args, sources: [ { src: 'https://uploads.guim.co.uk/2024/10/01/241001HeleneLoop_2.mp4', @@ -72,11 +72,11 @@ export const Without5to4Ratio: Story = { }; export const PausePlay: Story = { - ...Default, + ...Loop4to5, name: 'Pause and play interaction', play: async ({ canvasElement }) => { const canvas = within(canvasElement); - const videoEl = canvas.getByTestId('loop-video'); + const videoEl = canvas.getByTestId('self-hosted-video-player'); await userEvent.click(videoEl, { delay: 300, // Allow video to start playing. @@ -93,7 +93,7 @@ export const PausePlay: Story = { }; export const UnmuteMute: Story = { - ...Default, + ...Loop4to5, name: 'Unmute and mute interaction', parameters: { test: { @@ -120,11 +120,11 @@ function sleep(ms: number) { } export const InteractionObserver: Story = { - ...Default, + ...Loop4to5, name: 'Interaction observer', render: (args) => (
- +

End of page

diff --git a/dotcom-rendering/src/components/LoopVideoPlayer.tsx b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx similarity index 91% rename from dotcom-rendering/src/components/LoopVideoPlayer.tsx rename to dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx index d975e7bb45f..ab8015ce76b 100644 --- a/dotcom-rendering/src/components/LoopVideoPlayer.tsx +++ b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx @@ -17,8 +17,8 @@ import type { ActiveCue } from '../lib/useSubtitles'; import type { Source } from '../lib/video'; import { palette } from '../palette'; import { narrowPlayIconWidth, PlayIcon } from './Card/components/PlayIcon'; -import { LoopVideoProgressBar } from './LoopVideoProgressBar'; import { SubtitleOverlay } from './SubtitleOverlay'; +import { VideoProgressBar } from './VideoProgressBar'; export type SubtitleSize = 'small' | 'medium' | 'large'; @@ -40,7 +40,7 @@ const videoStyles = ( /* Hide the cue by default as we prefer custom overlay */ visibility: hidden; - color: ${palette('--loop-video-subtitle-text')}; + color: ${palette('--video-subtitle-text')}; ${subtitleSize === 'small' && textSans15}; ${subtitleSize === 'medium' && textSans17}; ${subtitleSize === 'large' && textSans20}; @@ -75,9 +75,9 @@ const audioIconContainerStyles = css` display: flex; justify-content: center; align-items: center; - background-color: ${palette('--loop-video-audio-icon-background')}; + background-color: ${palette('--video-audio-icon-background')}; border-radius: 50%; - border: 1px solid ${palette('--loop-video-audio-icon-border')}; + border: 1px solid ${palette('--video-audio-icon-border')}; `; export const PLAYER_STATES = [ @@ -132,11 +132,11 @@ type Props = { * https://react.dev/reference/react/forwardRef */ /** - * NB: To develop the loop video player locally, use `https://r.thegulocal.com/` instead of `localhost`. + * NB: To develop the video player locally, use `https://r.thegulocal.com/` instead of `localhost`. * This is required because CORS restrictions prevent accessing the subtitles and video file from localhost. */ -export const LoopVideoPlayer = forwardRef( +export const SelfHostedVideoPlayer = forwardRef( ( { sources, @@ -168,17 +168,18 @@ export const LoopVideoPlayer = forwardRef( }: Props, ref: React.ForwardedRef, ) => { - const loopVideoId = `loop-video-${uniqueId}`; + const videoId = `video-${uniqueId}`; + return ( <> {/* eslint-disable-next-line jsx-a11y/media-has-caption -- Captions will be considered later. */}