@@ -24,11 +24,12 @@ import type {
2424 DCRFrontImage ,
2525 DCRSupportingContent ,
2626} from '../types/front' ;
27- import type { MainMedia } from '../types/mainMedia' ;
27+ import type { MainMedia , YoutubeVideo } from '../types/mainMedia' ;
2828import { BrandingLabel } from './BrandingLabel' ;
2929import { CardFooter } from './Card/components/CardFooter' ;
3030import { CardLink } from './Card/components/CardLink' ;
3131import type { MediaSizeType } from './Card/components/MediaWrapper' ;
32+ import { narrowPlayIconDiameter , PlayIcon } from './Card/components/PlayIcon' ;
3233import { TrailText } from './Card/components/TrailText' ;
3334import { CardHeadline , type ResponsiveFontSize } from './CardHeadline' ;
3435import type { Loading } from './CardPicture' ;
@@ -38,7 +39,6 @@ import { FeatureCardCardAge } from './FeatureCardCardAge';
3839import { FeatureCardCommentCount } from './FeatureCardCommentCount' ;
3940import { FormatBoundary } from './FormatBoundary' ;
4041import { Island } from './Island' ;
41- import { MediaDuration } from './MediaDuration' ;
4242import { Pill } from './Pill' ;
4343import { StarRating } from './StarRating/StarRating' ;
4444import { SupportingContent } from './SupportingContent' ;
@@ -47,6 +47,17 @@ import { YoutubeBlockComponent } from './YoutubeBlockComponent.importable';
4747
4848export type Position = 'inner' | 'outer' | 'none' ;
4949
50+ type Media =
51+ | {
52+ type : 'picture' ;
53+ imageUrl : string ;
54+ imageAltText ?: string ;
55+ }
56+ | {
57+ type : 'youtube-video' ;
58+ mainMedia : YoutubeVideo ;
59+ } ;
60+
5061const baseCardStyles = css `
5162 display : flex;
5263 flex-direction : column;
@@ -224,6 +235,12 @@ const videoPillStyles = css`
224235 right : ${ space [ 2 ] } px;
225236` ;
226237
238+ const playIconStyles = css `
239+ position : absolute;
240+ top : calc (50% - ${ narrowPlayIconDiameter / 2 } px);
241+ left : calc (50% - ${ narrowPlayIconDiameter / 2 } px);
242+ ` ;
243+
227244const waveformStyles = css `
228245 position : absolute;
229246 bottom : 0 ;
@@ -239,16 +256,18 @@ const getMedia = ({
239256 imageUrl,
240257 imageAltText,
241258 mainMedia,
242- canPlayInline,
259+ isVideoArticle,
260+ showVideo,
243261} : {
244262 imageUrl ?: string ;
245263 imageAltText ?: string ;
246264 mainMedia ?: MainMedia ;
247- canPlayInline ?: boolean ;
248- } ) => {
249- if ( mainMedia && mainMedia . type === 'YoutubeVideo' && canPlayInline ) {
265+ isVideoArticle : boolean ;
266+ showVideo ?: boolean ;
267+ } ) : Media | undefined => {
268+ if ( isVideoArticle && mainMedia ?. type === 'YoutubeVideo' && showVideo ) {
250269 return {
251- type : 'video' ,
270+ type : 'youtube- video' ,
252271 mainMedia,
253272 } as const ;
254273 }
@@ -360,7 +379,7 @@ export const FeatureCard = ({
360379 imageLoading,
361380 showClock,
362381 mainMedia,
363- canPlayInline,
382+ canPlayInline = false ,
364383 kickerText,
365384 showPulsingDot,
366385 dataLinkName,
@@ -383,22 +402,16 @@ export const FeatureCard = ({
383402} : Props ) => {
384403 const hasSublinks = supportingContent && supportingContent . length > 0 ;
385404
386- const isVideoMainMedia = mainMedia ?. type === 'YoutubeVideo' ;
387405 const isVideoArticle = format . design === ArticleDesign . Video ;
388406
389- const videoDuration =
390- mainMedia ?. type === 'YoutubeVideo' ? mainMedia . duration : undefined ;
391-
392407 const media = getMedia ( {
393408 imageUrl : image ?. src ,
394409 imageAltText : image ?. altText ,
395410 mainMedia,
396- canPlayInline,
411+ isVideoArticle,
412+ showVideo : showVideo && canPlayInline ,
397413 } ) ;
398414
399- const showYoutubeVideo =
400- canPlayInline && showVideo && mainMedia ?. type === 'YoutubeVideo' ;
401-
402415 const showCardAge =
403416 webPublicationDate !== undefined && showClock !== undefined ;
404417
@@ -413,11 +426,13 @@ export const FeatureCard = ({
413426
414427 const isLabs = format . theme === ArticleSpecial . Labs ;
415428
429+ if ( ! media ) return null ;
430+
416431 return (
417432 < FormatBoundary format = { format } >
418433 < ContainerOverrides containerPalette = { containerPalette } >
419434 < div css = { [ baseCardStyles , hoverStyles , sublinkHoverStyles ] } >
420- { ! showYoutubeVideo && (
435+ { media . type !== 'youtube-video' && (
421436 < CardLink
422437 linkTo = { linkTo }
423438 headlineText = { headlineText }
@@ -426,7 +441,7 @@ export const FeatureCard = ({
426441 />
427442 ) }
428443 < div css = { contentStyles } >
429- { showYoutubeVideo && (
444+ { media . type === 'youtube-video' && (
430445 < div
431446 data-chromatic = "ignore"
432447 data-component = "youtube-atom"
@@ -441,15 +456,15 @@ export const FeatureCard = ({
441456 defer = { { until : 'visible' } }
442457 >
443458 < YoutubeBlockComponent
444- id = { mainMedia . id }
445- assetId = { mainMedia . videoId }
459+ id = { media . mainMedia . id }
460+ assetId = { media . mainMedia . videoId }
446461 index = { collectionId }
447- expired = { mainMedia . expired }
462+ expired = { media . mainMedia . expired }
448463 format = { format }
449464 stickyVideos = { false }
450465 enableAds = { false }
451- duration = { mainMedia . duration }
452- posterImage = { mainMedia . image }
466+ duration = { media . mainMedia . duration }
467+ posterImage = { media . mainMedia . image }
453468 width = { 300 }
454469 height = { 375 }
455470 origin = "The Guardian"
@@ -481,7 +496,7 @@ export const FeatureCard = ({
481496 </ Island >
482497 </ div >
483498 ) }
484- { ! showYoutubeVideo && media && (
499+ { media . type !== 'youtube-video' && (
485500 < div
486501 css = { css `
487502 position : relative;
@@ -490,23 +505,7 @@ export const FeatureCard = ({
490505 ) } ;
491506 ` }
492507 >
493- { media . type === 'video' && (
494- < div >
495- < CardPicture
496- mainImage = {
497- media . mainMedia . image ?? ''
498- }
499- imageSize = { imageSize }
500- alt = { headlineText }
501- loading = { imageLoading }
502- aspectRatio = { aspectRatio }
503- mobileAspectRatio = {
504- mobileAspectRatio
505- }
506- />
507- </ div >
508- ) }
509-
508+ { /* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- A PR to add self-hosted video is upcoming where this check will be needed. */ }
510509 { media . type === 'picture' && (
511510 < >
512511 < CardPicture
@@ -519,20 +518,30 @@ export const FeatureCard = ({
519518 mobileAspectRatio
520519 }
521520 />
522- { isVideoMainMedia &&
521+
522+ { mainMedia ?. type === 'YoutubeVideo' &&
523523 mainMedia . duration > 0 && (
524- < MediaDuration
525- mediaDuration = {
526- mainMedia . duration
527- }
528- mediaPositionOnDesktop = {
529- 'top'
530- }
531- mediaPositionOnMobile = {
532- 'left'
533- }
534- />
524+ < div css = { videoPillStyles } >
525+ < Pill
526+ content = {
527+ < time >
528+ { secondsToDuration (
529+ mainMedia . duration ,
530+ ) }
531+ </ time >
532+ }
533+ icon = {
534+ < SvgMediaControlsPlay />
535+ }
536+ />
537+ </ div >
535538 ) }
539+
540+ { mainMedia ?. type === 'YoutubeVideo' && (
541+ < div css = { playIconStyles } >
542+ < PlayIcon iconWidth = "narrow" />
543+ </ div >
544+ ) }
536545 </ >
537546 ) }
538547
@@ -684,7 +693,6 @@ export const FeatureCard = ({
684693 ) : undefined
685694 }
686695 showLivePlayable = { false }
687- mainMedia = { mainMedia }
688696 isNewsletter = { isNewsletter }
689697 />
690698
@@ -695,23 +703,6 @@ export const FeatureCard = ({
695703 233 ,
696704 ) }
697705 </ div >
698- { /* On video article cards, the duration is displayed in the footer */ }
699- { ! isVideoArticle &&
700- isVideoMainMedia &&
701- videoDuration !== undefined ? (
702- < div css = { videoPillStyles } >
703- < Pill
704- content = {
705- < time >
706- { secondsToDuration (
707- videoDuration ,
708- ) }
709- </ time >
710- }
711- icon = { < SvgMediaControlsPlay /> }
712- />
713- </ div >
714- ) : null }
715706 </ div >
716707
717708 { isImmersive &&
0 commit comments