Skip to content

Commit 33afddb

Browse files
Merge branch 'develop' into nav-bugbash-2
2 parents b1a22c8 + 6a943bf commit 33afddb

File tree

10 files changed

+324
-105
lines changed

10 files changed

+324
-105
lines changed

dist/dev/index.js

+10-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/prod/index.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+14
Loading

src/components/AccountMenu/index.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class AccountMenu extends React.Component {
4141

4242
render () {
4343
const {
44-
onClose, onClickNotifications, numNotifications, open, menu, switchText, onSwitch, profile
44+
onClose, open, menu, switchText, onSwitch, profile
4545
} = this.props
4646

4747
return (
@@ -82,7 +82,7 @@ class AccountMenu extends React.Component {
8282
onClick={onSwitch}
8383
>
8484
<IconSwitchBusiness className={styles['switch-icon']} />
85-
<Link to={hasAccess(profile.roles)? _.isEmpty(switchText.href) ? switchText.link : switchText.href : 'http://www.topcoder.com'} onClick={onClose}>
85+
<Link to={hasAccess(profile.roles) ? _.isEmpty(switchText.href) ? switchText.link : switchText.href : 'http://www.topcoder.com'} onClick={onClose}>
8686
<span className={styles['switch-to-busniness']}>{switchText.title}</span>
8787
</Link>
8888
</div>
@@ -112,8 +112,6 @@ AccountMenu.propTypes = {
112112
onClose: PropTypes.func,
113113
menu: PropTypes.array,
114114
switchText: PropTypes.shape(),
115-
numNotifications: PropTypes.number,
116-
onClickNotifications: PropTypes.func,
117115
onSwitch: PropTypes.func,
118116
profile: PropTypes.shape()
119117
}

src/components/TopNav/MobileNav.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import PropTypes from 'prop-types'
33
import styles from './MobileNav.module.scss'
44
import IconClose from '../../assets/images/icon-close.svg'
55
import IconMenu from '../../assets/images/icon-menu.svg'
6+
import IconMagnifyingGlass from '../../assets/images/magnifying_glass.svg'
7+
import { config } from 'topcoder-react-utils'
68

7-
const MobileNav = ({ showLeftMenu, onClickLeftMenu, logo, rightMenu }) => (
9+
const MobileNav = ({ showLeftMenu, onClickLeftMenu, logo, rightMenu }) => (<div>
810
<div className={styles.mobileNav}>
911
<div className={styles.leftMenuContainer}>
1012
<button className={styles.menuBtn} onClick={onClickLeftMenu}>
@@ -24,6 +26,23 @@ const MobileNav = ({ showLeftMenu, onClickLeftMenu, logo, rightMenu }) => (
2426
</div>
2527
)}
2628
</div>
29+
{showLeftMenu && (
30+
<div className={styles.search}>
31+
<IconMagnifyingGlass className={styles.icon} />
32+
<input
33+
onKeyPress={(event) => {
34+
if (event.key === 'Enter') {
35+
window.location = `${config.URL.BASE}/search/members?q=${
36+
encodeURIComponent(event.target.value)
37+
}`
38+
}
39+
}}
40+
placeholder='Find members by username or skill'
41+
aria-label='Find members by username or skill'
42+
/>
43+
</div>
44+
)}
45+
</div>
2746
)
2847

2948
MobileNav.propTypes = {

src/components/TopNav/MobileNav.module.scss

+43
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,46 @@
4343
right: 0;
4444
}
4545
}
46+
47+
.icon {
48+
@include mobile-only;
49+
left: 18px;
50+
position: absolute;
51+
top: 16px;
52+
}
53+
54+
.search {
55+
@include mobile-only;
56+
padding: 6px 12px 0;
57+
position: relative;
58+
59+
input {
60+
background: none;
61+
border: 1px solid $gray-50;
62+
box-shadow: none;
63+
color: $white;
64+
font: 16px "Roboto", Helvetica, Arial, sans-serif !important;
65+
height: 32px;
66+
outline: none;
67+
padding-left: 30px !important;
68+
69+
&::placeholder {
70+
color: $gray-50;
71+
}
72+
73+
&:hover {
74+
border: 1px solid $gray-50;
75+
}
76+
77+
&:focus {
78+
border: 1px solid $blue;
79+
}
80+
}
81+
82+
input:active,
83+
input:focus,
84+
input:hover {
85+
box-shadow: none;
86+
outline: none;
87+
}
88+
}

src/components/TopNav/PrimaryNav.js

+137-78
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import ResizeDetector from 'react-resize-detector'
55
import ChosenArrow from '../ChosenArrow'
66
import IconArrowSmalldown from '../../assets/images/arrow-small-down.svg'
77
import IconArrowSmallup from '../../assets/images/arrow-small-up.svg'
8+
import MagnifyingGlass from '../../assets/images/magnifying_glass.svg'
89
import styles from './PrimaryNav.module.scss'
10+
import { config } from 'topcoder-react-utils'
11+
12+
const BASE_URL = config.URL.BASE
913

1014
const PrimaryNav = ({
1115
collapsed,
@@ -27,94 +31,147 @@ const PrimaryNav = ({
2731
createHandleClickMoreItem,
2832
createSetRef,
2933
showChosenArrow,
30-
chosenArrowX
34+
chosenArrowX,
35+
searchOpened,
36+
toggleSearchOpen
3137
}) => {
3238
const filterNotInMore = menu => !(moreMenu || []).find(x => x.id === menu.id)
33-
39+
const activeTrigger = {
40+
bottom: 50 // The main nav head bottom Y
41+
}
3442
return (
35-
<div className={cn(styles.primaryNavContainer, showLeftMenu && styles.primaryNavContainerOpen)}>
36-
<div className={styles.primaryNav} ref={createSetRef('primaryNav')}>
37-
<a
38-
className={cn(styles.tcLogo, collapsed && styles.tcLogoPush)}
39-
onClick={onClickLogo}
40-
href='/'
41-
>
42-
{logo}
43-
</a>
44-
{menu.map((level1, i) => ([
45-
<span className={styles.primaryLevel1Separator} key={`separator-${i}`} />,
46-
/* Level 1 menu item */
43+
<div>
44+
<div className={cn(styles.primaryNavContainer, showLeftMenu && styles.primaryNavContainerOpen)}>
45+
<div className={styles.primaryNav} ref={createSetRef('primaryNav')}>
4746
<a
48-
className={cn(styles.primaryLevel1, !activeLevel2Id && level1.id === activeLevel1Id && styles.primaryLevel1Open, level1.mobileOnly && styles.mobileOnly)}
49-
href={level1.href}
50-
key={`level1-${i}`}
51-
onClick={createHandleClickLevel1(level1.id, true)}
52-
ref={createSetRef(level1.id)}
47+
className={cn(styles.tcLogo, collapsed && styles.tcLogoPush)}
48+
onClick={onClickLogo}
49+
href='/'
5350
>
54-
{level1.title}
55-
</a>,
56-
/* Level 2 menu */
57-
level1.subMenu && (
58-
<div
59-
className={cn(styles.primaryLevel2Container, level1.id === activeLevel1Id && styles.primaryLevel2ContainerOpen)}
60-
key={`level2-${i}-container`}
61-
ref={createSetRef(`level2Container${i}`)}
51+
{logo}
52+
</a>
53+
{menu.map((level1, i) => ([
54+
<span className={styles.primaryLevel1Separator} key={`separator-${i}`} />,
55+
/* Level 1 menu item */
56+
<a
57+
className={cn(styles.primaryLevel1, !activeLevel2Id && level1.id === activeLevel1Id && styles.primaryLevel1Open, level1.mobileOnly && styles.mobileOnly)}
58+
href={level1.href}
59+
key={`level1-${i}`}
60+
onClick={createHandleClickLevel1(level1.id, true)}
61+
ref={createSetRef(level1.id)}
6262
>
63-
{level1.subMenu.filter(filterNotInMore).map((level2, i) => (
64-
<a
65-
className={cn(styles.primaryLevel2, level2.id === activeLevel2Id && styles.primaryLevel2Open)}
66-
href={level2.href}
67-
key={`level2-${i}`}
68-
onClick={createHandleClickLevel2(level2.id, true)}
69-
ref={createSetRef(level2.id)}
70-
>
71-
{level2.title}
72-
</a>
73-
))}
74-
{/* The More menu */}
75-
{level1.id === activeLevel1Id && moreMenu && moreMenu.length > 0 && (
76-
<div className={cn(styles.moreBtnContainer, openMore && styles.moreOpen)}>
77-
<div className={styles.backdrop} onClick={onCloseMore} />
78-
<button
79-
className={cn(styles.primaryLevel2, styles.moreBtn)}
80-
onClick={handleClickMore}
81-
ref={createSetRef(moreId)}
63+
{level1.title}
64+
</a>,
65+
/* Level 2 menu */
66+
level1.subMenu && (
67+
<div
68+
className={cn(styles.primaryLevel2Container, level1.id === activeLevel1Id && styles.primaryLevel2ContainerOpen)}
69+
key={`level2-${i}-container`}
70+
ref={createSetRef(`level2Container${i}`)}
71+
>
72+
{level1.subMenu.filter(filterNotInMore).map((level2, i) => (
73+
<a
74+
className={cn(styles.primaryLevel2, level2.id === activeLevel2Id && styles.primaryLevel2Open)}
75+
href={level2.href}
76+
key={`level2-${i}`}
77+
onClick={createHandleClickLevel2(level2.id, true)}
78+
ref={createSetRef(level2.id)}
8279
>
83-
<div className={styles.moreBtnMask} />
84-
<span>More</span>
85-
{openMore && <IconArrowSmallup />}
86-
{!openMore && <IconArrowSmalldown />}
87-
</button>
88-
<div className={styles.moreContentContainer}>
89-
{moreMenu.map((menu, i) => (
90-
<a
91-
className={cn(styles.primaryLevel2, menu.id === activeLevel2Id && styles.primaryLevel2Open)}
92-
href={menu.href}
93-
key={`more-item-${i}`}
94-
onClick={createHandleClickMoreItem(menu.id)}
95-
>
96-
{menu.title}
97-
</a>
98-
))}
80+
{level2.title}
81+
</a>
82+
))}
83+
{/* The More menu */}
84+
{level1.id === activeLevel1Id && moreMenu && moreMenu.length > 0 && (
85+
<div className={cn(styles.moreBtnContainer, openMore && styles.moreOpen)}>
86+
<div className={styles.backdrop} onClick={onCloseMore} />
87+
<button
88+
className={cn(styles.primaryLevel2, styles.moreBtn)}
89+
onClick={handleClickMore}
90+
ref={createSetRef(moreId)}
91+
>
92+
<div className={styles.moreBtnMask} />
93+
<span>More</span>
94+
{openMore && <IconArrowSmallup />}
95+
{!openMore && <IconArrowSmalldown />}
96+
</button>
97+
<div className={styles.moreContentContainer}>
98+
{moreMenu.map((menu, i) => (
99+
<a
100+
className={cn(styles.primaryLevel2, menu.id === activeLevel2Id && styles.primaryLevel2Open)}
101+
href={menu.href}
102+
key={`more-item-${i}`}
103+
onClick={createHandleClickMoreItem(menu.id)}
104+
>
105+
{menu.title}
106+
</a>
107+
))}
108+
</div>
99109
</div>
100-
</div>
101-
)}
110+
)}
111+
</div>
112+
)
113+
]))}
114+
<ChosenArrow show={showChosenArrow} x={chosenArrowX} />
115+
</div>
116+
<div className={styles.primaryNavRight}>
117+
<ResizeDetector
118+
handleWidth
119+
onResize={onRightMenuResize}
120+
/>
121+
{rightMenu && (
122+
<div className={styles.primaryLevel1}>
123+
{rightMenu}
102124
</div>
103-
)
104-
]))}
105-
<ChosenArrow show={showChosenArrow} x={chosenArrowX} />
125+
)}
126+
<div
127+
aria-label='Find members by username or skill'
128+
role='button'
129+
tabIndex={0}
130+
data-menu='search'
131+
className={cn(styles.searchIcon, { opened: searchOpened })}
132+
onFocus={() => toggleSearchOpen(true)}
133+
onBlur={(event) => {
134+
if (event.pageY < activeTrigger.bottom) {
135+
toggleSearchOpen(false)
136+
}
137+
}}
138+
onMouseEnter={(event) => toggleSearchOpen(true)}
139+
onMouseLeave={(event) => {
140+
console.log(`${event.clientX} - ${event.clientY}`)
141+
if (event.pageY < activeTrigger.bottom) {
142+
toggleSearchOpen(false)
143+
}
144+
}}
145+
onTouchStart={(event) => {
146+
if (searchOpened) {
147+
toggleSearchOpen(false)
148+
} else {
149+
toggleSearchOpen(true)
150+
}
151+
}}
152+
>
153+
<MagnifyingGlass />
154+
</div>
155+
</div>
106156
</div>
107-
108-
<div className={styles.primaryNavRight}>
109-
<ResizeDetector
110-
handleWidth
111-
onResize={onRightMenuResize}
157+
<div
158+
role='search'
159+
className={cn(styles.searchField, { opened: searchOpened, closed: !searchOpened })}
160+
onMouseLeave={(event) => { toggleSearchOpen(false) }}
161+
>
162+
<input
163+
ref={createSetRef('searchInputBox')}
164+
onKeyPress={(event) => {
165+
if (event.key === 'Enter') {
166+
window.location = `${BASE_URL}/search/members?q=${
167+
encodeURIComponent(event.target.value)
168+
}`
169+
}
170+
}}
171+
onBlur={() => toggleSearchOpen(false)}
172+
aria-label='Find members by username or skill'
173+
placeholder='Find members by username or skill'
112174
/>
113-
{rightMenu && (
114-
<div className={styles.primaryLevel1}>
115-
{rightMenu}
116-
</div>
117-
)}
118175
</div>
119176
</div>
120177
)
@@ -140,7 +197,9 @@ PrimaryNav.propTypes = {
140197
createHandleClickMoreItem: PropTypes.func,
141198
createSetRef: PropTypes.func,
142199
showChosenArrow: PropTypes.bool,
143-
chosenArrowX: PropTypes.number
200+
chosenArrowX: PropTypes.number,
201+
searchOpened: PropTypes.bool,
202+
toggleSearchOpen: PropTypes.func
144203
}
145204

146205
export default PrimaryNav

0 commit comments

Comments
 (0)