Skip to content
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

[B2BP-933] [B2BP-934] - Video-image: add title and subtitle on image rendering and add image for mobile breakpoint #475

Merged
merged 13 commits into from
Oct 17, 2024
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
5 changes: 5 additions & 0 deletions .changeset/unlucky-berries-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nextjs-website": patch
---

VideoImage: Show title and subtitle when displaying image and add image for mobile breakpoint
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ export const renderVideo = ({
fallback,
onClick,
onVideoEnd,
isMobileDevice
isMobileDevice,
}: RenderVideoProps) => {
// Define styles for mobile and non-mobile devices
const mobileStyle = {
overflow: 'hidden',
width: '100vw',
Expand Down Expand Up @@ -55,17 +54,18 @@ export const renderVideo = ({
onClick={onClick}
style={isMobileDevice ? mobileStyle : nonMobileStyle}
>
<source
src={src}
onError={() => setError(true)}
/>
<source src={src} onError={() => setError(true)} />
</video>
);
};

// Refactored renderImage function
export const renderImage = ({ src, alt, isMobileDevice }: RenderImageProps) => {
// Define styles for mobile and non-mobile devices
export const renderImage = ({
src,
alt,
mobileSrc,
mobileAlt,
isMobileDevice,
}: RenderImageProps) => {
const mobileStyle = {
overflow: 'hidden',
width: '100vw',
Expand All @@ -80,10 +80,13 @@ export const renderImage = ({ src, alt, isMobileDevice }: RenderImageProps) => {
height: '100%',
};

const imageSrc = isMobileDevice && mobileSrc ? mobileSrc : src;
const imageAlt = isMobileDevice && mobileAlt ? mobileAlt : alt;

return (
<Image
alt={alt}
src={src}
alt={imageAlt}
src={imageSrc}
width={0}
height={0}
style={isMobileDevice ? mobileStyle : nonMobileStyle}
Expand Down Expand Up @@ -118,6 +121,37 @@ export const VideoText = ({
);
};

export const ImageText = ({
title,
subtitle,
theme = 'dark',
}: {
title?: string;
subtitle?: string;
theme: 'dark' | 'light';
}) => {
const textColor = TextColor(theme);
return (
<>
{title && (
<Typography variant='h5' mb={4} color={textColor}>
{title}
</Typography>
)}
{subtitle && (
<Typography
paragraph
sx={{ fontSize: '16px' }}
mb={3}
color={textColor}
>
{subtitle}
</Typography>
)}
</>
);
};

export const VideoCaption = ({ caption, isCentered }: VideoCaptionProps) => {
const { palette } = useTheme();
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// Disable rule below since we'll be determining whether image or video exist based on mediaState
/* eslint-disable @typescript-eslint/no-non-null-assertion */

import { useEffect, useRef, useState } from 'react';
import { useIsVisible } from '@react-components/types/common/Common.types';
import { VideoImageProps } from '@react-components/types';
Expand All @@ -11,6 +8,7 @@ import {
renderVideo,
VideoCaption,
VideoText,
ImageText,
} from './VideoImage.helpers';

const VideoImage = ({
Expand All @@ -20,12 +18,11 @@ const VideoImage = ({
isCentered,
theme,
image,
mobileImage,
video,
sectionID,
}: VideoImageProps) => {
if (!image && !video) {
// Disable lint for this case because we want the build to fail if user input nothing
// eslint-disable-next-line
throw new Error();
}

Expand All @@ -41,7 +38,6 @@ const VideoImage = ({

useEffect(() => {
setIsMobileDevice(window.innerWidth <= 768);

const handleResize = () => {
setIsMobileDevice(window.innerWidth <= 768);
};
Expand All @@ -52,7 +48,6 @@ const VideoImage = ({
useEffect(() => {
if (mediaState === 'image') return;
if (!isVisible) return;

const startVideoWhenVisible = async () => {
if (video?.autoplay && isVisible) play();
};
Expand All @@ -61,18 +56,14 @@ const VideoImage = ({

const play = (e?: React.MouseEvent) => {
e?.preventDefault();

if (mediaState === 'image') return;

if (videoRef.current) {
videoRef.current
.play()
.then(() => {
setMediaState('play');
})
.catch(() => {
// Handle play error
});
.catch(() => {});
}
};

Expand All @@ -95,7 +86,7 @@ const VideoImage = ({
position: 'relative',
overflow: 'hidden',
}}
{...sectionID && { id: sectionID }}
{...(sectionID && { id: sectionID })}
>
{video?.showControls &&
(mediaState === 'stop' || mediaState === 'pause') && (
Expand Down Expand Up @@ -165,29 +156,78 @@ const VideoImage = ({
</div>
</div>
)}
{mediaState === 'image' ? (
<>
<div
style={{ position: 'relative', width: '100%', height: '600px' }}
>
{renderImage({
src: image!.src,
alt: image!.alt,
mobileSrc: mobileImage!.src,
mobileAlt: mobileImage!.alt,
isMobileDevice,
})}

{(title || subtitle) && (
<>
<div
style={{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.25)',
zIndex: 10,
}}
/>

{mediaState === 'image'
? renderImage({
src: image!.src,
alt: image!.alt,
isMobileDevice,
})
: renderVideo({
videoRef,
error,
setError,
src: video!.src,
loop: video!.loop,
autoplay: video!.autoplay,
fallback: video!.fallback,
onVideoEnd: handleVideoEnd,
onClick: pause,
isMobileDevice,
})}
<div
style={{
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: isCentered ? 'center' : 'flex-start',
zIndex: 20,
padding: '20px',
marginLeft: isCentered ? '0' : '6em',
textAlign: isCentered ? 'center' : 'left',
}}
>
<ImageText
theme={theme}
title={title ?? ''}
subtitle={subtitle ?? ''}
/>
</div>
</>
)}
</div>
</>
) : (
renderVideo({
videoRef,
error,
setError,
src: video!.src,
loop: video!.loop,
autoplay: video!.autoplay,
fallback: video!.fallback,
onVideoEnd: handleVideoEnd,
onClick: pause,
isMobileDevice,
})
)}
</section>
{caption && (
<VideoCaption caption={caption} isCentered={isCentered} />
)}
{caption && <VideoCaption caption={caption} isCentered={isCentered} />}
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { SectionProps, Theme } from '../common/Common.types';

export interface VideoImageProps extends SectionProps, VideoTextProps, VideoCaptionProps {
export interface VideoImageProps
extends SectionProps,
VideoTextProps,
VideoCaptionProps {
image?: {
src: string;
alt: string;
};
mobileImage?: {
src: string;
alt: string;
};
video?: {
src: string;
autoplay: boolean;
Expand Down Expand Up @@ -43,5 +50,7 @@ export interface RenderVideoProps {
export interface RenderImageProps {
src: string;
alt: string;
mobileSrc: string;
mobileAlt: string;
isMobileDevice: boolean;
}
24 changes: 8 additions & 16 deletions apps/nextjs-website/src/components/VideoImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ const makeVideoImageProps = ({
subtitle,
caption,
image,
mobileImage,
video,
...rest
}: VideoImageSection): VideoImageProps => ({
...rest,
...(title && { title }),
...(subtitle && { subtitle }),
...(caption && { caption }),
// If user uploaded a video, use it
...(video &&
video.src.data && {
video: {
Expand All @@ -28,27 +28,19 @@ const makeVideoImageProps = ({
pausedPlayButtonLabel: video.pausedPlayButtonLabel,
},
}),
// If user did not upload a video, check if they input a URL
...(video &&
!video.src.data &&
video.srcURL && {
video: {
src: video.srcURL,
autoplay: video.autoplay,
loop: video.loop,
showControls: video.showControls,
fallback: video.fallback,
playButtonLabel: video.playButtonLabel,
pausedPlayButtonLabel: video.pausedPlayButtonLabel,
},
}),
// If user did not input any video source, check if they uploaded an image
...((!video || (!video.srcURL && !video.src.data)) &&
image.data && {
image: {
src: image.data.attributes.url,
alt: image.data.attributes.alternativeText ?? '',
},
mobileImage: {
src: mobileImage?.data?.attributes?.url ?? image.data.attributes.url,
alt:
mobileImage?.data?.attributes?.alternativeText ??
image.data.attributes.alternativeText ??
'',
},
}),
});

Expand Down
1 change: 1 addition & 0 deletions apps/nextjs-website/src/lib/fetch/types/PageSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ const VideoImageSectionCodec = t.strict({
caption: t.union([t.string, t.null]),
isCentered: t.boolean,
image: StrapiImageSchema,
mobileImage: StrapiImageSchema,
video: t.union([VideoCodec, t.null]),
});

Expand Down
Loading
Loading