@cloud-ru/uikit-product-site-cards 0.11.3
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 +690 -0
- package/LICENSE +201 -0
- package/README.md +8 -0
- package/package.json +51 -0
- package/src/components/CardBasic/CardBasic.tsx +74 -0
- package/src/components/CardBasic/index.ts +1 -0
- package/src/components/CardBasic/styles.module.scss +45 -0
- package/src/components/CardBasic/utils.ts +14 -0
- package/src/components/CardCase/CardCase.tsx +123 -0
- package/src/components/CardCase/index.ts +1 -0
- package/src/components/CardCase/styles.module.scss +68 -0
- package/src/components/CardInfo/CardInfo.tsx +120 -0
- package/src/components/CardInfo/index.ts +1 -0
- package/src/components/CardInfo/styles.module.scss +52 -0
- package/src/components/CardInfo/utilsTypes.ts +3 -0
- package/src/components/CardList/CardList.tsx +90 -0
- package/src/components/CardList/index.ts +1 -0
- package/src/components/CardList/styles.module.scss +102 -0
- package/src/components/CardList/utils.ts +35 -0
- package/src/components/CardMarketplace/CardMarketplace.tsx +112 -0
- package/src/components/CardMarketplace/index.ts +1 -0
- package/src/components/CardMarketplace/styles.module.scss +73 -0
- package/src/components/CardMedia/CardMedia.tsx +123 -0
- package/src/components/CardMedia/index.ts +1 -0
- package/src/components/CardMedia/styles.module.scss +157 -0
- package/src/components/CardMedia/types.ts +3 -0
- package/src/components/CardMedia/utils.ts +23 -0
- package/src/components/CardPartner/CardPartner.tsx +90 -0
- package/src/components/CardPartner/index.ts +1 -0
- package/src/components/CardPartner/styles.module.scss +60 -0
- package/src/components/CardProduct/CardProduct.tsx +123 -0
- package/src/components/CardProduct/constants.ts +11 -0
- package/src/components/CardProduct/index.ts +1 -0
- package/src/components/CardProduct/styles.module.scss +73 -0
- package/src/components/index.ts +8 -0
- package/src/components/utils.ts +15 -0
- package/src/constants.ts +1 -0
- package/src/helperComponents/Icon/Icon.tsx +31 -0
- package/src/helperComponents/Icon/index.ts +1 -0
- package/src/helperComponents/Icon/styles.module.scss +49 -0
- package/src/hooks.ts +40 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import { AnchorHTMLAttributes, MouseEvent } from 'react';
|
|
3
|
+
|
|
4
|
+
import { RichText } from '@cloud-ru/uikit-product-site-rich-text';
|
|
5
|
+
import { TagSpecial, TagSpecialProps } from '@cloud-ru/uikit-product-site-tag';
|
|
6
|
+
import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
|
|
7
|
+
import { Card } from '@snack-uikit/card';
|
|
8
|
+
import { Typography } from '@snack-uikit/typography';
|
|
9
|
+
|
|
10
|
+
import { Icon, IconProps } from '../../helperComponents/Icon';
|
|
11
|
+
import { useCardInteractions } from '../../hooks';
|
|
12
|
+
import { getTypographySize } from '../utils';
|
|
13
|
+
import styles from './styles.module.scss';
|
|
14
|
+
|
|
15
|
+
export type CardInfoProps = WithSupportProps<
|
|
16
|
+
WithLayoutType<{
|
|
17
|
+
/** Заголовок карточки*/
|
|
18
|
+
title: string;
|
|
19
|
+
/** Описание карточки */
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Ссылка */
|
|
22
|
+
href?: string;
|
|
23
|
+
/** HTML-аттрибут target */
|
|
24
|
+
target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
|
|
25
|
+
/** Колбек клика*/
|
|
26
|
+
onClick?(e?: MouseEvent<HTMLDivElement | HTMLAnchorElement>): void;
|
|
27
|
+
/** Слот под иконку/кастомную ноду */
|
|
28
|
+
icon?: IconProps['icon'];
|
|
29
|
+
/** Тег */
|
|
30
|
+
tag?: Pick<TagSpecialProps, 'text' | 'appearance'>;
|
|
31
|
+
/**
|
|
32
|
+
* Является ли деактивированным
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
/** Наличие обводки */
|
|
37
|
+
outline?: boolean;
|
|
38
|
+
/** CSS-класс */
|
|
39
|
+
className?: string;
|
|
40
|
+
}>
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
export function CardInfo({
|
|
44
|
+
title,
|
|
45
|
+
description,
|
|
46
|
+
icon,
|
|
47
|
+
href,
|
|
48
|
+
target = '_blank',
|
|
49
|
+
onClick,
|
|
50
|
+
tag,
|
|
51
|
+
disabled = false,
|
|
52
|
+
className,
|
|
53
|
+
layoutType,
|
|
54
|
+
outline,
|
|
55
|
+
'data-test-id': dataTestId = 'card-info',
|
|
56
|
+
...rest
|
|
57
|
+
}: CardInfoProps) {
|
|
58
|
+
const { anchorRef, handleLinkClick, handleCardClick, handleCardKeyDown } = useCardInteractions({
|
|
59
|
+
href,
|
|
60
|
+
disabled,
|
|
61
|
+
onClick,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Card
|
|
66
|
+
{...extractSupportProps(rest)}
|
|
67
|
+
size='m'
|
|
68
|
+
className={cn(styles.card, className)}
|
|
69
|
+
disabled={disabled}
|
|
70
|
+
outline={outline}
|
|
71
|
+
onClick={handleCardClick}
|
|
72
|
+
onKeyDown={handleCardKeyDown}
|
|
73
|
+
data-test-id={dataTestId}
|
|
74
|
+
>
|
|
75
|
+
<div data-layout-type={layoutType} className={styles.wrapper}>
|
|
76
|
+
{tag && <TagSpecial {...tag} className={styles.tag} data-test-id={`${dataTestId}__tag`} />}
|
|
77
|
+
|
|
78
|
+
{icon && <Icon size='m' data-test-id={`${dataTestId}__icon`} icon={icon} />}
|
|
79
|
+
|
|
80
|
+
<div className={styles.content}>
|
|
81
|
+
<Typography
|
|
82
|
+
tag='h3'
|
|
83
|
+
family='sans'
|
|
84
|
+
purpose='title'
|
|
85
|
+
size={getTypographySize(layoutType)}
|
|
86
|
+
className={styles.title}
|
|
87
|
+
data-test-id={`${dataTestId}__title`}
|
|
88
|
+
>
|
|
89
|
+
{href ? (
|
|
90
|
+
<a
|
|
91
|
+
tabIndex={-1}
|
|
92
|
+
ref={anchorRef}
|
|
93
|
+
href={href}
|
|
94
|
+
target={target}
|
|
95
|
+
onClick={handleLinkClick}
|
|
96
|
+
data-test-id={`${dataTestId}__title-link`}
|
|
97
|
+
>
|
|
98
|
+
<RichText richText={title} />
|
|
99
|
+
</a>
|
|
100
|
+
) : (
|
|
101
|
+
<RichText richText={title} />
|
|
102
|
+
)}
|
|
103
|
+
</Typography>
|
|
104
|
+
|
|
105
|
+
{description && (
|
|
106
|
+
<Typography
|
|
107
|
+
tag='div'
|
|
108
|
+
family='sans'
|
|
109
|
+
purpose='body'
|
|
110
|
+
size={getTypographySize(layoutType)}
|
|
111
|
+
data-test-id={`${dataTestId}__description`}
|
|
112
|
+
>
|
|
113
|
+
<RichText className={styles.description} richText={description} />
|
|
114
|
+
</Typography>
|
|
115
|
+
)}
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</Card>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CardInfo';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
@use '@sbercloud/figma-tokens-web/build/scss/components/styles-tokens-element' as ste;
|
|
2
|
+
|
|
3
|
+
.card {
|
|
4
|
+
position: relative;
|
|
5
|
+
border-radius: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.wrapper {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: row;
|
|
11
|
+
gap: ste.$dimension-2m;
|
|
12
|
+
|
|
13
|
+
.content {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: ste.$dimension-050m;
|
|
17
|
+
|
|
18
|
+
.title {
|
|
19
|
+
color: ste.$sys-neutral-text-main;
|
|
20
|
+
|
|
21
|
+
a {
|
|
22
|
+
color: ste.$sys-neutral-text-main;
|
|
23
|
+
text-decoration: none;
|
|
24
|
+
|
|
25
|
+
&::before {
|
|
26
|
+
content: '';
|
|
27
|
+
position: absolute;
|
|
28
|
+
top: 0;
|
|
29
|
+
left: 0;
|
|
30
|
+
right: 0;
|
|
31
|
+
bottom: 0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.description {
|
|
37
|
+
color: ste.$sys-neutral-text-support;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.tag {
|
|
42
|
+
position: absolute;
|
|
43
|
+
right: ste.$dimension-050m;
|
|
44
|
+
top: ste.$dimension-050m;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&[data-layout-type='tablet'],
|
|
48
|
+
&[data-layout-type='mobile'] {
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
gap: 12px;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import { AnchorHTMLAttributes, MouseEvent } from 'react';
|
|
3
|
+
|
|
4
|
+
import { TagSpecial, TagSpecialProps } from '@cloud-ru/uikit-product-site-tag';
|
|
5
|
+
import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
|
|
6
|
+
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
7
|
+
import { Typography } from '@snack-uikit/typography';
|
|
8
|
+
|
|
9
|
+
import styles from './styles.module.scss';
|
|
10
|
+
import { getTitleTruncateMaxLines, getTitleTypographyProps } from './utils';
|
|
11
|
+
|
|
12
|
+
export type CardListProps = WithSupportProps<
|
|
13
|
+
WithLayoutType<{
|
|
14
|
+
/** Изображение */
|
|
15
|
+
img: string;
|
|
16
|
+
/** Теги */
|
|
17
|
+
tags: Omit<TagSpecialProps, 'size' | 'className'>[];
|
|
18
|
+
/** Ссылка */
|
|
19
|
+
href: string;
|
|
20
|
+
/** HTML-аттрибут target */
|
|
21
|
+
target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
|
|
22
|
+
/** Колбек клика*/
|
|
23
|
+
onClick?(e: MouseEvent<HTMLAnchorElement>): void;
|
|
24
|
+
/**
|
|
25
|
+
* Является ли деактивированным
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/** CSS-класс */
|
|
30
|
+
className?: string;
|
|
31
|
+
/** Заголовок */
|
|
32
|
+
title: string;
|
|
33
|
+
/** Дата */
|
|
34
|
+
labelDate?: string;
|
|
35
|
+
}>
|
|
36
|
+
>;
|
|
37
|
+
|
|
38
|
+
export function CardList({
|
|
39
|
+
disabled,
|
|
40
|
+
layoutType,
|
|
41
|
+
img,
|
|
42
|
+
title,
|
|
43
|
+
className,
|
|
44
|
+
labelDate,
|
|
45
|
+
href,
|
|
46
|
+
onClick,
|
|
47
|
+
tags,
|
|
48
|
+
target,
|
|
49
|
+
'data-test-id': dataTestId = 'card-list',
|
|
50
|
+
...rest
|
|
51
|
+
}: CardListProps) {
|
|
52
|
+
return (
|
|
53
|
+
<a
|
|
54
|
+
{...extractSupportProps(rest)}
|
|
55
|
+
href={href}
|
|
56
|
+
target={target}
|
|
57
|
+
className={cn(styles.wrapper, className)}
|
|
58
|
+
aria-disabled={disabled || undefined}
|
|
59
|
+
tabIndex={disabled ? -1 : 0}
|
|
60
|
+
onClick={disabled ? undefined : onClick}
|
|
61
|
+
data-layout-type={layoutType}
|
|
62
|
+
>
|
|
63
|
+
<div className={styles.imgWrapper} data-test-id={`${dataTestId}-imgWrapper`}>
|
|
64
|
+
<img className={styles.img} src={img} alt='card_img' data-test-id={`${dataTestId}-img`} />
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div className={styles.content}>
|
|
68
|
+
<div className={styles.tagRow}>
|
|
69
|
+
{tags.map((tag, idx) => (
|
|
70
|
+
<TagSpecial {...tag} key={idx} />
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<Typography className={styles.title} tag='h3' family='sans' {...getTitleTypographyProps({ layoutType })}>
|
|
75
|
+
<TruncateString
|
|
76
|
+
text={title}
|
|
77
|
+
maxLines={getTitleTruncateMaxLines({ layoutType })}
|
|
78
|
+
data-test-id={`${dataTestId}-title`}
|
|
79
|
+
/>
|
|
80
|
+
</Typography>
|
|
81
|
+
|
|
82
|
+
{labelDate && (
|
|
83
|
+
<Typography.SansBodyS className={styles.labelDate} data-test-id={`${dataTestId}-time`}>
|
|
84
|
+
{labelDate}
|
|
85
|
+
</Typography.SansBodyS>
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
</a>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CardList';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
@use '@sbercloud/figma-tokens-web/build/scss/styles-theme-variables' as var;
|
|
2
|
+
@use '@sbercloud/figma-tokens-web/build/scss/components/styles-tokens-element' as element;
|
|
3
|
+
|
|
4
|
+
$transition: 0.3s;
|
|
5
|
+
$scale: 1.05;
|
|
6
|
+
|
|
7
|
+
.title {
|
|
8
|
+
flex: 1 0 auto;
|
|
9
|
+
|
|
10
|
+
color: var.$sys-neutral-text-main;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.img,
|
|
14
|
+
.title {
|
|
15
|
+
transition: all $transition;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.imgWrapper {
|
|
19
|
+
.img {
|
|
20
|
+
height: 100%;
|
|
21
|
+
width: 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
aspect-ratio: 1.6;
|
|
25
|
+
height: 176px;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.wrapper {
|
|
30
|
+
display: grid;
|
|
31
|
+
grid-template-columns: auto 1fr;
|
|
32
|
+
gap: var.$dimension-2m;
|
|
33
|
+
text-decoration: none;
|
|
34
|
+
|
|
35
|
+
&[data-layout-type='tablet'] {
|
|
36
|
+
.imgWrapper {
|
|
37
|
+
height: 160px;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&[data-layout-type='mobile'] {
|
|
42
|
+
.imgWrapper {
|
|
43
|
+
aspect-ratio: unset;
|
|
44
|
+
width: 100%;
|
|
45
|
+
height: auto;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
grid-template-columns: 1fr;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&[aria-disabled] {
|
|
52
|
+
pointer-events: none;
|
|
53
|
+
cursor: not-allowed;
|
|
54
|
+
|
|
55
|
+
.title {
|
|
56
|
+
color: var.$sys-neutral-text-disabled;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.imgWrapper {
|
|
60
|
+
opacity: 0.5;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&:not([aria-disabled]) {
|
|
65
|
+
&:hover {
|
|
66
|
+
.title {
|
|
67
|
+
color: var.$sys-primary-accent-hovered;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&:focus-visible {
|
|
72
|
+
@include element.outline-var(element.$container-focused-m);
|
|
73
|
+
|
|
74
|
+
outline-color: var.$sys-primary-decor-activated;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&:hover,
|
|
78
|
+
&:focus-visible {
|
|
79
|
+
.img {
|
|
80
|
+
scale: $scale;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.tagRow {
|
|
87
|
+
display: flex;
|
|
88
|
+
justify-content: flex-start;
|
|
89
|
+
gap: var.$dimension-1m;
|
|
90
|
+
|
|
91
|
+
flex-wrap: wrap;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.content {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
gap: var.$dimension-2m;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.labelDate {
|
|
101
|
+
color: var.$sys-neutral-text-light;
|
|
102
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { LAYOUT_TYPE, WithLayoutType } from '@cloud-ru/uikit-product-utils';
|
|
2
|
+
import { PURPOSE, SIZE, TypographyProps } from '@snack-uikit/typography';
|
|
3
|
+
|
|
4
|
+
type Props = WithLayoutType<unknown>;
|
|
5
|
+
|
|
6
|
+
export const getTitleTypographyProps = ({ layoutType }: Props): Pick<TypographyProps, 'size' | 'purpose'> => {
|
|
7
|
+
switch (layoutType) {
|
|
8
|
+
case LAYOUT_TYPE.Mobile:
|
|
9
|
+
case LAYOUT_TYPE.Tablet:
|
|
10
|
+
return {
|
|
11
|
+
purpose: PURPOSE.Title,
|
|
12
|
+
size: SIZE.L,
|
|
13
|
+
};
|
|
14
|
+
case LAYOUT_TYPE.Desktop:
|
|
15
|
+
case LAYOUT_TYPE.DesktopSmall:
|
|
16
|
+
default:
|
|
17
|
+
return {
|
|
18
|
+
purpose: PURPOSE.Headline,
|
|
19
|
+
size: SIZE.S,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const getTitleTruncateMaxLines = ({ layoutType }: Props): number => {
|
|
25
|
+
switch (layoutType) {
|
|
26
|
+
case LAYOUT_TYPE.Mobile:
|
|
27
|
+
return 5;
|
|
28
|
+
case LAYOUT_TYPE.Tablet:
|
|
29
|
+
return 3;
|
|
30
|
+
case LAYOUT_TYPE.Desktop:
|
|
31
|
+
case LAYOUT_TYPE.DesktopSmall:
|
|
32
|
+
default:
|
|
33
|
+
return 2;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import { AnchorHTMLAttributes, MouseEvent } from 'react';
|
|
3
|
+
|
|
4
|
+
import { TagSpecial, TagSpecialProps } from '@cloud-ru/uikit-product-site-tag';
|
|
5
|
+
import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
|
|
6
|
+
import { Card } from '@snack-uikit/card';
|
|
7
|
+
import { TruncateString } from '@snack-uikit/truncate-string';
|
|
8
|
+
import { Typography } from '@snack-uikit/typography';
|
|
9
|
+
|
|
10
|
+
import { useCardInteractions } from '../../hooks';
|
|
11
|
+
import { getTypographySize } from '../utils';
|
|
12
|
+
import styles from './styles.module.scss';
|
|
13
|
+
|
|
14
|
+
export type CardMarketplaceProps = WithSupportProps<
|
|
15
|
+
WithLayoutType<{
|
|
16
|
+
/** Заголовок карточки*/
|
|
17
|
+
title: string;
|
|
18
|
+
/** Описание карточки */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Ссылка */
|
|
21
|
+
href: string;
|
|
22
|
+
/** HTML-аттрибут target */
|
|
23
|
+
target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
|
|
24
|
+
/** Колбек клика*/
|
|
25
|
+
onClick?(e?: MouseEvent<HTMLDivElement | HTMLAnchorElement>): void;
|
|
26
|
+
/** Ссылка на изображение */
|
|
27
|
+
logo: {
|
|
28
|
+
src: string;
|
|
29
|
+
alt?: string;
|
|
30
|
+
};
|
|
31
|
+
/** Тег */
|
|
32
|
+
tag?: Omit<TagSpecialProps, 'className'>;
|
|
33
|
+
/**
|
|
34
|
+
* Является ли деактивированным
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
/** CSS-класс */
|
|
39
|
+
className?: string;
|
|
40
|
+
}>
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
export function CardMarketplace({
|
|
44
|
+
title,
|
|
45
|
+
description,
|
|
46
|
+
logo,
|
|
47
|
+
href,
|
|
48
|
+
target = '_blank',
|
|
49
|
+
onClick,
|
|
50
|
+
tag,
|
|
51
|
+
disabled = false,
|
|
52
|
+
className,
|
|
53
|
+
layoutType,
|
|
54
|
+
'data-test-id': dataTestId = 'card-marketplace',
|
|
55
|
+
...rest
|
|
56
|
+
}: CardMarketplaceProps) {
|
|
57
|
+
const { anchorRef, handleCardKeyDown, handleCardClick, handleLinkClick } = useCardInteractions({
|
|
58
|
+
href,
|
|
59
|
+
onClick,
|
|
60
|
+
disabled,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<Card
|
|
65
|
+
{...extractSupportProps(rest)}
|
|
66
|
+
size='m'
|
|
67
|
+
className={cn(styles.card, className)}
|
|
68
|
+
disabled={disabled}
|
|
69
|
+
onClick={handleCardClick}
|
|
70
|
+
onKeyDown={handleCardKeyDown}
|
|
71
|
+
data-test-id={dataTestId}
|
|
72
|
+
outline
|
|
73
|
+
>
|
|
74
|
+
<div data-layout-type={layoutType} className={styles.wrapper}>
|
|
75
|
+
<img alt={logo.alt ?? title} data-test-id={`${dataTestId}__logo`} src={logo.src} className={styles.logo} />
|
|
76
|
+
|
|
77
|
+
<div className={styles.content}>
|
|
78
|
+
<Typography
|
|
79
|
+
tag='h3'
|
|
80
|
+
family='sans'
|
|
81
|
+
purpose='title'
|
|
82
|
+
size={getTypographySize(layoutType)}
|
|
83
|
+
className={styles.title}
|
|
84
|
+
data-test-id={`${dataTestId}__title`}
|
|
85
|
+
>
|
|
86
|
+
<a
|
|
87
|
+
tabIndex={-1}
|
|
88
|
+
ref={anchorRef}
|
|
89
|
+
href={href}
|
|
90
|
+
target={target}
|
|
91
|
+
onClick={handleLinkClick}
|
|
92
|
+
data-test-id={`${dataTestId}__title-link`}
|
|
93
|
+
>
|
|
94
|
+
<TruncateString text={title} maxLines={2} />
|
|
95
|
+
</a>
|
|
96
|
+
</Typography>
|
|
97
|
+
|
|
98
|
+
{description && (
|
|
99
|
+
<TruncateString
|
|
100
|
+
className={styles.description}
|
|
101
|
+
text={description}
|
|
102
|
+
maxLines={4}
|
|
103
|
+
data-test-id={`${dataTestId}__description`}
|
|
104
|
+
/>
|
|
105
|
+
)}
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
{tag && <TagSpecial data-test-id={`${dataTestId}__tag`} className={styles.tag} {...tag} />}
|
|
109
|
+
</div>
|
|
110
|
+
</Card>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CardMarketplace';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
@use '@sbercloud/figma-tokens-web/build/scss/components/styles-tokens-card' as ste;
|
|
2
|
+
|
|
3
|
+
.card {
|
|
4
|
+
position: relative;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.wrapper {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
align-items: flex-start;
|
|
11
|
+
gap: 20px;
|
|
12
|
+
|
|
13
|
+
&[data-layout-type=mobile],
|
|
14
|
+
&[data-layout-type=tablet] {
|
|
15
|
+
gap: 12px;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.content {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
align-items: flex-start;
|
|
23
|
+
gap: 8px;
|
|
24
|
+
width: 100%;
|
|
25
|
+
|
|
26
|
+
[data-layout-type=mobile] &,
|
|
27
|
+
[data-layout-type=tablet] & {
|
|
28
|
+
gap: 4px;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
.title {
|
|
34
|
+
color: ste.$sys-neutral-text-main;
|
|
35
|
+
|
|
36
|
+
a {
|
|
37
|
+
color: inherit;
|
|
38
|
+
text-decoration: none;
|
|
39
|
+
|
|
40
|
+
&::before {
|
|
41
|
+
content: '';
|
|
42
|
+
position: absolute;
|
|
43
|
+
top: 0;
|
|
44
|
+
left: 0;
|
|
45
|
+
right: 0;
|
|
46
|
+
bottom: 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.description {
|
|
52
|
+
@include ste.composite-var(ste.$sans-body-l);
|
|
53
|
+
|
|
54
|
+
color: ste.$sys-neutral-text-support;
|
|
55
|
+
|
|
56
|
+
[data-layout-type=mobile] &,
|
|
57
|
+
[data-layout-type=tablet] & {
|
|
58
|
+
@include ste.composite-var(ste.$sans-body-m);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.tag {
|
|
63
|
+
position: absolute;
|
|
64
|
+
right: ste.simple-var(ste.$card-content-m-container, 'padding');
|
|
65
|
+
top: ste.simple-var(ste.$card-content-m-container, 'padding');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.logo {
|
|
69
|
+
flex-shrink: 0;
|
|
70
|
+
height: 40px;
|
|
71
|
+
width: 40px;
|
|
72
|
+
object-fit: contain;
|
|
73
|
+
}
|