@cloud-ru/uikit-product-site-hero 0.5.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +937 -0
- package/LICENSE +201 -0
- package/README.md +71 -0
- package/package.json +61 -0
- package/src/components/HeroEvent/HeroEvent.tsx +108 -0
- package/src/components/HeroEvent/constants.ts +23 -0
- package/src/components/HeroEvent/index.ts +1 -0
- package/src/components/HeroEvent/styles.module.scss +147 -0
- package/src/components/HeroEvent/types.ts +6 -0
- package/src/components/HeroMain/HeroMain.tsx +159 -0
- package/src/components/HeroMain/components/PlatformLink/PlatformLink.tsx +31 -0
- package/src/components/HeroMain/components/PlatformLink/index.ts +1 -0
- package/src/components/HeroMain/components/index.ts +1 -0
- package/src/components/HeroMain/index.ts +1 -0
- package/src/components/HeroMain/styles.module.scss +154 -0
- package/src/components/HeroMain/utils.ts +17 -0
- package/src/components/HeroSlider/HeroSlider.tsx +72 -0
- package/src/components/HeroSlider/components/HeroSlide/HeroSlide.tsx +70 -0
- package/src/components/HeroSlider/components/HeroSlide/constants.ts +12 -0
- package/src/components/HeroSlider/components/HeroSlide/index.ts +2 -0
- package/src/components/HeroSlider/components/HeroSlide/styles.module.scss +164 -0
- package/src/components/HeroSlider/components/HeroSlide/types.ts +39 -0
- package/src/components/HeroSlider/components/HeroSlide/util.ts +35 -0
- package/src/components/HeroSlider/components/HeroSlideImage/HeroSlideImage.tsx +29 -0
- package/src/components/HeroSlider/components/HeroSlideImage/index.ts +1 -0
- package/src/components/HeroSlider/components/HeroSlideImage/styles.module.scss +31 -0
- package/src/components/HeroSlider/components/HeroSlideImageBg/HeroSlideImageBg.tsx +31 -0
- package/src/components/HeroSlider/components/HeroSlideImageBg/index.ts +1 -0
- package/src/components/HeroSlider/components/HeroSlideImageBg/styles.module.scss +20 -0
- package/src/components/HeroSlider/components/HeroSlideMedia/HeroSlideMedia.tsx +22 -0
- package/src/components/HeroSlider/components/HeroSlideMedia/index.ts +2 -0
- package/src/components/HeroSlider/components/HeroSlideMedia/types.ts +17 -0
- package/src/components/HeroSlider/components/HeroSlideVideoBg/HTMLComment.tsx +36 -0
- package/src/components/HeroSlider/components/HeroSlideVideoBg/HeroSlideVideoBg.tsx +30 -0
- package/src/components/HeroSlider/components/HeroSlideVideoBg/index.ts +1 -0
- package/src/components/HeroSlider/components/index.ts +5 -0
- package/src/components/HeroSlider/index.ts +2 -0
- package/src/components/HeroSlider/styles.module.scss +41 -0
- package/src/components/HeroZero/HeroZero.tsx +84 -0
- package/src/components/HeroZero/index.ts +1 -0
- package/src/components/HeroZero/styles.module.scss +111 -0
- package/src/components/HeroZero/utils.ts +15 -0
- package/src/components/index.ts +4 -0
- package/src/constants.ts +12 -0
- package/src/helperComponents/HeroEventButton/HeroEventButton.tsx +32 -0
- package/src/helperComponents/HeroEventButton/constants.ts +21 -0
- package/src/helperComponents/HeroEventButton/index.ts +1 -0
- package/src/helperComponents/HeroEventButton/types.ts +5 -0
- package/src/helperComponents/HeroNavbar/HeroNavbar.tsx +26 -0
- package/src/helperComponents/HeroNavbar/index.ts +1 -0
- package/src/helperComponents/HeroNavbar/styles.module.scss +13 -0
- package/src/helperComponents/Place/Place.tsx +32 -0
- package/src/helperComponents/Place/constants.ts +34 -0
- package/src/helperComponents/Place/index.ts +1 -0
- package/src/helperComponents/Place/styles.module.scss +3 -0
- package/src/helperComponents/index.tsx +3 -0
- package/src/index.ts +1 -0
- package/src/types.ts +5 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ButtonPromoProps } from '@cloud-ru/uikit-product-button-predefined';
|
|
2
|
+
import { EridProps } from '@cloud-ru/uikit-product-site-tag';
|
|
3
|
+
import { ValueOf } from '@snack-uikit/utils';
|
|
4
|
+
|
|
5
|
+
import { HeroSlideMediaProps } from '../HeroSlideMedia';
|
|
6
|
+
import { Appearance, Color } from './constants';
|
|
7
|
+
|
|
8
|
+
type ColorType = ValueOf<typeof Color>;
|
|
9
|
+
|
|
10
|
+
type AppearanceType = ValueOf<typeof Appearance>;
|
|
11
|
+
|
|
12
|
+
export type HeroSlideBaseProps = {
|
|
13
|
+
/** id компонента */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Заголовок*/
|
|
16
|
+
title: string;
|
|
17
|
+
/** Описание */
|
|
18
|
+
description?: string;
|
|
19
|
+
/** Медиа-контент */
|
|
20
|
+
media: HeroSlideMediaProps;
|
|
21
|
+
/** Кнопка ButtonPromo */
|
|
22
|
+
button: Omit<ButtonPromoProps, 'size' | 'appearance' | 'className'>;
|
|
23
|
+
/** Плашка рекламы с tooltip */
|
|
24
|
+
erid?: Pick<EridProps, 'tip' | 'appearance'>;
|
|
25
|
+
/** CSS-класс */
|
|
26
|
+
className?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type HeroSlideWithColor = HeroSlideBaseProps & {
|
|
30
|
+
appearance: Exclude<AppearanceType, 'brand' | 'graphite'>;
|
|
31
|
+
color: ColorType;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type HeroSlideWithoutColor = HeroSlideBaseProps & {
|
|
35
|
+
appearance: Exclude<AppearanceType, 'decor'>;
|
|
36
|
+
color?: never;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type HeroSlideProps = HeroSlideWithColor | HeroSlideWithoutColor;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { LayoutType } from '@cloud-ru/uikit-product-utils';
|
|
2
|
+
import { TypographyProps } from '@snack-uikit/typography';
|
|
3
|
+
|
|
4
|
+
import { HeroSlideImageProps } from '../HeroSlideImage';
|
|
5
|
+
import { HeroSlideBaseProps } from './types';
|
|
6
|
+
|
|
7
|
+
export const getTitleProps = (layoutType: LayoutType): Pick<TypographyProps, 'purpose' | 'size'> => {
|
|
8
|
+
switch (layoutType) {
|
|
9
|
+
case 'mobile':
|
|
10
|
+
case 'tablet':
|
|
11
|
+
return {
|
|
12
|
+
purpose: 'headline',
|
|
13
|
+
size: 'l',
|
|
14
|
+
};
|
|
15
|
+
default:
|
|
16
|
+
return {
|
|
17
|
+
purpose: 'display',
|
|
18
|
+
size: 'm',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const getSliderContentWrapperImageType = (
|
|
24
|
+
media: HeroSlideBaseProps['media'],
|
|
25
|
+
): HeroSlideImageProps['format'] | undefined => {
|
|
26
|
+
switch (media.type) {
|
|
27
|
+
case 'image':
|
|
28
|
+
return media.format;
|
|
29
|
+
|
|
30
|
+
case 'imageBg':
|
|
31
|
+
case 'videoBg':
|
|
32
|
+
default:
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CSS_BREAKPOINTS, WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
2
|
+
|
|
3
|
+
import styles from './styles.module.scss';
|
|
4
|
+
|
|
5
|
+
export type HeroSlideImageProps = {
|
|
6
|
+
/** Ссылки на картинку */
|
|
7
|
+
source: {
|
|
8
|
+
desktop: string;
|
|
9
|
+
tablet?: string;
|
|
10
|
+
};
|
|
11
|
+
/** Форма картинки */
|
|
12
|
+
format: 'rectangle' | 'square' | 'custom';
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function HeroSlideImage({ source, format, layoutType }: WithLayoutType<HeroSlideImageProps>) {
|
|
16
|
+
const { tablet, desktop } = source;
|
|
17
|
+
|
|
18
|
+
if (layoutType === 'mobile') {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<picture className={styles.imageWrapper} data-image-format={format} data-layout-type={layoutType}>
|
|
24
|
+
{tablet && <source srcSet={tablet} media={CSS_BREAKPOINTS.tablet} />}
|
|
25
|
+
<source srcSet={desktop} media={CSS_BREAKPOINTS.large} />
|
|
26
|
+
<img src={desktop} className={styles.image} data-image-format={format} loading='lazy' alt='main slide' />
|
|
27
|
+
</picture>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './HeroSlideImage';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
$rectangle: 'rectangle';
|
|
2
|
+
$square: 'square';
|
|
3
|
+
|
|
4
|
+
.imageWrapper {
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
height: 100%;
|
|
8
|
+
|
|
9
|
+
&[data-image-format='#{$rectangle}'] {
|
|
10
|
+
&[data-layout-type='desktop'] {
|
|
11
|
+
flex-shrink: 0;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.image {
|
|
17
|
+
height: 100%;
|
|
18
|
+
object-fit: cover;
|
|
19
|
+
object-position: center;
|
|
20
|
+
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
|
|
23
|
+
&[data-image-format='#{$rectangle}'] {
|
|
24
|
+
width: auto;
|
|
25
|
+
max-height: 328px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&[data-image-format='#{$square}'] {
|
|
29
|
+
max-height: 368px;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CSS_BREAKPOINTS, WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
2
|
+
|
|
3
|
+
import styles from './styles.module.scss';
|
|
4
|
+
|
|
5
|
+
export type HeroSlideImageBgProps = {
|
|
6
|
+
/** Ссылки на картинку-фон */
|
|
7
|
+
source: {
|
|
8
|
+
desktopLg?: string;
|
|
9
|
+
desktop: string;
|
|
10
|
+
tablet: string;
|
|
11
|
+
mobile: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function HeroSlideImageBg({ source }: WithLayoutType<HeroSlideImageBgProps>) {
|
|
16
|
+
return (
|
|
17
|
+
<picture className={styles.backgroundImageWrapper}>
|
|
18
|
+
<source srcSet={source.mobile} media={CSS_BREAKPOINTS.mobile} />
|
|
19
|
+
<source srcSet={source.tablet} media={CSS_BREAKPOINTS.tablet} />
|
|
20
|
+
{source.desktopLg ? (
|
|
21
|
+
<>
|
|
22
|
+
<source srcSet={source.desktop} media={CSS_BREAKPOINTS.desktop} />
|
|
23
|
+
<source srcSet={source.desktopLg} />
|
|
24
|
+
</>
|
|
25
|
+
) : (
|
|
26
|
+
<source srcSet={source.desktop} />
|
|
27
|
+
)}
|
|
28
|
+
<img loading='lazy' src={source.desktop} className={styles.backgroundImage} alt='background' />
|
|
29
|
+
</picture>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './HeroSlideImageBg';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.backgroundImageWrapper {
|
|
2
|
+
position: absolute;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
/* stylelint-disable-next-line declaration-property-value-allowed-list */
|
|
8
|
+
z-index: 2;
|
|
9
|
+
|
|
10
|
+
padding: 0;
|
|
11
|
+
display: block;
|
|
12
|
+
line-height: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.backgroundImage {
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
object-fit: cover;
|
|
19
|
+
object-position: center 0;
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
2
|
+
|
|
3
|
+
import { HeroSlideImage } from '../HeroSlideImage';
|
|
4
|
+
import { HeroSlideImageBg } from '../HeroSlideImageBg';
|
|
5
|
+
import { HeroSlideVideoBg } from '../HeroSlideVideoBg';
|
|
6
|
+
import { HeroSlideMediaProps } from './types';
|
|
7
|
+
|
|
8
|
+
export function HeroSlideMedia(props: WithLayoutType<HeroSlideMediaProps>) {
|
|
9
|
+
switch (props.type) {
|
|
10
|
+
case 'image':
|
|
11
|
+
return <HeroSlideImage {...props} />;
|
|
12
|
+
|
|
13
|
+
case 'imageBg':
|
|
14
|
+
return <HeroSlideImageBg {...props} />;
|
|
15
|
+
|
|
16
|
+
case 'videoBg':
|
|
17
|
+
return <HeroSlideVideoBg {...props} />;
|
|
18
|
+
|
|
19
|
+
default:
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { HeroSlideImageProps } from '../HeroSlideImage';
|
|
2
|
+
import { HeroSlideImageBgProps } from '../HeroSlideImageBg';
|
|
3
|
+
import { HeroSlideVideoBgProps } from '../HeroSlideVideoBg';
|
|
4
|
+
|
|
5
|
+
type HeroImageProps = HeroSlideImageProps & {
|
|
6
|
+
type: 'image';
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type HeroImageBgProps = HeroSlideImageBgProps & {
|
|
10
|
+
type: 'imageBg';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type HeroVideoBgProps = HeroSlideVideoBgProps & {
|
|
14
|
+
type: 'videoBg';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type HeroSlideMediaProps = HeroImageProps | HeroImageBgProps | HeroVideoBgProps;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createRef, RefObject, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function HTMLComment({ text }: Props) {
|
|
8
|
+
const ref: RefObject<HTMLSpanElement> = createRef();
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
let el: HTMLSpanElement | null = null;
|
|
12
|
+
let parent: ParentNode | null = null;
|
|
13
|
+
let comm: Comment | null = null;
|
|
14
|
+
|
|
15
|
+
if (ref.current) {
|
|
16
|
+
el = ref.current;
|
|
17
|
+
parent = el.parentNode;
|
|
18
|
+
comm = document.createComment(` ${text.trim()} `);
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
if (parent && parent.contains(el)) {
|
|
22
|
+
parent.replaceChild(comm, el);
|
|
23
|
+
}
|
|
24
|
+
// eslint-disable-next-line
|
|
25
|
+
} catch {}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return () => {
|
|
29
|
+
if (parent && el && comm) {
|
|
30
|
+
parent.replaceChild(el, comm);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}, [ref, text]);
|
|
34
|
+
|
|
35
|
+
return <span ref={ref} style={{ display: 'none' }} />;
|
|
36
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SiteVideo } from '@cloud-ru/uikit-product-site-media';
|
|
2
|
+
import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
3
|
+
|
|
4
|
+
import { HTMLComment } from './HTMLComment';
|
|
5
|
+
|
|
6
|
+
export type HeroSlideVideoBgProps = {
|
|
7
|
+
/** Ссылка на видео */
|
|
8
|
+
link: string;
|
|
9
|
+
/** Картинка-предпросмотр видео */
|
|
10
|
+
previewImage: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function HeroSlideVideoBg({ link, previewImage, layoutType }: WithLayoutType<HeroSlideVideoBgProps>) {
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<HTMLComment text='noindex' />
|
|
17
|
+
<SiteVideo
|
|
18
|
+
layoutType={layoutType}
|
|
19
|
+
video={{
|
|
20
|
+
src: link,
|
|
21
|
+
poster: previewImage,
|
|
22
|
+
muted: true,
|
|
23
|
+
loop: true,
|
|
24
|
+
autoPlay: true,
|
|
25
|
+
}}
|
|
26
|
+
/>
|
|
27
|
+
<HTMLComment text='/noindex' />
|
|
28
|
+
</>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './HeroSlideVideoBg';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@use '@sbercloud/figma-tokens-web/build/scss/styles-theme-variables' as var;
|
|
2
|
+
|
|
3
|
+
$decor: 'decor';
|
|
4
|
+
$graphite: 'graphite';
|
|
5
|
+
$brand: 'brand';
|
|
6
|
+
|
|
7
|
+
.root {
|
|
8
|
+
position: relative;
|
|
9
|
+
touch-action: none;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.heroCarousel {
|
|
13
|
+
& > div > div {
|
|
14
|
+
padding: 0;
|
|
15
|
+
margin: 0;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.paginationWrapper {
|
|
20
|
+
position: absolute;
|
|
21
|
+
bottom: 24px;
|
|
22
|
+
left: 0;
|
|
23
|
+
right: 0;
|
|
24
|
+
|
|
25
|
+
display: flex;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
|
|
28
|
+
&[data-appearance='#{$brand}'] {
|
|
29
|
+
button[data-activated="true"] > div {
|
|
30
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
31
|
+
background-color: var.$sys-neutral-accent-default !important;
|
|
32
|
+
|
|
33
|
+
&:hover,
|
|
34
|
+
&:focus-visible,
|
|
35
|
+
&:active {
|
|
36
|
+
/* stylelint-disable-next-line declaration-no-important */
|
|
37
|
+
background-color: var.$sys-neutral-accent-hovered !important;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
|
|
3
|
+
import { Layout } from '@cloud-ru/uikit-product-site-layout';
|
|
4
|
+
import { RichText } from '@cloud-ru/uikit-product-site-rich-text';
|
|
5
|
+
import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
|
|
6
|
+
import { Breadcrumbs, Item } from '@snack-uikit/breadcrumbs';
|
|
7
|
+
import { ButtonFilled, ButtonFilledProps } from '@snack-uikit/button';
|
|
8
|
+
import { Typography } from '@snack-uikit/typography';
|
|
9
|
+
|
|
10
|
+
import { HERO_COLORS } from '../../constants';
|
|
11
|
+
import { HeroColor } from '../../types';
|
|
12
|
+
import styles from './styles.module.scss';
|
|
13
|
+
import { getTitleTypographyProps } from './utils';
|
|
14
|
+
|
|
15
|
+
export type HeroZeroProps = WithSupportProps<
|
|
16
|
+
WithLayoutType<{
|
|
17
|
+
/** Хлебные крошки */
|
|
18
|
+
breadcrumbs: Item[];
|
|
19
|
+
/** Название секции */
|
|
20
|
+
title: string;
|
|
21
|
+
/** Описание секции */
|
|
22
|
+
description?: string;
|
|
23
|
+
/** Массив с настройками кнопок ButtonFilled */
|
|
24
|
+
buttons?: [ButtonFilledProps, ButtonFilledProps?];
|
|
25
|
+
/** Наличие нижнего паддинга */
|
|
26
|
+
showBottomPadding?: boolean;
|
|
27
|
+
/** Цвет фона */
|
|
28
|
+
backgroundColor?: HeroColor;
|
|
29
|
+
/** Выравнивание текста */
|
|
30
|
+
contentAlign?: 'left' | 'center';
|
|
31
|
+
/** CSS - класснейм */
|
|
32
|
+
className?: string;
|
|
33
|
+
}>
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
export function HeroZero({
|
|
37
|
+
breadcrumbs,
|
|
38
|
+
title,
|
|
39
|
+
description,
|
|
40
|
+
layoutType,
|
|
41
|
+
buttons,
|
|
42
|
+
className,
|
|
43
|
+
backgroundColor = HERO_COLORS.NeutralBackground,
|
|
44
|
+
showBottomPadding = true,
|
|
45
|
+
contentAlign = 'left',
|
|
46
|
+
...rest
|
|
47
|
+
}: HeroZeroProps) {
|
|
48
|
+
return (
|
|
49
|
+
<Layout.SectionWrapper
|
|
50
|
+
layoutType={layoutType}
|
|
51
|
+
className={cn(className, styles.sectionWrapper)}
|
|
52
|
+
data-section-background={backgroundColor}
|
|
53
|
+
{...extractSupportProps(rest)}
|
|
54
|
+
>
|
|
55
|
+
<div className={cn(styles.heroZero, { [styles.withBottomPadding]: showBottomPadding })}>
|
|
56
|
+
<div className={styles.contentLayout} data-layout-type={layoutType}>
|
|
57
|
+
<div className={styles.contentText} data-layout-type={layoutType}>
|
|
58
|
+
<Breadcrumbs items={breadcrumbs} size='xs' />
|
|
59
|
+
|
|
60
|
+
<div className={styles.text} data-layout-type={layoutType} data-align={contentAlign}>
|
|
61
|
+
<Typography family='sans' tag='h1' className={styles.title} {...getTitleTypographyProps(layoutType)}>
|
|
62
|
+
{title}
|
|
63
|
+
</Typography>
|
|
64
|
+
|
|
65
|
+
{description && (
|
|
66
|
+
<Typography.SansBodyL tag='div' className={styles.description}>
|
|
67
|
+
<RichText richText={description} />
|
|
68
|
+
</Typography.SansBodyL>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
{buttons && buttons.length > 0 && (
|
|
74
|
+
<div className={styles.buttons} data-layout-type={layoutType} data-align={contentAlign}>
|
|
75
|
+
{buttons.map((props, index) => (
|
|
76
|
+
<ButtonFilled key={index} className={styles.button} {...props} data-layout-type={layoutType} />
|
|
77
|
+
))}
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</Layout.SectionWrapper>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './HeroZero';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
@use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
|
|
2
|
+
|
|
3
|
+
.heroZero {
|
|
4
|
+
position: relative;
|
|
5
|
+
padding: var.$dimension-5m 0 0;
|
|
6
|
+
|
|
7
|
+
&[data-layout-type='tablet'] {
|
|
8
|
+
padding: var.$dimension-4m 0 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&[data-layout-type='mobile'] {
|
|
12
|
+
padding: var.$dimension-3m 0 0;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.sectionWrapper {
|
|
17
|
+
&[data-section-background='neutral-background1-level'] {
|
|
18
|
+
background-color: var.$sys-neutral-background1-level;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&[data-section-background='neutral-background'] {
|
|
22
|
+
background-color: var.$sys-neutral-background;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.withBottomPadding {
|
|
27
|
+
padding-bottom: var.$dimension-5m;
|
|
28
|
+
|
|
29
|
+
&[data-layout-type='tablet'] {
|
|
30
|
+
padding-bottom: var.$dimension-4m;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&[data-layout-type='mobile'] {
|
|
34
|
+
padding-bottom: var.$dimension-3m;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.contentLayout {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
gap: var.$dimension-6m;
|
|
42
|
+
|
|
43
|
+
&[data-layout-type='tablet'] {
|
|
44
|
+
gap: var.$dimension-4m;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&[data-layout-type='mobile'] {
|
|
48
|
+
gap: var.$dimension-3m;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.contentText {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
gap: var.$dimension-4m;
|
|
56
|
+
|
|
57
|
+
&[data-layout-type='tablet'],
|
|
58
|
+
&[data-layout-type='mobile']{
|
|
59
|
+
gap: var.$dimension-3m;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.text {
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
gap: calc(#{var.$dimension-1m + var.$dimension-050m});
|
|
67
|
+
max-width: 800px;
|
|
68
|
+
text-align: left;
|
|
69
|
+
|
|
70
|
+
&[data-layout-type='tablet'],
|
|
71
|
+
&[data-layout-type='mobile']{
|
|
72
|
+
gap: var.$dimension-1m;
|
|
73
|
+
max-width: unset;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&[data-align='center'] {
|
|
77
|
+
text-align: center;
|
|
78
|
+
align-self: center;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.title {
|
|
83
|
+
color: var.$sys-neutral-text-main;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.description {
|
|
87
|
+
color: var.$sys-neutral-text-support;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.buttons {
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-direction: row;
|
|
93
|
+
gap: var.$dimension-2m;
|
|
94
|
+
|
|
95
|
+
&[data-layout-type='tablet'],
|
|
96
|
+
&[data-layout-type='mobile'] {
|
|
97
|
+
flex-direction: column;
|
|
98
|
+
gap: var.$dimension-1m;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&[data-align='center'] {
|
|
102
|
+
justify-content: center;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.button{
|
|
107
|
+
&[data-layout-type='tablet'],
|
|
108
|
+
&[data-layout-type='mobile'] {
|
|
109
|
+
width: 100%;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LayoutType } from '@cloud-ru/uikit-product-utils';
|
|
2
|
+
import { TypographyProps } from '@snack-uikit/typography';
|
|
3
|
+
|
|
4
|
+
export const getTitleTypographyProps = (layoutType: LayoutType): Pick<TypographyProps, 'size' | 'purpose'> => {
|
|
5
|
+
switch (layoutType) {
|
|
6
|
+
case 'tablet':
|
|
7
|
+
case 'mobile':
|
|
8
|
+
return { purpose: 'headline', size: 'l' };
|
|
9
|
+
|
|
10
|
+
case 'desktop':
|
|
11
|
+
case 'desktopSmall':
|
|
12
|
+
default:
|
|
13
|
+
return { purpose: 'display', size: 'm' };
|
|
14
|
+
}
|
|
15
|
+
};
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const HERO_EVENT_BUTTONS = {
|
|
2
|
+
Registration: 'registration',
|
|
3
|
+
RegistrationClosed: 'registration-closed',
|
|
4
|
+
Watch: 'watch',
|
|
5
|
+
WatchLater: 'watch-later',
|
|
6
|
+
AdditionalMaterials: 'additional-materials',
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export const HERO_COLORS = {
|
|
10
|
+
NeutralBackground1Level: 'neutral-background1-level',
|
|
11
|
+
NeutralBackground: 'neutral-background',
|
|
12
|
+
} as const;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MouseEventHandler } from 'react';
|
|
2
|
+
|
|
3
|
+
import { WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
4
|
+
import { ButtonFilled, ButtonFilledProps } from '@snack-uikit/button';
|
|
5
|
+
|
|
6
|
+
import { HERO_BUTTON_META } from './constants';
|
|
7
|
+
import { HeroButtonType } from './types';
|
|
8
|
+
|
|
9
|
+
export type HeroButtonProps = Pick<ButtonFilledProps, 'label' | 'href' | 'disabled' | 'icon'> & {
|
|
10
|
+
type?: HeroButtonType;
|
|
11
|
+
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type HeroButtonPropsInternal = WithLayoutType<HeroButtonProps>;
|
|
15
|
+
|
|
16
|
+
export function HeroEventButton({ href, label, disabled, icon, onClick, type, layoutType }: HeroButtonPropsInternal) {
|
|
17
|
+
const meta = type ? HERO_BUTTON_META[type] : undefined;
|
|
18
|
+
const Icon = meta?.icon;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<ButtonFilled
|
|
22
|
+
size='l'
|
|
23
|
+
onClick={onClick}
|
|
24
|
+
href={href}
|
|
25
|
+
target='_blank'
|
|
26
|
+
disabled={meta?.disabled ?? disabled}
|
|
27
|
+
label={meta?.label ?? label}
|
|
28
|
+
icon={(Icon && <Icon />) ?? icon}
|
|
29
|
+
fullWidth={['mobile', 'tablet'].includes(layoutType)}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { JSXElementConstructor } from 'react';
|
|
2
|
+
|
|
3
|
+
import { DownloadSVG, PlaySVG } from '@cloud-ru/uikit-product-icons';
|
|
4
|
+
|
|
5
|
+
import { HERO_EVENT_BUTTONS } from '../../constants';
|
|
6
|
+
import { HeroButtonType } from './types';
|
|
7
|
+
|
|
8
|
+
export const HERO_BUTTON_META: Record<
|
|
9
|
+
HeroButtonType,
|
|
10
|
+
{
|
|
11
|
+
label: string;
|
|
12
|
+
icon?: JSXElementConstructor<{ size?: number }>;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
> = {
|
|
16
|
+
[HERO_EVENT_BUTTONS.Watch]: { label: 'Смотреть запись', icon: PlaySVG },
|
|
17
|
+
[HERO_EVENT_BUTTONS.WatchLater]: { label: 'Запись скоро будет', icon: PlaySVG, disabled: true },
|
|
18
|
+
[HERO_EVENT_BUTTONS.AdditionalMaterials]: { label: 'Получить материал', icon: DownloadSVG },
|
|
19
|
+
[HERO_EVENT_BUTTONS.Registration]: { label: 'Регистрация' },
|
|
20
|
+
[HERO_EVENT_BUTTONS.RegistrationClosed]: { label: 'Регистрация закрыта', disabled: true },
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './HeroEventButton';
|