Skip to content

Commit

Permalink
feat: add video microdata (#1070)
Browse files Browse the repository at this point in the history
  • Loading branch information
aeksandla authored Nov 14, 2024
1 parent 1acaf8a commit 8ba8ca0
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 31 deletions.
9 changes: 7 additions & 2 deletions src/blocks/Media/Media.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import {useTheme} from '../../context/theme';
import {MediaBlockProps} from '../../models';
import {block, getThemedValue} from '../../utils';
import {getMediaBorder} from '../../utils/borderSelector';
import {mergeVideoMicrodata} from '../../utils/microdata';

import './Media.scss';

const b = block('media-block');

export const MediaBlock = (props: MediaBlockProps) => {
const {media, border, disableShadow} = props;
const {media, border, disableShadow, title, description} = props;
const borderSelected = getMediaBorder({
border,
disableShadow,
Expand All @@ -21,13 +22,17 @@ export const MediaBlock = (props: MediaBlockProps) => {
const [play, setPlay] = useState<boolean>(false);
const theme = useTheme();
const mediaThemed = getThemedValue(media, theme);
const mediaWithMicrodata = mergeVideoMicrodata(mediaThemed, {
name: title,
description,
});

return (
<MediaBase {...props} onScroll={() => setPlay(true)}>
<MediaBase.Card>
<Media
imageClassName={b('image')}
{...mediaThemed}
{...mediaWithMicrodata}
playVideo={play}
className={b({border: borderSelected})}
/>
Expand Down
7 changes: 6 additions & 1 deletion src/blocks/PromoFeaturesBlock/PromoFeaturesBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {BREAKPOINTS} from '../../constants';
import {useTheme} from '../../context/theme';
import {PromoFeaturesProps} from '../../models';
import {block, getThemedValue} from '../../utils';
import {mergeVideoMicrodata} from '../../utils/microdata';

import './PromoFeaturesBlock.scss';

Expand Down Expand Up @@ -39,6 +40,10 @@ const PromoFeaturesBlock = (props: PromoFeaturesProps) => {
const blockModifier = backgroundTheme === 'default' ? 'default' : 'light';
const themeMod = cardTheme || blockModifier || '';
const themedMedia = getThemedValue(media, globalTheme);
const allProps = mergeVideoMicrodata(themedMedia, {
name: cardTitle,
description: text,
});

return (
<div
Expand All @@ -54,7 +59,7 @@ const PromoFeaturesBlock = (props: PromoFeaturesProps) => {
<YFMWrapper content={text} modifiers={{constructor: true}} />
</div>
</div>
{media && <Media className={b('card-media')} {...themedMedia} />}
{media && <Media className={b('card-media')} {...allProps} />}
</div>
);
})}
Expand Down
10 changes: 8 additions & 2 deletions src/blocks/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {useTheme} from '../../context/theme';
import {Col, GridColumnOrderClasses, Row} from '../../grid';
import {TabsBlockProps} from '../../models';
import {block, getThemedValue} from '../../utils';
import {mergeVideoMicrodata} from '../../utils/microdata';

import TabsTextContent from './TabsTextContent/TabsTextContent';

Expand Down Expand Up @@ -85,7 +86,7 @@ export const TabsBlock = ({
const showText = Boolean(activeTabData?.text);
const border = activeTabData?.border || 'shadow';

const textContent = activeTabData && showText && (
const textContent = showText && (
<TabsTextContent
showMedia={showMedia}
data={activeTabData}
Expand All @@ -109,7 +110,12 @@ export const TabsBlock = ({
<div style={{minHeight: mediaVideoHeight || minImageHeight}}>
<div ref={ref}>
<Media
{...getThemedValue(activeTabData.media, theme)}
{...mergeVideoMicrodata(getThemedValue(activeTabData.media, theme), {
name: activeTabData.tabName,
description: activeTabData.caption
? activeTabData.caption
: undefined,
})}
key={activeTab}
className={b('media', {border})}
playVideo={play}
Expand Down
54 changes: 31 additions & 23 deletions src/blocks/Tabs/TabsTextContent/TabsTextContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const b = block('tabs-block-text-content');
interface TextContentProps extends Pick<TabsBlockProps, 'centered' | 'contentSize'> {
showMedia: boolean;
isReverse: boolean;
data: TabsBlockItem;
data?: TabsBlockItem;
centered?: boolean;
imageProps?: ImageObjectProps | ImageDeviceProps;
}
Expand All @@ -21,29 +21,37 @@ export const TabsTextContent = ({
centered,
contentSize = 's',
showMedia,
data: {media, title, text, additionalInfo, link, links, buttons, list},
data,
imageProps,
isReverse,
}: TextContentProps) => (
<Col sizes={{all: 12, md: showMedia ? 4 : 8}} className={b({centered: centered})}>
<div
className={b('wrapper', {
reverse: isReverse,
'no-image': !(media || imageProps),
})}
>
<Content
title={title}
text={text}
additionalInfo={additionalInfo}
size={contentSize}
list={list}
links={[...(link ? [link] : []), ...(links || [])]}
buttons={buttons}
colSizes={{all: 12}}
/>
</div>
</Col>
);
}: TextContentProps) => {
if (!data) {
return null;
}

const {media, title, text, additionalInfo, link, links, buttons, list} = data;

return (
<Col sizes={{all: 12, md: showMedia ? 4 : 8}} className={b({centered: centered})}>
<div
className={b('wrapper', {
reverse: isReverse,
'no-image': !(media || imageProps),
})}
>
<Content
title={title}
text={text}
additionalInfo={additionalInfo}
size={contentSize}
list={list}
links={[...(link ? [link] : []), ...(links || [])]}
buttons={buttons}
colSizes={{all: 12}}
/>
</div>
</Col>
);
};

export default TabsTextContent;
25 changes: 24 additions & 1 deletion src/components/Media/Media.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, {ReactElement, useMemo, useState} from 'react';
import React, {ReactElement, useContext, useMemo, useState} from 'react';

import {InnerContext} from '../../context/innerContext';
import {MediaProps, QAProps} from '../../models';
import {block, getQaAttrubutes} from '../../utils';
import {sanitizeMicrodata} from '../../utils/microdata';
import IframeVideoBlock from '../VideoBlock/VideoBlock';

import DataLens from './DataLens/DataLens';
Expand Down Expand Up @@ -49,9 +51,11 @@ export const Media = (props: MediaAllProps) => {
onImageLoad,
iframe,
margins,
videoMicrodata,
} = props;

const [hasVideoFallback, setHasVideoFallback] = useState(false);
const {microdata} = useContext(InnerContext);

const qaAttributes = getQaAttrubutes(qa, 'video');

Expand Down Expand Up @@ -155,8 +159,27 @@ export const Media = (props: MediaAllProps) => {
margins,
]);

const videoMicrodataScript = useMemo(() => {
const {name, description} = videoMicrodata || {};
const json = JSON.stringify({
'@context': 'http://schema.org/',
'@type': 'VideoObject',
uploadDate: microdata?.contentUpdatedDate,
contentUrl: video?.src?.[0] || videoIframe || youtube,
thumbnailUrl: previewImg,
...(videoMicrodata || {}),
name: name ? sanitizeMicrodata(name) : name,
description: description ? sanitizeMicrodata(description) : description,
});

return video || youtube || videoIframe ? (
<script type="application/ld+json">{json}</script>
) : null;
}, [microdata?.contentUpdatedDate, previewImg, video, videoIframe, videoMicrodata, youtube]);

return (
<div className={b(null, className)} style={{backgroundColor: color}} data-qa={qa}>
{videoMicrodataScript}
{content}
</div>
);
Expand Down
7 changes: 6 additions & 1 deletion src/containers/PageConstructor/PageConstructor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export interface PageConstructorProps {
custom?: CustomConfig;
renderMenu?: () => React.ReactNode;
navigation?: NavigationData;
microdata?: {
contentUpdatedDate?: string;
};
}

export const Constructor = (props: PageConstructorProps) => {
Expand All @@ -59,6 +62,7 @@ export const Constructor = (props: PageConstructorProps) => {
shouldRenderBlock,
navigation,
custom,
microdata,
} = props;

const {context} = useMemo(
Expand All @@ -85,9 +89,10 @@ export const Constructor = (props: PageConstructorProps) => {
customization: {
decorators: custom?.decorators,
},
microdata,
},
}),
[custom, shouldRenderBlock],
[custom, shouldRenderBlock, microdata],
);

const theme = useTheme();
Expand Down
4 changes: 4 additions & 0 deletions src/context/innerContext/InnerContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export interface InnerContextType {
loadables?: LoadableConfig;
shouldRenderBlock?: ShouldRenderBlock;
customization?: Pick<CustomConfig, 'decorators'>;
microdata?: {
contentUpdatedDate?: string;
};
}

export const InnerContext = React.createContext<InnerContextType>({
Expand All @@ -22,4 +25,5 @@ export const InnerContext = React.createContext<InnerContextType>({
navigationBlockTypes: [],
itemMap: {} as ItemMap,
navItemMap: {} as NavItemMap,
microdata: {},
});
8 changes: 8 additions & 0 deletions src/models/constructor-items/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,14 @@ export interface MediaProps
Partial<MediaComponentIframeProps>,
Partial<MediaComponentVideoProps> {
color?: string;
videoMicrodata?: {
name?: string;
description?: string;
duration?: string;
uploadDate?: string;
contentUrl?: string;
thumbnailUrl?: string;
};
}

export interface BackgroundMediaProps extends MediaProps, Animatable, QAProps {
Expand Down
8 changes: 7 additions & 1 deletion src/sub-blocks/LayoutItem/LayoutItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {FullscreenMedia, IconWrapper, Media, MetaInfo} from '../../components';
import {useTheme} from '../../context/theme';
import {ContentBlockProps, LayoutItemProps} from '../../models';
import {block, getThemedValue} from '../../utils';
import {mergeVideoMicrodata} from '../../utils/microdata';
import Content from '../Content/Content';

import {getLayoutItemLinks, hasFullscreen, showFullscreenIcon} from './utils';
Expand Down Expand Up @@ -43,6 +44,11 @@ const LayoutItem = ({
return null;
}
const themedMedia = getThemedValue(media, theme);
const {title} = content;
const mediaWithMicrodata = mergeVideoMicrodata(themedMedia, {
name: typeof title === 'string' ? title : title?.text,
description: content.text,
});

return fullscreen && hasFullscreen(themedMedia) ? (
<FullscreenMedia showFullscreenIcon={showFullscreenIcon(themedMedia)}>
Expand All @@ -52,7 +58,7 @@ const LayoutItem = ({
...fullscreenMediaProps
} = {}) => (
<Media
{...themedMedia}
{...mediaWithMicrodata}
{...fullscreenMediaProps}
className={b('media', {border}, mediaClassName)}
analyticsEvents={analyticsEvents}
Expand Down
12 changes: 12 additions & 0 deletions src/utils/microdata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import sanitize from 'sanitize-html';

import {MediaProps} from '../models';

export const mergeVideoMicrodata = (
values: MediaProps = {},
newValues: MediaProps['videoMicrodata'] = {},
): MediaProps => ({...values, videoMicrodata: {...newValues, ...(values.videoMicrodata || {})}});

export function sanitizeMicrodata(html: string) {
return html && sanitize(html, {allowedTags: [], allowedAttributes: {}});
}

0 comments on commit 8ba8ca0

Please sign in to comment.