diff --git a/memory-bank/usage/headerBlock.md b/memory-bank/usage/headerBlock.md index 5ec01a22e..51d3cc97f 100644 --- a/memory-bank/usage/headerBlock.md +++ b/memory-bank/usage/headerBlock.md @@ -22,6 +22,7 @@ The HeaderBlock now supports multiple className props for fine-grained styling c ### Props Evolution - **Props Refactoring**: Renamed `containerFluidClassName` to `contentWrapperClassName` for better semantic clarity +- **Props Added/Modified**: Added option to use `videoIframe` to embed iframe-based video content as media ### Enhanced Content Structure @@ -33,6 +34,7 @@ The HeaderBlock now supports multiple className props for fine-grained styling c ### Background and Media Features - **`fullWidthMedia`**: Support for full-width media backgrounds +- **`videoIframe`**: Support for embedding iframe-based video content as media - **`mediaView`**: Control over media display mode ('full' by default) - **Component Composition**: Separate `Background` and `FullWidthBackground` components for better maintainability @@ -159,6 +161,18 @@ The HeaderBlock uses a sophisticated layout structure: /> ``` +### With Iframe Video + +```tsx + +``` + ### With Full-Width Background ```tsx @@ -285,6 +299,7 @@ const FullWidthBackground = ({background}: FullWidthBackgroundProps) => ( 1. **Image Optimization**: Use appropriately sized and optimized images 2. **Theme Support**: Provide both light and dark theme variants when needed 3. **Mobile Adaptation**: Consider how media displays on mobile devices +4. **Video Iframe**: When using videoIframe, ensure the source URL is properly formatted and accessible ### Background Implementation diff --git a/src/blocks/Header/Header.scss b/src/blocks/Header/Header.scss index 364fb4e5a..aff4844e7 100644 --- a/src/blocks/Header/Header.scss +++ b/src/blocks/Header/Header.scss @@ -175,6 +175,14 @@ $backgroundWidth: 1440px; border-radius: $borderRadius; } + &__video-iframe { + position: absolute; + top: 50%; + right: 0; + left: 0; + transform: translateY(-50%); + } + &__breadcrumbs { position: absolute; top: $indentXS; @@ -255,6 +263,15 @@ $backgroundWidth: 1440px; } } + &_media-view_full { + #{$block}__video-iframe { + top: 0; + bottom: 0; + height: auto !important; /* stylelint-disable-line declaration-no-important */ // we have to override contents of the style tag + transform: none; + } + } + @media (max-width: $backgroundWidth) { &__background, &__background#{$block}__background_media { diff --git a/src/blocks/Header/Header.tsx b/src/blocks/Header/Header.tsx index 5473c8553..059237e1d 100644 --- a/src/blocks/Header/Header.tsx +++ b/src/blocks/Header/Header.tsx @@ -80,6 +80,7 @@ export const HeaderBlock = (props: React.PropsWithChildren buttons, image, video, + videoIframe, width = 'm', imageSize, offset = 'default', @@ -102,7 +103,7 @@ export const HeaderBlock = (props: React.PropsWithChildren const windowWidth = useWindowWidth(); const isMobile = windowWidth <= BREAKPOINTS.sm; const theme = useTheme(); - const hasRightSideImage = Boolean((image || video) && !centered); + const hasRightSideImage = Boolean((image || video || videoIframe) && !centered); const curImageSize = imageSize || getImageSize(width); const titleSizes = hasRightSideImage ? titleWithImageSizes(curImageSize) : getTitleSizes(width); let curVerticalOffset = verticalOffset; @@ -114,8 +115,9 @@ export const HeaderBlock = (props: React.PropsWithChildren const backgroundThemed = background && getThemedValue(background, theme); const imageThemed = image && getThemedValue(image, theme); const videoThemed = video && getThemedValue(video, theme); + const {src: videoIframeSrc, ...videoIframeProps} = videoIframe ?? {}; const mediaWithMicrodata = mergeVideoMicrodata( - {video: videoThemed, image: imageThemed}, + {video: videoThemed, image: imageThemed, videoIframe: videoIframeSrc, ...videoIframeProps}, {name: title, description}, ); const fullWidth = backgroundThemed?.fullWidth || backgroundThemed?.fullWidthMedia; @@ -235,6 +237,7 @@ export const HeaderBlock = (props: React.PropsWithChildren className={b('media', {[curImageSize]: true}, mediaClassName)} videoClassName={b('video')} imageClassName={b('image')} + youtubeClassName={b('video-iframe')} {...mediaWithMicrodata} /> )} diff --git a/src/blocks/Header/__stories__/Header.mdx b/src/blocks/Header/__stories__/Header.mdx index 8ae13673e..500302e2b 100644 --- a/src/blocks/Header/__stories__/Header.mdx +++ b/src/blocks/Header/__stories__/Header.mdx @@ -32,6 +32,12 @@ There could be only one one Header block on the page. - `start: number` - `end: number` +`videoIframe?:` +- `src: string` +- `autoplay?: boolean` +- `previewImg?: string` +- `height?: number` + `backLink?: 'url' | 'title'` `imageSize?: 's' | 'm'` — Image size. diff --git a/src/blocks/Header/__stories__/Header.stories.tsx b/src/blocks/Header/__stories__/Header.stories.tsx index b9a30f678..546747589 100644 --- a/src/blocks/Header/__stories__/Header.stories.tsx +++ b/src/blocks/Header/__stories__/Header.stories.tsx @@ -216,6 +216,7 @@ export const FullWidthMediaBackground = FullWidthMediaBackgroundTemplate.bind({} export const DarkTheme = DefaultTemplate.bind({}); export const Breadcrumbs = BreadCrumbsTemplate.bind({}); export const MediaViewFit = FitTemplate.bind({}); +export const VideoIframe = DefaultTemplate.bind([]); Default.args = {...DefaultArgs} as HeaderBlockProps; @@ -260,3 +261,8 @@ MediaViewFit.args = { ...data.image.content, mediaView: 'fit', } as HeaderBlockProps; + +VideoIframe.args = { + ...DefaultArgs, + ...data.videoIframe.content, +} as HeaderBlockProps; diff --git a/src/blocks/Header/__stories__/data.json b/src/blocks/Header/__stories__/data.json index d0b6cd784..46fe528bf 100644 --- a/src/blocks/Header/__stories__/data.json +++ b/src/blocks/Header/__stories__/data.json @@ -180,6 +180,15 @@ } } }, + "videoIframe": { + "content": { + "videoIframe": { + "src": "https://runtime.video.cloud.yandex.net/player/video/vplvmyqsxi7dlwndvb4y", + "autoplay": false, + "previewImg": "/story-assets/header-img_0-12_light.png" + } + } + }, "size": { "title": "Header size {{size}}" } diff --git a/src/blocks/Header/schema.ts b/src/blocks/Header/schema.ts index aaa8e47ba..ab4053b34 100644 --- a/src/blocks/Header/schema.ts +++ b/src/blocks/Header/schema.ts @@ -9,6 +9,18 @@ import { } from '../../schema/validators/common'; import {filteredArray} from '../../schema/validators/utils'; +export const HeaderVideoIframeProps = { + type: 'object', + additionalProperties: false, + required: ['src'], + properties: { + src: {type: 'string'}, + autoplay: {type: 'boolean'}, + previewImg: {type: 'string'}, + height: {type: 'number'}, + }, +}; + export const HeaderBackgroundProps = { type: 'object', additionalProperties: false, @@ -50,6 +62,7 @@ export const HeaderProperties = { }, image: withTheme(ImageProps), video: withTheme(VideoProps), + videoIframe: withTheme(HeaderVideoIframeProps), mediaView: { type: 'string', enum: mediaView, diff --git a/src/models/constructor-items/blocks.ts b/src/models/constructor-items/blocks.ts index adef6534d..e38e6f1d1 100644 --- a/src/models/constructor-items/blocks.ts +++ b/src/models/constructor-items/blocks.ts @@ -166,6 +166,13 @@ export interface HeaderBlockBackground extends Partial, P export type ThemedHeaderBlockBackground = ThemeSupporting; +export interface HeaderBlockVideoIframe { + src: string; + autoplay?: boolean; + previewImg?: string; + height?: number; +} + export interface HeaderBlockProps { title: string; overtitle?: string | JSX.Element; @@ -182,6 +189,7 @@ export interface HeaderBlockProps { offset?: HeaderOffset; image?: ThemedImage; video?: ThemedMediaVideoProps; + videoIframe?: HeaderBlockVideoIframe; mediaView?: MediaView; centered?: boolean; background?: ThemedHeaderBlockBackground;