@cloud-ru/ds-uikit-product-header 1.3.9 → 1.3.10-preview-1030ded1.0
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/README.md +6 -2
- package/dist/cjs/components/MainMenu/helperComponents/Banners/MenuBanner.d.ts +1 -1
- package/dist/cjs/components/MainMenu/helperComponents/Banners/MenuBanner.js +3 -2
- package/dist/cjs/components/MainMenu/helperComponents/Banners/styles.module.css +11 -15
- package/dist/cjs/components/MainMenu/helperComponents/Content/Content.js +0 -5
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupCards.js +1 -1
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/SubCategory.js +16 -2
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/styles.module.css +7 -1
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.css +3 -0
- package/dist/cjs/components/MainMenu/helperComponents/Favorites/styles.module.css +2 -2
- package/dist/cjs/components/MainMenu/helperComponents/ServiceCard/ServiceCard.js +0 -3
- package/dist/cjs/components/MainMenu/types.d.ts +14 -3
- package/dist/cjs/components/MainMenu/utils/innerLink.d.ts +10 -0
- package/dist/cjs/components/MainMenu/utils/innerLink.js +20 -0
- package/dist/cjs/style.css +23 -18
- package/dist/esm/components/MainMenu/helperComponents/Banners/MenuBanner.d.ts +1 -1
- package/dist/esm/components/MainMenu/helperComponents/Banners/MenuBanner.js +3 -2
- package/dist/esm/components/MainMenu/helperComponents/Banners/styles.module.css +11 -15
- package/dist/esm/components/MainMenu/helperComponents/Content/Content.js +1 -6
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupCards.js +2 -2
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/SubCategory.js +17 -3
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/styles.module.css +7 -1
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.css +3 -0
- package/dist/esm/components/MainMenu/helperComponents/Favorites/styles.module.css +2 -2
- package/dist/esm/components/MainMenu/helperComponents/ServiceCard/ServiceCard.js +0 -3
- package/dist/esm/components/MainMenu/types.d.ts +14 -3
- package/dist/esm/components/MainMenu/utils/innerLink.d.ts +10 -0
- package/dist/esm/components/MainMenu/utils/innerLink.js +19 -0
- package/dist/esm/style.css +23 -18
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +28 -27
- package/src/components/MainMenu/helperComponents/Banners/MenuBanner.tsx +44 -42
- package/src/components/MainMenu/helperComponents/Banners/styles.module.scss +15 -22
- package/src/components/MainMenu/helperComponents/Content/Content.tsx +1 -7
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupCards.tsx +2 -2
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/SubCategory.tsx +61 -2
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/styles.module.scss +10 -1
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.scss +5 -0
- package/src/components/MainMenu/helperComponents/Favorites/styles.module.scss +3 -2
- package/src/components/MainMenu/helperComponents/ServiceCard/ServiceCard.tsx +0 -4
- package/src/components/MainMenu/types.ts +15 -3
- package/src/components/MainMenu/utils/innerLink.ts +23 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloud-ru/ds-uikit-product-header",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.10-preview-1030ded1.0",
|
|
4
4
|
"description": "Продуктовая шапка консоли — HeaderLayout, MainMenu, UserMenu, Logo, PathBreadcrumbs и PlatformLogo.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -45,32 +45,33 @@
|
|
|
45
45
|
"@dnd-kit/utilities": "^3.2.2",
|
|
46
46
|
"classnames": "^2.5.1",
|
|
47
47
|
"fuse.js": "^7.1.0",
|
|
48
|
-
"@cloud-ru/ds-accordion": "
|
|
49
|
-
"@cloud-ru/ds-adaptive": "
|
|
50
|
-
"@cloud-ru/ds-avatar": "
|
|
51
|
-
"@cloud-ru/ds-
|
|
52
|
-
"@cloud-ru/ds-button": "
|
|
53
|
-
"@cloud-ru/ds-
|
|
54
|
-
"@cloud-ru/ds-
|
|
55
|
-
"@cloud-ru/ds-
|
|
56
|
-
"@cloud-ru/ds-
|
|
57
|
-
"@cloud-ru/ds-icons": "
|
|
58
|
-
"@cloud-ru/ds-list": "
|
|
59
|
-
"@cloud-ru/ds-
|
|
60
|
-
"@cloud-ru/ds-
|
|
61
|
-
"@cloud-ru/ds-
|
|
62
|
-
"@cloud-ru/ds-
|
|
63
|
-
"@cloud-ru/ds-
|
|
64
|
-
"@cloud-ru/ds-scroll": "
|
|
65
|
-
"@cloud-ru/ds-
|
|
66
|
-
"@cloud-ru/ds-
|
|
67
|
-
"@cloud-ru/ds-
|
|
68
|
-
"@cloud-ru/ds-
|
|
69
|
-
"@cloud-ru/ds-
|
|
70
|
-
"@cloud-ru/ds-
|
|
71
|
-
"@cloud-ru/ds-uikit-product-
|
|
72
|
-
"@cloud-ru/ds-
|
|
73
|
-
"@cloud-ru/ds-
|
|
48
|
+
"@cloud-ru/ds-accordion": "1.0.6",
|
|
49
|
+
"@cloud-ru/ds-adaptive": "1.0.1",
|
|
50
|
+
"@cloud-ru/ds-avatar": "1.0.3",
|
|
51
|
+
"@cloud-ru/ds-card": "1.0.12",
|
|
52
|
+
"@cloud-ru/ds-button": "1.0.2",
|
|
53
|
+
"@cloud-ru/ds-breadcrumbs": "1.0.15",
|
|
54
|
+
"@cloud-ru/ds-divider": "1.0.1",
|
|
55
|
+
"@cloud-ru/ds-drag-and-drop": "1.1.1",
|
|
56
|
+
"@cloud-ru/ds-drawer": "1.2.0",
|
|
57
|
+
"@cloud-ru/ds-icons": "1.1.0",
|
|
58
|
+
"@cloud-ru/ds-list": "2.1.4",
|
|
59
|
+
"@cloud-ru/ds-info-block": "1.0.1",
|
|
60
|
+
"@cloud-ru/ds-locale": "1.0.0",
|
|
61
|
+
"@cloud-ru/ds-modal": "1.1.1",
|
|
62
|
+
"@cloud-ru/ds-portal-context": "1.0.1",
|
|
63
|
+
"@cloud-ru/ds-promo-tag": "1.0.1",
|
|
64
|
+
"@cloud-ru/ds-scroll": "1.0.2",
|
|
65
|
+
"@cloud-ru/ds-search": "1.0.7",
|
|
66
|
+
"@cloud-ru/ds-segment-control": "1.0.5",
|
|
67
|
+
"@cloud-ru/ds-skeleton": "1.0.1",
|
|
68
|
+
"@cloud-ru/ds-theme": "1.1.0",
|
|
69
|
+
"@cloud-ru/ds-tooltip": "1.0.4",
|
|
70
|
+
"@cloud-ru/ds-typography": "1.0.0",
|
|
71
|
+
"@cloud-ru/ds-uikit-product-card-predefined": "3.0.10-preview-1030ded1.0",
|
|
72
|
+
"@cloud-ru/ds-utils": "1.1.0",
|
|
73
|
+
"@cloud-ru/ds-uikit-product-title-clickable": "1.0.8",
|
|
74
|
+
"@cloud-ru/ds-uikit-product-switch-row": "1.0.6"
|
|
74
75
|
},
|
|
75
76
|
"publishConfig": {
|
|
76
77
|
"access": "public"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Button } from '@cloud-ru/ds-button';
|
|
2
|
+
import { Card } from '@cloud-ru/ds-card';
|
|
2
3
|
import { CrossSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
3
4
|
import { PromoTag, PromoTagProps, ROLE_APPEARANCE, SIZE } from '@cloud-ru/ds-promo-tag';
|
|
4
5
|
import { useThemeClassnames } from '@cloud-ru/ds-theme';
|
|
@@ -33,7 +34,6 @@ export function MenuBanner({
|
|
|
33
34
|
onClose,
|
|
34
35
|
className,
|
|
35
36
|
href = '#',
|
|
36
|
-
target,
|
|
37
37
|
'data-test-id': dataTestId,
|
|
38
38
|
...rest
|
|
39
39
|
}: MenuBannerProps): ReactElement {
|
|
@@ -50,54 +50,56 @@ export function MenuBanner({
|
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
|
-
<
|
|
53
|
+
<Card
|
|
54
|
+
as='a'
|
|
54
55
|
href={href}
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
radius='l'
|
|
57
|
+
view='simple'
|
|
57
58
|
className={cn(styles.root, className)}
|
|
58
59
|
data-test-id={dataTestId ?? MENU_BANNER_TEST_IDS.root}
|
|
59
60
|
{...rest}
|
|
60
61
|
>
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
variant='body'
|
|
65
|
-
size='m'
|
|
66
|
-
className={styles.title}
|
|
67
|
-
data-test-id={MENU_BANNER_TEST_IDS.title}
|
|
68
|
-
>
|
|
69
|
-
{title}
|
|
70
|
-
</Typography>
|
|
71
|
-
|
|
72
|
-
{promoTag && (
|
|
73
|
-
<PromoTag
|
|
74
|
-
{...promoTag}
|
|
62
|
+
<div className={styles.contentRow}>
|
|
63
|
+
<span className={styles.titleWrapper}>
|
|
64
|
+
<Typography
|
|
75
65
|
as='span'
|
|
76
|
-
|
|
77
|
-
size=
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
66
|
+
variant='body'
|
|
67
|
+
size='m'
|
|
68
|
+
className={styles.title}
|
|
69
|
+
data-test-id={MENU_BANNER_TEST_IDS.title}
|
|
70
|
+
>
|
|
71
|
+
{title}
|
|
72
|
+
</Typography>
|
|
82
73
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
74
|
+
{promoTag && (
|
|
75
|
+
<PromoTag
|
|
76
|
+
{...promoTag}
|
|
77
|
+
roleAppearance={ROLE_APPEARANCE.Decor}
|
|
78
|
+
size={SIZE.Xs}
|
|
79
|
+
data-test-id={MENU_BANNER_TEST_IDS.promoTag}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
</span>
|
|
88
83
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
84
|
+
{afterTitle && (
|
|
85
|
+
<div className={styles.afterTitle} data-test-id={MENU_BANNER_TEST_IDS.afterTitle}>
|
|
86
|
+
{afterTitle}
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
|
|
90
|
+
{onClose && (
|
|
91
|
+
<Button
|
|
92
|
+
className={cn(styles.closeButton, compactThemeClassname)}
|
|
93
|
+
view='elevated'
|
|
94
|
+
appearance='neutral'
|
|
95
|
+
size='s'
|
|
96
|
+
icon={<CrossSVG size={16} />}
|
|
97
|
+
onClick={handleClose}
|
|
98
|
+
aria-label={t('close')}
|
|
99
|
+
data-test-id={MENU_BANNER_TEST_IDS.close}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
</Card>
|
|
102
104
|
);
|
|
103
105
|
}
|
|
@@ -11,38 +11,31 @@
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
.root {
|
|
14
|
-
position: relative;
|
|
15
|
-
|
|
16
|
-
display: flex;
|
|
17
|
-
gap: base.$sn-primitive-dimension-4;
|
|
18
|
-
align-items: center;
|
|
19
|
-
|
|
20
|
-
box-sizing: border-box;
|
|
21
14
|
width: 100%;
|
|
22
15
|
min-width: 0;
|
|
23
|
-
min-height: base.$sn-primitive-dimension-48;
|
|
24
|
-
padding: 0 base.$sn-primitive-dimension-12;
|
|
25
|
-
border-radius: base.$sn-density-radius-2xs;
|
|
26
|
-
|
|
27
|
-
font: inherit;
|
|
28
|
-
color: inherit;
|
|
29
|
-
text-align: left;
|
|
30
|
-
text-decoration: none;
|
|
31
|
-
|
|
32
|
-
background-color: base.$sn-theme-color-neutral-background1Level;
|
|
33
16
|
|
|
34
17
|
&:hover,
|
|
35
18
|
&:focus-visible,
|
|
36
|
-
&:focus-
|
|
19
|
+
&:has(*:focus-visible) {
|
|
37
20
|
.closeButton {
|
|
38
21
|
visibility: visible;
|
|
39
22
|
}
|
|
40
23
|
}
|
|
24
|
+
}
|
|
41
25
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
26
|
+
.contentRow {
|
|
27
|
+
position: relative;
|
|
28
|
+
|
|
29
|
+
display: flex;
|
|
30
|
+
gap: base.$sn-density-spacing-interval-s;
|
|
31
|
+
align-items: center;
|
|
32
|
+
|
|
33
|
+
box-sizing: border-box;
|
|
34
|
+
width: 100%;
|
|
35
|
+
min-width: 0;
|
|
36
|
+
min-height: base.$sn-primitive-dimension-40;
|
|
37
|
+
padding: 0 base.$sn-primitive-dimension-12;
|
|
38
|
+
border-radius: inherit;
|
|
46
39
|
}
|
|
47
40
|
|
|
48
41
|
.titleWrapper {
|
|
@@ -4,7 +4,7 @@ import { CrossSVG, SearchSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
|
4
4
|
import { InfoBlock } from '@cloud-ru/ds-info-block';
|
|
5
5
|
import { useValueControl } from '@cloud-ru/ds-utils';
|
|
6
6
|
import cn from 'classnames';
|
|
7
|
-
import { MouseEvent, ReactNode, useCallback, useDeferredValue,
|
|
7
|
+
import { MouseEvent, ReactNode, useCallback, useDeferredValue, useMemo } from 'react';
|
|
8
8
|
|
|
9
9
|
import { headerLocale } from '../../../../locale';
|
|
10
10
|
import { shouldBeOpenedInNewTab } from '../../../../utils/shouldBeOpenedInNewTab';
|
|
@@ -133,12 +133,6 @@ export function Content({
|
|
|
133
133
|
const isSearching = Boolean(searchValue);
|
|
134
134
|
const enableServiceDrag = Boolean(favorite) && !isMobile && !isSearching;
|
|
135
135
|
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
if (!segments?.some(segment => segment.id === segmentId) && defaultSegmentId) {
|
|
138
|
-
setSegmentId(defaultSegmentId);
|
|
139
|
-
}
|
|
140
|
-
}, [defaultSegmentId, segmentId, setSegmentId, segments]);
|
|
141
|
-
|
|
142
136
|
const handleLinkClick = useCallback(
|
|
143
137
|
(service: InnerLink, e?: MouseEvent<HTMLElement>) => {
|
|
144
138
|
if (service.disabled) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { InnerLink } from '../../../../../types';
|
|
2
|
-
import {
|
|
2
|
+
import { isSubCategoryCard } from '../../../../../utils/innerLink';
|
|
3
3
|
import { DraggableServiceCard, ServiceCardProps } from '../../../../ServiceCard';
|
|
4
4
|
import styles from '../styles.module.scss';
|
|
5
5
|
import { SubCategory } from './SubCategory';
|
|
@@ -33,7 +33,7 @@ export function SortableGroupCards({
|
|
|
33
33
|
|
|
34
34
|
const key = String(groupId) + service.id;
|
|
35
35
|
|
|
36
|
-
if (
|
|
36
|
+
if (isSubCategoryCard(service)) {
|
|
37
37
|
return (
|
|
38
38
|
<SubCategory
|
|
39
39
|
key={key}
|
|
@@ -8,6 +8,8 @@ import baseGroupStyles from '../../styles.module.scss';
|
|
|
8
8
|
import styles from './styles.module.scss';
|
|
9
9
|
import { SubCategoryTitle } from './SubCategoryTitle';
|
|
10
10
|
|
|
11
|
+
const NOOP = () => {};
|
|
12
|
+
|
|
11
13
|
export type SubCategoryProps = Pick<
|
|
12
14
|
ServiceCardProps,
|
|
13
15
|
'service' | 'onServiceClick' | 'favorite' | 'showDescription' | 'isMobile'
|
|
@@ -30,11 +32,14 @@ export function SubCategory({
|
|
|
30
32
|
const subcategoryId = getSubCategoryId(groupId, service.id);
|
|
31
33
|
const nestedGroupId = getNestedServiceGroupId(groupId, service.id);
|
|
32
34
|
const nestedItems = useMemo(() => service.items?.filter(item => !item.hidden) ?? [], [service.items]);
|
|
35
|
+
const hasItems = nestedItems.length > 0;
|
|
36
|
+
|
|
37
|
+
const viewMode = service.viewMode ?? 'expanded';
|
|
33
38
|
|
|
34
|
-
const isExpandableEnabled =
|
|
39
|
+
const isExpandableEnabled = hasItems && viewMode === 'expandable';
|
|
35
40
|
|
|
36
41
|
// Раскрытие подкатегории — локальное uncontrolled состояние: наружу его пока не выводим.
|
|
37
|
-
const [isExpanded, setIsExpanded] = useState<string | undefined>(subcategoryId);
|
|
42
|
+
const [isExpanded, setIsExpanded] = useState<string | undefined>(hasItems ? subcategoryId : undefined);
|
|
38
43
|
|
|
39
44
|
const handleExpandedChange = useCallback(() => {
|
|
40
45
|
if (isExpandableEnabled) {
|
|
@@ -42,6 +47,60 @@ export function SubCategory({
|
|
|
42
47
|
}
|
|
43
48
|
}, [isExpanded, subcategoryId, isExpandableEnabled]);
|
|
44
49
|
|
|
50
|
+
// 'group-title-only' — только заголовок подкатегории, без раскрываемого тела и кнопки
|
|
51
|
+
// переключения: карточка ведёт себя как обычная ссылка (см. isSubCategoryCard в utils/innerLink).
|
|
52
|
+
if (viewMode === 'group-title-only') {
|
|
53
|
+
return (
|
|
54
|
+
<div className={styles.subcategory} data-title-only data-test-id={`${TEST_IDS.subcategory}-${service.id}`}>
|
|
55
|
+
<SubCategoryTitle
|
|
56
|
+
groupId={groupId}
|
|
57
|
+
service={service}
|
|
58
|
+
expandable={{ value: true, onClick: NOOP }}
|
|
59
|
+
showDescription={showDescription}
|
|
60
|
+
isMobile={isMobile}
|
|
61
|
+
dragDisabled={dragDisabled}
|
|
62
|
+
favorite={groupFavoritesEnabled ? favorite : undefined}
|
|
63
|
+
onServiceClick={onServiceClick}
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (viewMode === 'expanded') {
|
|
70
|
+
return (
|
|
71
|
+
<div className={styles.subcategory} data-test-id={`${TEST_IDS.subcategory}-${service.id}`}>
|
|
72
|
+
<SubCategoryTitle
|
|
73
|
+
groupId={groupId}
|
|
74
|
+
service={service}
|
|
75
|
+
expandable={{
|
|
76
|
+
value: Boolean(isExpanded),
|
|
77
|
+
onClick: handleExpandedChange,
|
|
78
|
+
}}
|
|
79
|
+
showDescription={showDescription}
|
|
80
|
+
isMobile={isMobile}
|
|
81
|
+
dragDisabled={dragDisabled}
|
|
82
|
+
favorite={groupFavoritesEnabled ? favorite : undefined}
|
|
83
|
+
onServiceClick={onServiceClick}
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
<div className={baseGroupStyles.groupBody} data-subcategory-body='expanded' data-mobile={isMobile || undefined}>
|
|
87
|
+
{nestedItems.map(nestedService => (
|
|
88
|
+
<DraggableServiceCard
|
|
89
|
+
key={nestedGroupId + nestedService.id}
|
|
90
|
+
groupId={nestedGroupId}
|
|
91
|
+
service={nestedService}
|
|
92
|
+
favorite={favorite}
|
|
93
|
+
isMobile={isMobile}
|
|
94
|
+
onServiceClick={onServiceClick}
|
|
95
|
+
showDescription={showDescription}
|
|
96
|
+
dragDisabled={dragDisabled}
|
|
97
|
+
/>
|
|
98
|
+
))}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
45
104
|
return (
|
|
46
105
|
<div className={styles.subcategory} data-test-id={`${TEST_IDS.subcategory}-${service.id}`}>
|
|
47
106
|
<Accordion selectionMode='single' expanded={isExpanded} onExpandedChange={handleExpandedChange}>
|
|
@@ -13,12 +13,21 @@
|
|
|
13
13
|
.subcategory {
|
|
14
14
|
min-width: 0;
|
|
15
15
|
|
|
16
|
-
&:has([data-subcategory-body])
|
|
16
|
+
&:has([data-subcategory-body]),
|
|
17
|
+
&[data-title-only] {
|
|
17
18
|
grid-column: 1 / -1;
|
|
18
19
|
padding: 0 base.$sn-primitive-dimension-4;
|
|
19
20
|
border-radius: base.$sn-density-radius-2xs;
|
|
20
21
|
background-color: base.$sn-theme-color-neutral-decorTransparent;
|
|
21
22
|
}
|
|
23
|
+
|
|
24
|
+
&[data-title-only] {
|
|
25
|
+
padding: base.$sn-primitive-dimension-4;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&:has([data-subcategory-body='expanded']) {
|
|
29
|
+
padding: base.$sn-primitive-dimension-4 base.$sn-primitive-dimension-4 0;
|
|
30
|
+
}
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
.subcategoryAccordion {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
2
|
@use '@cloud-ru/ds-figma-variables/build/scss/components/button.module' as button;
|
|
3
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/accordion.module' as accordion;
|
|
3
4
|
|
|
4
5
|
// Радиус контейнера группы: от него считается радиус подложки внутри рамки выделения.
|
|
5
6
|
$group-border-radius: base.$sn-density-radius-2xs;
|
|
@@ -173,6 +174,10 @@ $map-block-color-decor: (
|
|
|
173
174
|
&[data-subcategory-body] {
|
|
174
175
|
padding-bottom: base.$sn-primitive-dimension-4;
|
|
175
176
|
}
|
|
177
|
+
|
|
178
|
+
&[data-subcategory-body='expanded'] {
|
|
179
|
+
padding-top: accordion.$sn-accordion-anatomy-accordionTertiary-container-bodyContent-paddingVertical;
|
|
180
|
+
}
|
|
176
181
|
}
|
|
177
182
|
|
|
178
183
|
.decoration {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
box-sizing: border-box;
|
|
11
11
|
width: 100%;
|
|
12
|
-
|
|
12
|
+
// высота всего блока с одной карточкой
|
|
13
|
+
min-height: base.$sn-primitive-dimension-88;
|
|
13
14
|
padding: base.$sn-primitive-dimension-8 0 0;
|
|
14
15
|
border-radius: base.$sn-density-radius-2xs;
|
|
15
16
|
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
position: relative;
|
|
41
42
|
flex: 1 1 auto;
|
|
42
43
|
width: 100%;
|
|
43
|
-
min-height:
|
|
44
|
+
min-height: base.$sn-primitive-dimension-44;
|
|
44
45
|
|
|
45
46
|
&[data-insert-new] {
|
|
46
47
|
[data-favorite] {
|
|
@@ -94,10 +94,6 @@ export function DraggableServiceCard({
|
|
|
94
94
|
|
|
95
95
|
const { tabIndex, ...restAttributes } = attributes ?? {};
|
|
96
96
|
|
|
97
|
-
if (disabled) {
|
|
98
|
-
return <ServiceCard service={service} favorite={favorite} {...props} tabIndex={tabIndex} />;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
97
|
return (
|
|
102
98
|
<DragGhost
|
|
103
99
|
innerRef={setNodeRef}
|
|
@@ -6,6 +6,8 @@ import { JSXElementConstructor, MouseEvent, ReactNode } from 'react';
|
|
|
6
6
|
import { ContentProps } from './helperComponents/Content';
|
|
7
7
|
import { FavoritesSegment } from './helperComponents/Favorites/constants';
|
|
8
8
|
|
|
9
|
+
export type InnerLinkViewMode = 'group-title-only' | 'flat-link' | 'expanded' | 'expandable';
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* Карточка сервиса или ссылки внутри {@link LinksGroup}.
|
|
11
13
|
*
|
|
@@ -38,15 +40,25 @@ export type InnerLink = {
|
|
|
38
40
|
badge?: CardServiceLightProps['promoTag'];
|
|
39
41
|
/** Разрешено ли добавление карточки в избранное. default=true - разрешено */
|
|
40
42
|
favoritesEnabled?: boolean;
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Режим отображения карточки. default='expandable'.
|
|
45
|
+
*
|
|
46
|
+
* - `'expandable'` — подкатегория при наличии реальных {@link items}: заголовок
|
|
47
|
+
* {@link TitleClickable} с шевроном и сетка вложенных сервисов (раскрытие/схлопывание —
|
|
48
|
+
* см. {@link expandableEnabled}). Без `items` — обычная карточка сервиса.
|
|
49
|
+
* - `'group-title-only'` — заголовок подкатегории ({@link TitleClickable} с шевроном) без
|
|
50
|
+
* раскрываемого тела, даже если `items` заданы: карточка ведёт себя как обычная ссылка.
|
|
51
|
+
* Полезно для группы, чьи вложенные сервисы показываются на отдельной странице.
|
|
52
|
+
* - `'flat-link'` — всегда обычная карточка сервиса, даже если `items` заданы.
|
|
53
|
+
*/
|
|
54
|
+
viewMode?: InnerLinkViewMode;
|
|
43
55
|
/**
|
|
44
56
|
* Вложенные сервисы подкатегории.
|
|
45
57
|
*
|
|
46
58
|
* При наличии карточка раскрывается аккордеоном: в свёрнутом виде — обычная карточка
|
|
47
59
|
* с кнопкой раскрытия, в развёрнутом — заголовок {@link TitleClickable} и сетка вложенных сервисов.
|
|
48
60
|
*/
|
|
49
|
-
items?: InnerLink[];
|
|
61
|
+
items?: Omit<InnerLink, 'items' | 'viewMode' | 'expandableEnabled'>[];
|
|
50
62
|
/**
|
|
51
63
|
* Синонимы для fuzzy-поиска.
|
|
52
64
|
*/
|
|
@@ -4,6 +4,29 @@ export function hasNestedItems(item: InnerLink): boolean {
|
|
|
4
4
|
return Boolean(item.items?.some(child => !child.hidden));
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Рендерится ли карточка как подкатегория (заголовок {@link TitleClickable} + вложенная сетка).
|
|
9
|
+
*
|
|
10
|
+
* Решение зависит от `viewMode` (не указан — считается `'expandable'`):
|
|
11
|
+
* - `'flat-link'` — никогда, карточка всегда обычная ссылка, даже если `items` заданы.
|
|
12
|
+
* - `'group-title-only'` — всегда, даже без `items`: только заголовок, без раскрываемого тела
|
|
13
|
+
* и кнопки переключения — карточка ведёт себя как обычная ссылка.
|
|
14
|
+
* - `'expandable'` — только при наличии реальных вложенных сервисов.
|
|
15
|
+
*/
|
|
16
|
+
export function isSubCategoryCard(item: InnerLink): boolean {
|
|
17
|
+
const viewMode = item.viewMode ?? 'expanded';
|
|
18
|
+
|
|
19
|
+
if (viewMode === 'flat-link') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (viewMode === 'group-title-only') {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return hasNestedItems(item);
|
|
28
|
+
}
|
|
29
|
+
|
|
7
30
|
export function flatInnerLinks(items: InnerLink[] = []): InnerLink[] {
|
|
8
31
|
return items.flatMap(item => {
|
|
9
32
|
if (item.hidden) {
|