Skip to content

Commit 71f23a8

Browse files
authored
feat: add dropdown item in right column of navigation (#213)
* feat: add dropdown item in right column of navigation
1 parent 3af0926 commit 71f23a8

File tree

12 files changed

+295
-154
lines changed

12 files changed

+295
-154
lines changed

src/containers/PageConstructor/__stories__/data.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,23 @@
308308
}
309309
],
310310
"rightItems": [
311+
{
312+
"type": "dropdown",
313+
"text": "Language",
314+
"icon": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_light.svg",
315+
"items": [
316+
{
317+
"text": "Russian",
318+
"url": "/ru",
319+
"type": "link"
320+
},
321+
{
322+
"text": "English",
323+
"url": "/",
324+
"type": "link"
325+
}
326+
]
327+
},
311328
{
312329
"type": "github-button",
313330
"text": "Star",

src/navigation/components/Header/Header.scss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ $block: '.#{$ns}header';
5959
&__right {
6060
flex: 0;
6161
justify-content: flex-end;
62+
63+
@include text-size(body-2);
6264
}
6365

6466
&__navigation-container {
@@ -75,6 +77,7 @@ $block: '.#{$ns}header';
7577
display: flex;
7678
align-items: center;
7779
@include desktop-only();
80+
@include reset-list-style();
7881

7982
& > * {
8083
&:not(:last-child) {
@@ -83,6 +86,19 @@ $block: '.#{$ns}header';
8386
}
8487
}
8588

89+
&__buttons-item {
90+
position: relative;
91+
92+
height: var(--header-height);
93+
94+
line-height: var(--header-height);
95+
@include navigation-link();
96+
97+
&:not(:last-child) {
98+
margin-right: $indentS;
99+
}
100+
}
101+
86102
&__button {
87103
margin-top: 0;
88104
}

src/navigation/components/Header/Header.tsx

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import React, {MouseEvent, useCallback, useState} from 'react';
2+
import _ from 'lodash';
23

34
import {block} from '../../../utils';
45
import {HeaderData, ThemedNavigationLogoData} from '../../../models';
56
import {Col, Grid, Row} from '../../../grid';
67
import OutsideClick from '../../../components/OutsideClick/OutsideClick';
78
import Control from '../../../components/Control/Control';
9+
import {NavigationClose, NavigationOpen} from '../../../icons';
10+
import {ItemColumnName} from '../../constants';
811
import Navigation from '../Navigation/Navigation';
912
import MobileNavigation from '../MobileNavigation/MobileNavigation';
10-
import NavigationItem from '../NavigationItem/NavigationItem';
1113
import Logo from '../Logo/Logo';
12-
13-
import {NavigationClose, NavigationOpen} from '../../../icons';
14+
import {NavigationListItem} from '../NavigationListItem/NavigationListItem';
1415

1516
import './Header.scss';
1617

@@ -53,12 +54,16 @@ const MobileMenuButton: React.FC<MobileMenuButtonProps> = ({
5354
export const Header: React.FC<HeaderProps> = ({data, logo}) => {
5455
const {leftItems, rightItems} = data;
5556
const [isSidebarOpened, setIsSidebarOpened] = useState(false);
56-
const [activeItemIndex, setActiveItemIndex] = useState(-1);
57+
const [activeItemId, setactiveItemId] = useState<string | undefined>(undefined);
5758

58-
const onActiveItemChange = useCallback((index: number) => {
59-
setActiveItemIndex(index);
59+
const onActiveItemChange = useCallback((id?: string) => {
60+
setactiveItemId(id);
6061
}, []);
6162

63+
const hidePopup = useCallback(() => {
64+
onActiveItemChange();
65+
}, [onActiveItemChange]);
66+
6267
const onSidebarOpenedChange = useCallback((isOpen: boolean) => {
6368
setIsSidebarOpened(isOpen);
6469
}, []);
@@ -81,7 +86,7 @@ export const Header: React.FC<HeaderProps> = ({data, logo}) => {
8186
<Navigation
8287
className={b('navigation')}
8388
links={leftItems}
84-
activeItemIndex={activeItemIndex}
89+
activeItemId={activeItemId}
8590
onActiveItemChange={onActiveItemChange}
8691
/>
8792
</div>
@@ -91,19 +96,28 @@ export const Header: React.FC<HeaderProps> = ({data, logo}) => {
9196
onSidebarOpenedChange={onSidebarOpenedChange}
9297
/>
9398
{rightItems && (
94-
<div className={b('buttons')}>
95-
{rightItems.map((button) => (
96-
<NavigationItem key={button.text} data={button} />
99+
<ul className={b('buttons')}>
100+
{rightItems.map((button, index) => (
101+
<NavigationListItem
102+
key={index}
103+
className={b('buttons-item')}
104+
item={button}
105+
index={index}
106+
activeItemId={activeItemId}
107+
hidePopup={hidePopup}
108+
column={ItemColumnName.Right}
109+
onActiveItemChange={onActiveItemChange}
110+
/>
97111
))}
98-
</div>
112+
</ul>
99113
)}
100114
</div>
101115
<OutsideClick onOutsideClick={() => onSidebarOpenedChange(false)}>
102116
<MobileNavigation
103117
topItems={leftItems}
104118
bottomItems={rightItems}
105119
isOpened={isSidebarOpened}
106-
activeItemIndex={activeItemIndex}
120+
activeItemId={activeItemId}
107121
onActiveItemChange={onActiveItemChange}
108122
onClose={hideSidebar}
109123
/>

src/navigation/components/MobileNavigation/MobileNavigation.scss

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ $block: '.#{$ns}mobile-navigation';
2727
margin-top: $indentSM;
2828
}
2929

30-
&__links {
30+
&__nav {
31+
margin-bottom: $indentSM;
32+
}
33+
34+
&__rows {
3135
position: relative;
3236

3337
display: flex;
@@ -37,7 +41,7 @@ $block: '.#{$ns}mobile-navigation';
3741
@include reset-list-style();
3842
}
3943

40-
&__links-item {
44+
&__rows-item {
4145
&:not(:last-child) {
4246
margin-bottom: $indentSM;
4347
}

src/navigation/components/MobileNavigation/MobileNavigation.tsx

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {Popup, Portal} from '@gravity-ui/uikit';
44
import {block} from '../../../utils';
55
import Foldable from '../../../components/Foldable/Foldable';
66
import {NavigationItemModel, NavigationDropdownItem, NavigationItemType} from '../../../models';
7+
import {ItemColumnName} from '../../constants';
78
import NavigationItem from '../NavigationItem/NavigationItem';
89

910
import './MobileNavigation.scss';
@@ -46,27 +47,33 @@ const MobileNavigationDropdown: React.FC<MobileNavigationDropdownProps> = ({
4647

4748
interface MobileNavigationItemProps
4849
extends Pick<MobileNavigationProps, 'onActiveItemChange' | 'onClose'> {
49-
link: NavigationItemModel;
50+
item: NavigationItemModel;
51+
column: ItemColumnName;
5052
index: number;
51-
isActive?: boolean;
53+
isOpened?: boolean;
54+
activeItemId?: string;
5255
}
5356

5457
const MobileNavigationItem = ({
55-
link,
58+
item,
5659
index,
57-
isActive,
60+
isOpened,
61+
activeItemId,
5862
onActiveItemChange,
63+
column,
5964
onClose,
6065
}: MobileNavigationItemProps) => {
66+
const id = `${column}-${index}`;
67+
const isActive = id === activeItemId && isOpened;
6168
const toggleActive: MouseEventHandler = useCallback(
6269
(e) => {
6370
e.stopPropagation();
6471

6572
if (onActiveItemChange) {
66-
onActiveItemChange(isActive ? -1 : index);
73+
onActiveItemChange(isActive ? undefined : `${column}-${index}`);
6774
}
6875
},
69-
[isActive, index, onActiveItemChange],
76+
[onActiveItemChange, isActive, column, index],
7077
);
7178

7279
const onItemClick: MouseEventHandler = useCallback(
@@ -78,16 +85,16 @@ const MobileNavigationItem = ({
7885
);
7986

8087
return (
81-
<li key={index} className={b('links-item')}>
82-
{link.type === NavigationItemType.Dropdown ? (
88+
<li key={index} className={b('rows-item')}>
89+
{item.type === NavigationItemType.Dropdown ? (
8390
<MobileNavigationDropdown
84-
data={link}
91+
data={item}
8592
onToggle={toggleActive}
8693
isOpened={isActive}
8794
onItemClick={onItemClick}
8895
/>
8996
) : (
90-
<NavigationItem data={link} onClick={onItemClick} />
97+
<NavigationItem data={item} onClick={onItemClick} />
9198
)}
9299
</li>
93100
);
@@ -98,43 +105,52 @@ export interface MobileNavigationProps {
98105
isOpened?: boolean;
99106
topItems?: NavigationItemModel[];
100107
bottomItems?: NavigationItemModel[];
101-
activeItemIndex: number;
108+
activeItemId?: string;
102109
onClose: () => void;
103-
onActiveItemChange: (index: number) => void;
110+
onActiveItemChange: (id?: string) => void;
104111
}
105112

106113
const MobileNavigation: React.FC<MobileNavigationProps> = (props) => {
107114
if (typeof window === 'undefined') {
108115
return null;
109116
}
110117

111-
const {isOpened, topItems, bottomItems, activeItemIndex, onActiveItemChange, onClose} = props;
118+
const {isOpened, topItems, bottomItems, activeItemId, onActiveItemChange, onClose} = props;
112119

113120
return (
114121
<Portal>
115122
<Foldable key={topItems?.length} className={b()} isOpened={Boolean(isOpened)}>
116123
<div className={b('wrapper')}>
117-
<nav>
118-
<ul className={b('links')}>
119-
{topItems?.map((link, index) => {
120-
const isActive = index === activeItemIndex;
121-
122-
return (
123-
<MobileNavigationItem
124-
key={index}
125-
link={link}
126-
index={index}
127-
isActive={isOpened && isActive}
128-
onClose={onClose}
129-
onActiveItemChange={onActiveItemChange}
130-
/>
131-
);
132-
})}
124+
<nav className={b('nav')}>
125+
<ul className={b('rows')}>
126+
{topItems?.map((link, index) => (
127+
<MobileNavigationItem
128+
key={index}
129+
item={link}
130+
column={ItemColumnName.Top}
131+
index={index}
132+
isOpened={isOpened}
133+
activeItemId={activeItemId}
134+
onClose={onClose}
135+
onActiveItemChange={onActiveItemChange}
136+
/>
137+
))}
133138
</ul>
134139
</nav>
135-
{bottomItems?.map((item) => (
136-
<NavigationItem key={item.text} data={item} className={b('button')} />
137-
))}
140+
<ul className={b('rows')}>
141+
{bottomItems?.map((item, index) => (
142+
<MobileNavigationItem
143+
key={index}
144+
item={item}
145+
column={ItemColumnName.Bottom}
146+
index={index}
147+
isOpened={isOpened}
148+
activeItemId={activeItemId}
149+
onClose={onClose}
150+
onActiveItemChange={onActiveItemChange}
151+
/>
152+
))}
153+
</ul>
138154
</div>
139155
</Foldable>
140156
</Portal>

src/navigation/components/Navigation/Navigation.scss

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,4 @@ $block: '.#{$ns}navigation';
2626
margin-right: $indentS;
2727
}
2828
}
29-
30-
&__slider-container {
31-
position: absolute;
32-
right: 0;
33-
bottom: 0;
34-
left: 0;
35-
}
36-
37-
&__slider {
38-
width: 100%;
39-
height: 2px;
40-
41-
background-color: var(--yc-color-text-link);
42-
}
4329
}

0 commit comments

Comments
 (0)